evaluator: implement an elaborate system that should mean that recursive functions don't require reaching far up the stack

This commit is contained in:
Alex Zenla 2023-09-05 01:35:27 -07:00
parent cc23789203
commit 65f61fcd90
Signed by: alex
GPG Key ID: C0780728420EBFE5
3 changed files with 36 additions and 5 deletions

View File

@ -4,6 +4,7 @@ import gay.pizza.pork.ast.*
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> { class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root private var currentScope: Scope = root
private var insideFastCachePreservation = false
override fun visitIntLiteral(node: IntLiteral): Any = node.value override fun visitIntLiteral(node: IntLiteral): Any = node.value
override fun visitStringLiteral(node: StringLiteral): Any = node.text override fun visitStringLiteral(node: StringLiteral): Any = node.text
@ -28,7 +29,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
override fun visitLambda(node: Lambda): CallableFunction { override fun visitLambda(node: Lambda): CallableFunction {
return CallableFunction { arguments -> return CallableFunction { arguments ->
currentScope = currentScope.fork() currentScope = currentScope.fork(inheritFastCache = insideFastCachePreservation)
for ((index, argumentSymbol) in node.arguments.withIndex()) { for ((index, argumentSymbol) in node.arguments.withIndex()) {
currentScope.define(argumentSymbol.id, arguments.values[index]) currentScope.define(argumentSymbol.id, arguments.values[index])
} }
@ -104,7 +105,8 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
override fun visitFunctionDefinition(node: FunctionDefinition): Any { override fun visitFunctionDefinition(node: FunctionDefinition): Any {
val blockFunction = visitBlock(node.block) as BlockFunction val blockFunction = visitBlock(node.block) as BlockFunction
val function = CallableFunction { arguments -> 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()) { for ((index, argumentSymbol) in node.arguments.withIndex()) {
currentScope.define(argumentSymbol.id, arguments.values[index]) currentScope.define(argumentSymbol.id, arguments.values[index])
} }

View File

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

View File

@ -1,10 +1,15 @@
package gay.pizza.pork.evaluator 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 inherited = inherits.toMutableList()
private val variables = mutableMapOf<String, Any>() private val variables = mutableMapOf<String, Any>()
fun define(name: String, value: Any) { fun define(name: String, value: Any) {
fastVariableCache.invalidate(name)
if (variables.containsKey(name)) { if (variables.containsKey(name)) {
throw RuntimeException("Variable '${name}' is already defined") throw RuntimeException("Variable '${name}' is already defined")
} }
@ -12,6 +17,11 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
} }
fun value(name: String): Any { fun value(name: String): Any {
val fastCached = fastVariableCache.lookup(name)
if (fastCached != FastVariableCache.NotFound) {
return fastCached
}
val value = valueOrNotFound(name) val value = valueOrNotFound(name)
if (value == NotFound) { if (value == NotFound) {
throw RuntimeException("Variable '${name}' not defined.") throw RuntimeException("Variable '${name}' not defined.")
@ -48,8 +58,9 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
return value.call(arguments) return value.call(arguments)
} }
fun fork(): Scope { fun fork(inheritFastCache: Boolean = false): Scope {
return Scope(this) val fastCache = if (inheritFastCache) fastVariableCache else FastVariableCache()
return Scope(this, fastVariableCache = fastCache)
} }
fun leave(): Scope { fun leave(): Scope {