mirror of
https://github.com/iritmaximus/compilers.git
synced 2026-10-12 19:13:35 +03:00
Add while-do and declarations
This commit is contained in:
@@ -21,7 +21,13 @@ case class UnaryOperator(operator: String, expr: Expression) extends Expression
|
|||||||
override def toString: String = s"UnaryOperator($operator: $expr)"
|
override def toString: String = s"UnaryOperator($operator: $expr)"
|
||||||
}
|
}
|
||||||
case class IfThenElse(condition: Expression, body: Expression, elseBody: Option[Expression]) extends Expression {
|
case class IfThenElse(condition: Expression, body: Expression, elseBody: Option[Expression]) extends Expression {
|
||||||
override def toString: String = s"If($condition then $body)"
|
override def toString: String = s"If($condition then $body, else $elseBody)"
|
||||||
|
}
|
||||||
|
case class WhileDo(condition: Expression, body: Expression) extends Expression {
|
||||||
|
override def toString: String = s"While($condition do $body)"
|
||||||
|
}
|
||||||
|
case class Declaration(name: Identifier, body: Expression) extends Expression {
|
||||||
|
override def toString: String = s"Var($name = $body)"
|
||||||
}
|
}
|
||||||
case class Function(name: String, arguments: List[Expression]) extends Expression {
|
case class Function(name: String, arguments: List[Expression]) extends Expression {
|
||||||
override def toString: String = s"Function($name(${arguments.mkString(", ")}))"
|
override def toString: String = s"Function($name(${arguments.mkString(", ")}))"
|
||||||
@@ -110,6 +116,7 @@ class Parser(tokens: List[Token]):
|
|||||||
return token.tokenType match {
|
return token.tokenType match {
|
||||||
case TokenType.IntLiteral => parseIntLiteral()
|
case TokenType.IntLiteral => parseIntLiteral()
|
||||||
case TokenType.Identifier if token.value == "if" => parseIfThenElse()
|
case TokenType.Identifier if token.value == "if" => parseIfThenElse()
|
||||||
|
case TokenType.Identifier if token.value == "while" => parseWhileDo()
|
||||||
case TokenType.Identifier if token.value == "not" => parseUnaryOperator()
|
case TokenType.Identifier if token.value == "not" => parseUnaryOperator()
|
||||||
case TokenType.Identifier => parseIdentifier()
|
case TokenType.Identifier => parseIdentifier()
|
||||||
case TokenType.Operator if token.value == "-" => parseUnaryOperator()
|
case TokenType.Operator if token.value == "-" => parseUnaryOperator()
|
||||||
@@ -131,6 +138,14 @@ class Parser(tokens: List[Token]):
|
|||||||
return IfThenElse(condition, body, elseBody)
|
return IfThenElse(condition, body, elseBody)
|
||||||
|
|
||||||
|
|
||||||
|
def parseWhileDo(): Expression =
|
||||||
|
consume(Some("while")).get
|
||||||
|
val condition = parseExpression()
|
||||||
|
consume(Some("do")).get
|
||||||
|
val body = parseExpression()
|
||||||
|
return WhileDo(condition, body)
|
||||||
|
|
||||||
|
|
||||||
def parseFunction(parsedFnName: Option[String] = None): Expression =
|
def parseFunction(parsedFnName: Option[String] = None): Expression =
|
||||||
val fnName = parsedFnName.getOrElse(consume(Some(TokenType.Identifier)).get.value)
|
val fnName = parsedFnName.getOrElse(consume(Some(TokenType.Identifier)).get.value)
|
||||||
consume(Some("(")).get
|
consume(Some("(")).get
|
||||||
@@ -160,6 +175,13 @@ class Parser(tokens: List[Token]):
|
|||||||
return right
|
return right
|
||||||
|
|
||||||
|
|
||||||
|
def parseDeclaration(): Expression =
|
||||||
|
val name = parseIdentifier()
|
||||||
|
consume(Some("=")).get
|
||||||
|
val body = parseExpression()
|
||||||
|
return Declaration(name, body)
|
||||||
|
|
||||||
|
|
||||||
def parseExpression(initialDepth: Int = 0): Expression =
|
def parseExpression(initialDepth: Int = 0): Expression =
|
||||||
var depth = initialDepth
|
var depth = initialDepth
|
||||||
var left = parseFactor()
|
var left = parseFactor()
|
||||||
@@ -167,6 +189,7 @@ class Parser(tokens: List[Token]):
|
|||||||
// If identifier is followed by ( => it is a function call (or syntax error :D)
|
// If identifier is followed by ( => it is a function call (or syntax error :D)
|
||||||
left = left match {
|
left = left match {
|
||||||
case left: Identifier if peek().value == "(" => parseFunction(Some(left.name))
|
case left: Identifier if peek().value == "(" => parseFunction(Some(left.name))
|
||||||
|
case left: Identifier if left.name == "var" => parseDeclaration()
|
||||||
case left if peek().value == "=" => parseEquals(Some(left))
|
case left if peek().value == "=" => parseEquals(Some(left))
|
||||||
case _ => left
|
case _ => left
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -560,3 +560,66 @@ class ParserEqualTests extends BaseParserTests {
|
|||||||
assertEquals(result, expected)
|
assertEquals(result, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ParseWhileDoTests extends BaseParserTests {
|
||||||
|
test("should parse simple while do") {
|
||||||
|
val p = testParser("while true do print()")
|
||||||
|
val result = p.parseExpression()
|
||||||
|
val expected = WhileDo(Identifier("true"), Function("print", List()))
|
||||||
|
|
||||||
|
assertEquals(result, expected)
|
||||||
|
}
|
||||||
|
test("should parse while do with expressions") {
|
||||||
|
val p = testParser("while i+3 <= x do parse_bool(true) != false")
|
||||||
|
val result = p.parseExpression()
|
||||||
|
val expected = WhileDo(
|
||||||
|
BinaryOperator(
|
||||||
|
BinaryOperator(Identifier("i"), "+", Literal(3)),
|
||||||
|
"<=",
|
||||||
|
Identifier("x")
|
||||||
|
),
|
||||||
|
BinaryOperator(Function("parse_bool", List(Identifier("true"))), "!=", Identifier("false"))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ParserDeclarationTests extends BaseParserTests {
|
||||||
|
test("should parse simple declaration") {
|
||||||
|
val p = testParser("var x = 1")
|
||||||
|
val result = p.parseExpression()
|
||||||
|
val expected = Declaration(Identifier("x"), Literal(1))
|
||||||
|
|
||||||
|
assertEquals(result, expected)
|
||||||
|
}
|
||||||
|
test("should parse declaration with expression body") {
|
||||||
|
val p = testParser("var result = parse(1+x)")
|
||||||
|
val result = p.parseExpression()
|
||||||
|
val expected = Declaration(
|
||||||
|
Identifier("result"),
|
||||||
|
Function("parse", List(BinaryOperator(Literal(1), "+", Identifier("x"))))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(result, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("should not parse declaration with non-identifier name") {
|
||||||
|
val token = Tokenizer.tokenize("var x>").get(2)
|
||||||
|
// var (1+1) is function...
|
||||||
|
val p = testParser("var x>y = parse(1+x)")
|
||||||
|
interceptMessage[java.lang.Exception](s"Token $token was not expected: =") {
|
||||||
|
val result = p.parseExpression()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test("should not parse declaration with non-identifier name (function)".fail) {
|
||||||
|
val token = Tokenizer.tokenize("var (").get(1)
|
||||||
|
// var (1+1) is function...
|
||||||
|
val p = testParser("var (1+1) = parse(1+x)")
|
||||||
|
interceptMessage[java.lang.Exception](s"Token $token was not expected: Identifier") {
|
||||||
|
val result = p.parseExpression()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user