Add For Loops

main
Olivier Abrivard 1 year ago
parent cc80306292
commit a2054be116

@ -21,6 +21,10 @@ class AstPrinter : ExprVisitor<String> {
return expr.value?.toString() ?: "nil"
}
override fun visitLogical(expr: Logical): String {
return parenthesize(expr.operator.lexeme, expr.left, expr.right)
}
override fun visitUnary(expr: Unary): String {
return parenthesize(expr.operator.lexeme, expr.right)
}

@ -54,6 +54,7 @@ class Parser(private val tokens: List<Token>) {
private fun statement(): Stmt {
return when {
match(FOR) -> forStatement()
match(IF) -> ifStatement()
match(PRINT) -> printStatement()
match(WHILE) -> whileStatement()
@ -62,6 +63,42 @@ class Parser(private val tokens: List<Token>) {
}
}
private fun forStatement(): Stmt {
consume(LEFT_PAREN, "Expect '(' after 'for'.")
val initializer = when {
match(SEMICOLON) -> null
match(VAR) -> varDeclaration()
else -> expressionStatement()
}
val condition = when {
!check(SEMICOLON) -> expression()
else -> Literal(true)
}
consume(SEMICOLON, "Expect ';' after loop condition.")
val increment = when {
!check(RIGHT_PAREN) -> expression()
else -> null
}
consume(RIGHT_PAREN, "Expect ')' after for clauses.")
var body = statement()
if (increment != null) {
body = Block(listOf(body, Expression(increment)))
}
body = While(condition, body)
if (initializer != null) {
body = Block(listOf(initializer, body))
}
return body
}
private fun ifStatement(): Stmt {
consume(LEFT_PAREN, "Expect '(' after 'if'.")
val condition = expression()

@ -23,6 +23,10 @@ class RpnPrinter : ExprVisitor<String> {
return expr.value?.toString() ?: "nil"
}
override fun visitLogical(expr: Logical): String {
return stack(expr.operator.lexeme, expr.left, expr.right)
}
override fun visitUnary(expr: Unary): String {
return stack(expr.operator.lexeme, expr.right)
}

@ -305,4 +305,57 @@ else print "else";
System.setOut(standardOut)
}
}
@Test
fun `Fibonacci test`() {
val standardOut = System.out
val outputStreamCaptor = ByteArrayOutputStream()
System.setOut(PrintStream(outputStreamCaptor))
try {
val code = """
var a = 0;
var temp;
for (var b = 1; a < 10000; b = temp + b) {
print a;
temp = a;
a = b;
}
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(3, statements.size)
Interpreter().interpret(statements)
val output = outputStreamCaptor.toString().trim()
assertEquals("0\n" +
"1\n" +
"1\n" +
"2\n" +
"3\n" +
"5\n" +
"8\n" +
"13\n" +
"21\n" +
"34\n" +
"55\n" +
"89\n" +
"144\n" +
"233\n" +
"377\n" +
"610\n" +
"987\n" +
"1597\n" +
"2584\n" +
"4181\n" +
"6765", output)
} finally {
System.setOut(standardOut)
}
}
}

@ -161,4 +161,38 @@ class ParserTest {
assertTrue(ifStmt.thenBranch is Print)
assertTrue(ifStmt.elseBranch is Print)
}
@Test
fun `valid code with while statement`() {
val code = """
while (1 < 2) print "true";
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(1,statements.size)
val stmt = statements.first()
assertTrue(stmt is While)
val whileStmt = stmt as While
assertTrue(whileStmt.condition is Binary)
assertTrue(whileStmt.body is Print)
}
@Test
fun `valid code with for statement`() {
val code = """
for (var i = 0; i < 10; i = i + 1) print i;
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(1,statements.size)
val stmt = statements.first()
assertTrue(stmt is Block)
val block = stmt as Block
val blockStatements = block.statements
assertEquals(2,blockStatements.size)
}
}
Loading…
Cancel
Save