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
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)
|
|
}
|
|
} |