You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.9 KiB
Kotlin

package fr.celticinfo.lox
import fr.celticinfo.loxext.RpnPrinter
import org.junit.jupiter.api.assertAll
import kotlin.test.*
import kotlin.test.Test
class ParserTest {
@Test
fun `validate parser`() {
val code = """
1 + 2 * 3 - 4 / 5;
""".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 Expression)
val expr = stmt.expression
assertEquals("1.0 2.0 3.0 * + 4.0 5.0 / -", RpnPrinter().print(expr))
}
@Test
fun `invalid code generates parsing error`() {
val code = """
1 + (2
""".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()
assertNull(stmt)
}
@Test
fun `invalid expression generates parsing error`() {
val code = """
1(2
""".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()
assertNull(stmt)
}
@Test
fun `valid code with multiple statements`() {
val code = """
var a = 1;
var b = 2;
print a + b;
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(3,statements.size)
assertAll(
{ assertTrue(statements[0] is Var) },
{ assertTrue(statements[1] is Var) },
{ assertTrue(statements[2] is Print) }
)
}
@Test
fun `valid code with block`() {
val code = """
{
var a = 1;
var b = 2;
print a + b;
}
""".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.statements
assertEquals(3,block.size)
assertAll(
{ assertTrue(block[0] is Var) },
{ assertTrue(block[1] is Var) },
{ assertTrue(block[2] is Print) }
)
}
@Test
fun `valid code with block and nested block`() {
val code = """
{
var a = 1;
{
var b = 2;
print a + b;
}
}
""".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.statements
assertEquals(2,block.size)
assertAll(
{ assertTrue(block[0] is Var) },
{ assertTrue(block[1] is Block) }
)
val nestedBlock = block[1] as Block
val nestedStatements = nestedBlock.statements
assertEquals(2,nestedStatements.size)
assertAll(
{ assertTrue(nestedStatements[0] is Var) },
{ assertTrue(nestedStatements[1] is Print) }
)
}
@Test
fun `valid code with if statement`() {
val code = """
if (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 If)
val ifStmt = stmt as If
assertTrue(ifStmt.condition is Binary)
assertTrue(ifStmt.thenBranch is Print)
}
@Test
fun `valid code with if else statement`() {
val code = """
if (1 < 2) print "true"; else print "false";
""".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 If)
val ifStmt = stmt as If
assertTrue(ifStmt.condition is Binary)
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)
}
}