mirror of
https://github.com/iritmaximus/compilers.git
synced 2026-10-12 19:13:35 +03:00
Improve block parsing
This commit is contained in:
@@ -60,6 +60,8 @@ class Parser(tokens: List[Token]):
|
||||
def peek(): Token =
|
||||
return if pos < tokens.length then tokens(pos) else Token("", TokenType.End, tokens.last.location)
|
||||
|
||||
def previous(): Token =
|
||||
return if pos-1 < 0 then tokens(0) else tokens(pos-1)
|
||||
|
||||
def consume(expected: Option[TokenType | String | List[String]] = None): Try[Token] =
|
||||
val token = peek()
|
||||
@@ -193,18 +195,22 @@ class Parser(tokens: List[Token]):
|
||||
def parseBlock(): Expression =
|
||||
consume(Some("{")).get
|
||||
var expressions: List[Expression] = List()
|
||||
var hasSemicolon: Boolean = false
|
||||
var endsInSemicolon: Boolean = false
|
||||
|
||||
while
|
||||
peek().value != "}"
|
||||
do
|
||||
hasSemicolon = false
|
||||
endsInSemicolon = false
|
||||
expressions = expressions ::: List(parseExpression(topLevelOrBlock=true))
|
||||
if peek().value != "}" then
|
||||
consume(Some(";")).get
|
||||
hasSemicolon = true
|
||||
|
||||
if hasSemicolon then
|
||||
if peek().value != "}" && previous().value != "}" && previous().value != ";" then
|
||||
consume(Some(";")).get
|
||||
endsInSemicolon = true
|
||||
|
||||
if previous().value == "}" then
|
||||
if peek().value == ";" then consume(Some(";")).get
|
||||
|
||||
if endsInSemicolon then
|
||||
expressions = expressions ::: List(Literal(Unit()))
|
||||
|
||||
consume(Some("}")).get
|
||||
|
||||
@@ -15,7 +15,7 @@ class Position(var line: Int, var column: Int):
|
||||
}
|
||||
|
||||
class TokenLocation(val start: Position, val end: Position):
|
||||
override def toString: String = s"TokenLoc(S:$start, E:$end)"
|
||||
override def toString: String = s"L(S:$start, E:$end)"
|
||||
override def equals(other: Any): Boolean = other match {
|
||||
case that: TokenLocation => (that.start == this.start) && (that.end == this.end)
|
||||
case that: TokenLocationDebug => true
|
||||
|
||||
@@ -744,7 +744,74 @@ class ParserBlockTests extends BaseParserTests {
|
||||
val p = testParser("if true then var x = 1")
|
||||
interceptMessage[java.lang.Exception]("Declaration found in not toplevel or block") {
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
println(s"Result: $result")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ParserBlockSemicolonTests extends BaseParserTests {
|
||||
test("should parse two blocks inside a block") {
|
||||
val p = testParser("{ { a } { b } }")
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
val expected = Block(List(
|
||||
Block(List(Identifier("a"))),
|
||||
Block(List(Identifier("b")))
|
||||
))
|
||||
|
||||
assertEquals(result, expected)
|
||||
}
|
||||
test("should parse two blocks inside a block (with semicolons)") {
|
||||
val p = testParser("{ { a }; { b } }")
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
val expected = Block(List(
|
||||
Block(List(Identifier("a"))),
|
||||
Block(List(Identifier("b")))
|
||||
))
|
||||
|
||||
assertEquals(result, expected)
|
||||
}
|
||||
test("should parse identifier after IfThen block") {
|
||||
// { if true then { a } b }
|
||||
val p = testParser("{ if true then { a } b }")
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
val expected = Block(List(
|
||||
IfThenElse(
|
||||
Identifier("true"),
|
||||
Block(List(Identifier("a"))),
|
||||
None
|
||||
),
|
||||
Identifier("b")
|
||||
))
|
||||
|
||||
assertEquals(result, expected)
|
||||
}
|
||||
test("should parse identifier after IfThen block (with semicolon)") {
|
||||
// { if true then { a } b }
|
||||
val p = testParser("{ if true then { a }; b }")
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
val expected = Block(List(
|
||||
IfThenElse(
|
||||
Identifier("true"),
|
||||
Block(List(Identifier("a"))),
|
||||
None
|
||||
),
|
||||
Identifier("b")
|
||||
))
|
||||
|
||||
assertEquals(result, expected)
|
||||
}
|
||||
test("should not parse identifiers inside block") {
|
||||
val token = Tokenizer.tokenize("{ a b }").get(2)
|
||||
val p = testParser("{ a b }")
|
||||
interceptMessage[java.lang.Exception](s"Token $token was not expected: ;") {
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
}
|
||||
}
|
||||
test("should not parse two identifiers after block in IfThenElse") {
|
||||
// { if true then { a } b c }
|
||||
val token = Tokenizer.tokenize("{ if true then { a } b c }").get(8)
|
||||
val p = testParser("{ if true then { a } b c }")
|
||||
interceptMessage[java.lang.Exception](s"Token $token was not expected: ;") {
|
||||
val result = p.parseExpression(topLevelOrBlock=true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user