Skip to content

Commit

Permalink
evaluator: implement an elaborate system that should mean that recurs…
Browse files Browse the repository at this point in the history
…ive functions don't require reaching far up the stack
  • Loading branch information
azenla committed Sep 5, 2023
1 parent cc23789 commit 65f61fc
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import gay.pizza.pork.ast.*

class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root
private var insideFastCachePreservation = false

override fun visitIntLiteral(node: IntLiteral): Any = node.value
override fun visitStringLiteral(node: StringLiteral): Any = node.text
Expand All @@ -28,7 +29,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {

override fun visitLambda(node: Lambda): CallableFunction {
return CallableFunction { arguments ->
currentScope = currentScope.fork()
currentScope = currentScope.fork(inheritFastCache = insideFastCachePreservation)
for ((index, argumentSymbol) in node.arguments.withIndex()) {
currentScope.define(argumentSymbol.id, arguments.values[index])
}
Expand Down Expand Up @@ -104,7 +105,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
val blockFunction = visitBlock(node.block) as BlockFunction
val function = CallableFunction { arguments ->
currentScope = currentScope.fork()
currentScope = currentScope.fork(inheritFastCache = insideFastCachePreservation)
currentScope.fastVariableCache.put(node.symbol.id, currentScope.value(node.symbol.id))
for ((index, argumentSymbol) in node.arguments.withIndex()) {
currentScope.define(argumentSymbol.id, arguments.values[index])
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gay.pizza.pork.evaluator

class FastVariableCache {
private val cache = mutableMapOf<String, Any>()

fun put(key: String, value: Any) {
cache[key] = value
}

fun lookup(key: String): Any = cache[key] ?: NotFound
fun has(key: String): Boolean = cache.containsKey(key)

fun invalidate(key: String) {
cache.remove(key)
}

object NotFound
}
17 changes: 14 additions & 3 deletions evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package gay.pizza.pork.evaluator

class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
class Scope(
val parent: Scope? = null,
inherits: List<Scope> = emptyList(),
val fastVariableCache: FastVariableCache = FastVariableCache()
) {
private val inherited = inherits.toMutableList()
private val variables = mutableMapOf<String, Any>()

fun define(name: String, value: Any) {
fastVariableCache.invalidate(name)
if (variables.containsKey(name)) {
throw RuntimeException("Variable '${name}' is already defined")
}
variables[name] = value
}

fun value(name: String): Any {
val fastCached = fastVariableCache.lookup(name)
if (fastCached != FastVariableCache.NotFound) {
return fastCached
}

val value = valueOrNotFound(name)
if (value == NotFound) {
throw RuntimeException("Variable '${name}' not defined.")
Expand Down Expand Up @@ -48,8 +58,9 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
return value.call(arguments)
}

fun fork(): Scope {
return Scope(this)
fun fork(inheritFastCache: Boolean = false): Scope {
val fastCache = if (inheritFastCache) fastVariableCache else FastVariableCache()
return Scope(this, fastVariableCache = fastCache)
}

fun leave(): Scope {
Expand Down

0 comments on commit 65f61fc

Please sign in to comment.