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 =
|
def peek(): Token =
|
||||||
return if pos < tokens.length then tokens(pos) else Token("", TokenType.End, tokens.last.location)
|
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] =
|
def consume(expected: Option[TokenType | String | List[String]] = None): Try[Token] =
|
||||||
val token = peek()
|
val token = peek()
|
||||||
@@ -193,18 +195,22 @@ class Parser(tokens: List[Token]):
|
|||||||
def parseBlock(): Expression =
|
def parseBlock(): Expression =
|
||||||
consume(Some("{")).get
|
consume(Some("{")).get
|
||||||
var expressions: List[Expression] = List()
|
var expressions: List[Expression] = List()
|
||||||
var hasSemicolon: Boolean = false
|
var endsInSemicolon: Boolean = false
|
||||||
|
|
||||||
while
|
while
|
||||||
peek().value != "}"
|
peek().value != "}"
|
||||||
do
|
do
|
||||||
hasSemicolon = false
|
endsInSemicolon = false
|
||||||
expressions = expressions ::: List(parseExpression(topLevelOrBlock=true))
|
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()))
|
expressions = expressions ::: List(Literal(Unit()))
|
||||||
|
|
||||||
consume(Some("}")).get
|
consume(Some("}")).get
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Position(var line: Int, var column: Int):
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TokenLocation(val start: Position, val end: Position):
|
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 {
|
override def equals(other: Any): Boolean = other match {
|
||||||
case that: TokenLocation => (that.start == this.start) && (that.end == this.end)
|
case that: TokenLocation => (that.start == this.start) && (that.end == this.end)
|
||||||
case that: TokenLocationDebug => true
|
case that: TokenLocationDebug => true
|
||||||
|
|||||||
@@ -744,7 +744,74 @@ class ParserBlockTests extends BaseParserTests {
|
|||||||
val p = testParser("if true then var x = 1")
|
val p = testParser("if true then var x = 1")
|
||||||
interceptMessage[java.lang.Exception]("Declaration found in not toplevel or block") {
|
interceptMessage[java.lang.Exception]("Declaration found in not toplevel or block") {
|
||||||
val result = p.parseExpression(topLevelOrBlock=true)
|
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