-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #362 from alephium/import_parser
`Import` statement parser
- Loading branch information
Showing
11 changed files
with
522 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
...cess/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ImportParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.alephium.ralph.lsp.access.compiler.parser.soft | ||
|
||
import fastparse._ | ||
import fastparse.NoWhitespace.noWhitespaceImplicit | ||
import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range | ||
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} | ||
|
||
private object ImportParser { | ||
|
||
/** | ||
* Parses an import statement. | ||
* | ||
* Example syntax: | ||
* | ||
* {{{ | ||
* import "some text" | ||
* import "a/b/c/d" | ||
* }}} | ||
*/ | ||
def parseOrFail[Unknown: P]: P[SoftAST.Import] = | ||
P { | ||
Index ~ | ||
TokenParser.parseOrFail(Token.Import) ~ | ||
&(TokenParser.WhileInOrFail(Token.Space, Token.Newline, Token.Quote) | End) ~ | ||
SpaceParser.parseOrFail.? ~ | ||
StringLiteralParser.parseOrFail.? ~ | ||
Index | ||
} map { | ||
case (from, importToken, space, endQuote, to) => | ||
SoftAST.Import( | ||
index = range(from, to), | ||
importToken = importToken, | ||
postImportSpace = space, | ||
string = endQuote | ||
) | ||
} | ||
|
||
} |
60 changes: 60 additions & 0 deletions
60
...c/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StringLiteralParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.alephium.ralph.lsp.access.compiler.parser.soft | ||
|
||
import fastparse._ | ||
import fastparse.NoWhitespace.noWhitespaceImplicit | ||
import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.{point, range} | ||
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} | ||
|
||
object StringLiteralParser { | ||
|
||
/** | ||
* Parses text enclosed in quotes, e.g. `"some text"`. | ||
* | ||
* If the text follows a path format (i.e., it contains forward slashes [[Token.ForwardSlash]]), | ||
* it is parsed as a path. | ||
*/ | ||
def parseOrFail[Unknown: P]: P[SoftAST.StringLiteral] = | ||
P { | ||
Index ~ | ||
TokenParser.parseOrFail(Token.Quote) ~ | ||
Index ~ | ||
TextParser.parseOrFail(Token.ForwardSlash, Token.Quote).? ~ | ||
path.rep ~ | ||
TokenParser.parse(Token.Quote) ~ | ||
Index | ||
} map { | ||
case (from, startQuote, headIndex, head, tail, endQuote, to) => | ||
val headResult = | ||
if (head.isEmpty && tail.nonEmpty) | ||
// if the tail-path is provided, e.g. `import "/abc"` but the head-path is empty, | ||
// report error at the head-path. | ||
Some(SoftAST.CodeStringExpected(point(headIndex))) | ||
else | ||
head | ||
|
||
SoftAST.StringLiteral( | ||
index = range(from, to), | ||
startQuote = startQuote, | ||
head = headResult, | ||
tail = tail, | ||
endQuote = endQuote | ||
) | ||
} | ||
|
||
/** A string-literal could also define a path if it contains forward slashes */ | ||
private def path[Unknown: P]: P[SoftAST.Path] = | ||
P { | ||
Index ~ | ||
TokenParser.parseOrFail(Token.ForwardSlash) ~ | ||
TextParser.parse(Token.ForwardSlash, Token.Quote) ~ | ||
Index | ||
} map { | ||
case (from, slash, text, to) => | ||
SoftAST.Path( | ||
index = range(from, to), | ||
slash = slash, | ||
text = text | ||
) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
.../src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ImportParserSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package org.alephium.ralph.lsp.access.compiler.parser.soft | ||
|
||
import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ | ||
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} | ||
import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ | ||
import org.alephium.ralph.lsp.access.util.TestCodeUtil._ | ||
import org.alephium.ralph.lsp.access.util.TestFastParse.assertIsFastParseError | ||
import org.scalatest.matchers.should.Matchers | ||
import org.scalatest.wordspec.AnyWordSpec | ||
|
||
class ImportParserSpec extends AnyWordSpec with Matchers { | ||
|
||
"fail" when { | ||
"import is a prefix of an identifier" in { | ||
assertIsFastParseError { | ||
parseImport("important") | ||
} | ||
} | ||
} | ||
|
||
"succeed" when { | ||
"only the import token is defined" in { | ||
val importAST = | ||
parseImport("import") | ||
|
||
importAST shouldBe | ||
SoftAST.Import( | ||
index = indexOf(">>import<<"), | ||
importToken = Import(indexOf(">>import<<")), | ||
postImportSpace = None, | ||
string = None | ||
) | ||
} | ||
|
||
"tail space is defined" in { | ||
val importAST = | ||
parseImport("import ") | ||
|
||
importAST shouldBe | ||
SoftAST.Import( | ||
index = indexOf(">>import <<"), | ||
importToken = Import(indexOf(">>import<< ")), | ||
postImportSpace = Some(SpaceOne(indexOf("import>> <<"))), | ||
string = None | ||
) | ||
} | ||
|
||
"starting quote is defined without space" in { | ||
val importAST = | ||
parseImport("import\"") | ||
|
||
importAST shouldBe | ||
SoftAST.Import( | ||
index = indexOf(">>import\"<<"), | ||
importToken = Import(indexOf(">>import<<")), | ||
postImportSpace = None, | ||
string = Some( | ||
SoftAST.StringLiteral( | ||
index = indexOf("import>>\"<<"), | ||
startQuote = Quote(indexOf("import>>\"<<")), | ||
head = None, | ||
tail = Seq.empty, | ||
endQuote = SoftAST.TokenExpected(indexOf("import\">><<"), Token.Quote) | ||
) | ||
) | ||
) | ||
} | ||
|
||
"import is fully defined" in { | ||
val importAST = | ||
parseImport("""import "folder/file.ral"""") | ||
|
||
importAST shouldBe | ||
SoftAST.Import( | ||
index = indexOf(""">>import "folder/file.ral"<<"""), | ||
importToken = Import(indexOf(""">>import<< "folder/file.ral"""")), | ||
postImportSpace = Some(SpaceOne(indexOf("""import>> <<"folder/file.ral""""))), | ||
string = Some( | ||
SoftAST.StringLiteral( | ||
index = indexOf("""import >>"folder/file.ral"<<"""), | ||
startQuote = Quote(indexOf("""import >>"<<folder/file.ral"""")), | ||
head = Some(SoftAST.CodeString(indexOf("""import ">>folder<</file.ral""""), "folder")), | ||
tail = Seq( | ||
SoftAST.Path( | ||
index = indexOf("""import "folder>>/file.ral<<""""), | ||
slash = ForwardSlash(indexOf("""import "folder>>/<<file.ral"""")), | ||
text = SoftAST.CodeString(indexOf("""import "folder/>>file.ral<<""""), "file.ral") | ||
) | ||
), | ||
endQuote = Quote(indexOf("""import "folder/file.ral>>"<<""")) | ||
) | ||
) | ||
) | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.