mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10:55 +00:00
evaluator: implement an elaborate system that should mean that recursive functions don't require reaching far up the stack
This commit is contained in:
parent
cc23789203
commit
65f61fcd90
@ -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])
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user