Add methods on classes

main
Olivier Abrivard 1 year ago
parent 22a4d86160
commit fd71a46ede

@ -48,7 +48,14 @@ class Interpreter: ExprVisitor<Any?>, StmtVisitor<Unit>{
override fun visitClassStmt(stmt: ClassStmt) {
environment.define(stmt.name.lexeme, null)
val klass = LoxClass(stmt.name.lexeme)
val methods = stmt.methods.associate { method ->
val function = LoxFunction(method, environment)
method.name.lexeme to function
}
val klass = LoxClass(stmt.name.lexeme, methods)
environment.assign(stmt.name, klass)
}

@ -1,11 +1,15 @@
package fr.celticinfo.lox
class LoxClass(private val name: String) : LoxCallable {
class LoxClass(private val name: String, private val methods: Map<String, LoxFunction>) : LoxCallable {
override fun call(interpreter: Interpreter, arguments: List<Any?>): Any? {
val instance = LoxInstance(this)
return instance
}
fun findMethod(name: String): LoxFunction? {
return methods[name]
}
override fun arity() = 0
override fun toString() = name

@ -8,6 +8,11 @@ class LoxInstance(private val klass: LoxClass) {
return fields[name.lexeme]
}
val method = klass.findMethod(name.lexeme)
if (method != null) {
return method
}
throw RuntimeError(name, "Undefined property '${name.lexeme}'.")
}

@ -20,6 +20,11 @@ class Resolver(private val interpreter: Interpreter) : ExprVisitor<Unit>, StmtVi
override fun visitClassStmt(stmt: ClassStmt) {
declare(stmt.name)
define(stmt.name)
for (method in stmt.methods) {
val declaration = FunctionType.METHOD
resolveFunction(method, declaration)
}
}
override fun visitExpression(stmt: Expression) {
@ -172,5 +177,6 @@ class Resolver(private val interpreter: Interpreter) : ExprVisitor<Unit>, StmtVi
enum class FunctionType {
NONE,
FUNCTION
FUNCTION,
METHOD
}

@ -838,7 +838,6 @@ var a = "global";
}
}
@Test
fun `valid code with properties initialization and access`() {
val standardOut = System.out
@ -873,4 +872,39 @@ var a = "global";
System.setOut(standardOut)
}
}
}
@Test
fun `valid code with method`() {
val standardOut = System.out
val outputStreamCaptor = ByteArrayOutputStream()
System.setOut(PrintStream(outputStreamCaptor))
try {
val code = """
class Bacon {
eat() {
print "Crunch crunch crunch!";
}
}
Bacon().eat();
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(2, statements.size)
val interpreter = Interpreter()
val resolver = Resolver(interpreter)
resolver.resolve(statements)
interpreter.interpret(statements)
val output = outputStreamCaptor.toString().trim()
assertEquals("Crunch crunch crunch!", output)
} finally {
System.setOut(standardOut)
}
}}

@ -291,4 +291,24 @@ class ParserTest {
assertTrue(statements[2] is Expression)
assertTrue(statements[3] is Print)
}
@Test
fun `valid code with methods`() {
val code = """
class Bacon {
eat() {
print "Crunch crunch crunch!";
}
}
Bacon().eat();
""".trimIndent()
val scanner = Scanner(code)
val tokens = scanner.scanTokens()
val parser = Parser(tokens)
val statements = parser.parse()
assertEquals(2,statements.size)
assertTrue(statements[0] is ClassStmt)
assertTrue(statements[1] is Expression)
}
}
Loading…
Cancel
Save