Add function call

main
Olivier Abrivard 1 year ago
parent a2054be116
commit 5ee14af59a

@ -42,6 +42,7 @@ fun defineAst(baseName: String, types: List<String>) {
val exprTypes = listOf(
"Assign : Token name, Expr value",
"Binary : Expr left, Token operator, Expr right",
"Call : Expr callee, Token paren, List<Expr> arguments",
"Grouping : Expr expression",
"Literal : Any? value",
"Logical : Expr left, Token operator, Expr right",

@ -6,6 +6,7 @@ package fr.celticinfo.lox
interface ExprVisitor<R> {
fun visitAssign(expr: Assign): R
fun visitBinary(expr: Binary): R
fun visitCall(expr: Call): R
fun visitGrouping(expr: Grouping): R
fun visitLiteral(expr: Literal): R
fun visitLogical(expr: Logical): R
@ -37,6 +38,16 @@ data class Binary(
}
}
data class Call(
val callee: Expr,
val paren: Token,
val arguments: List<Expr>
) : Expr() {
override fun <R> accept(visitor: ExprVisitor<R>): R {
return visitor.visitCall(this)
}
}
data class Grouping(
val expression: Expr
) : Expr() {

@ -125,6 +125,22 @@ class Interpreter: ExprVisitor<Any?>, StmtVisitor<Unit>{
}
}
override fun visitCall(expr: Call): Any? {
val callee = evaluate(expr.callee)
val arguments = expr.arguments.map { evaluate(it) }
if (callee !is LoxCallable) {
throw RuntimeError(expr.paren, "Can only call functions and classes")
}
if (arguments.size != callee.arity()) {
throw RuntimeError(expr.paren, "Expected ${callee.arity()} arguments but got ${arguments.size}")
}
return callee.call(this, arguments)
}
override fun visitGrouping(expr: Grouping): Any? {
return evaluate(expr.expression)
}

@ -0,0 +1,6 @@
package fr.celticinfo.lox
interface LoxCallable {
fun call(interpreter: Interpreter, arguments: List<Any?>): Any?
fun arity(): Int
}

@ -238,7 +238,7 @@ class Parser(private val tokens: List<Token>) {
return Unary(operator, right)
}
return primary()
return call()
}
private fun match(vararg types: TokenType): Boolean {
@ -251,6 +251,36 @@ class Parser(private val tokens: List<Token>) {
return false
}
private fun call(): Expr {
var expr = primary()
while (true) {
if (match(LEFT_PAREN)) {
expr = finishCall(expr)
} else {
break
}
}
return expr
}
private fun finishCall(callee: Expr): Expr {
val arguments: MutableList<Expr> = ArrayList()
if (!check(RIGHT_PAREN)) {
do {
if (arguments.size >= 255) {
error(peek(), "Cannot have more than 255 arguments.")
}
arguments.add(expression())
} while (match(COMMA))
}
val paren = consume(RIGHT_PAREN, "Expect ')' after arguments.")
return Call(callee, paren, arguments)
}
private fun primary(): Expr {
when {
match(FALSE) -> return Literal(false)

Loading…
Cancel
Save