evaluator: ensure function definitions use root scope

This commit is contained in:
Alex Zenla 2023-09-05 02:20:46 -07:00
parent 725137c82f
commit 9634a735ee
Signed by: alex
GPG Key ID: C0780728420EBFE5
4 changed files with 13 additions and 25 deletions

View File

@ -10,10 +10,10 @@ class EvaluationContext(
) { ) {
private var isAlreadySetup = false private var isAlreadySetup = false
val internalScope = rootScope.fork() val internalRootScope = rootScope.fork()
val externalScope = rootScope.fork() val externalRootScope = rootScope.fork()
private val evaluationVisitor = EvaluationVisitor(internalScope) private val evaluationVisitor = EvaluationVisitor(internalRootScope)
fun setup() { fun setup() {
if (isAlreadySetup) { if (isAlreadySetup) {
@ -23,13 +23,13 @@ class EvaluationContext(
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>() val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
for (import in imports) { for (import in imports) {
val evaluationContext = evaluationContextProvider.provideEvaluationContext(import.path.text) val evaluationContext = evaluationContextProvider.provideEvaluationContext(import.path.text)
internalScope.inherit(evaluationContext.externalScope) internalRootScope.inherit(evaluationContext.externalRootScope)
} }
for (definition in compilationUnit.definitions) { for (definition in compilationUnit.definitions) {
evaluationVisitor.visit(definition) evaluationVisitor.visit(definition)
if (definition.modifiers.export) { if (definition.modifiers.export) {
externalScope.define(definition.symbol.id, internalScope.value(definition.symbol.id)) externalRootScope.define(definition.symbol.id, internalRootScope.value(definition.symbol.id))
} }
} }
} }

View File

@ -2,7 +2,7 @@ package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.* import gay.pizza.pork.ast.*
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> { class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root private var currentScope: Scope = root
override fun visitIntLiteral(node: IntLiteral): Any = node.value override fun visitIntLiteral(node: IntLiteral): Any = node.value
@ -104,15 +104,15 @@ 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(inheritFastCache = true) val formerScope = currentScope
currentScope.fastVariableCache.put(node.symbol.id, currentScope.value(node.symbol.id)) currentScope = root.fork()
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])
} }
try { try {
return@CallableFunction blockFunction.call() return@CallableFunction blockFunction.call()
} finally { } finally {
currentScope = currentScope.leave() currentScope = formerScope
} }
} }
currentScope.define(node.symbol.id, function) currentScope.define(node.symbol.id, function)

View File

@ -7,7 +7,7 @@ class Evaluator(val world: World, val scope: Scope) : EvaluationContextProvider
fun evaluate(path: String): Scope { fun evaluate(path: String): Scope {
val context = provideEvaluationContext(path) val context = provideEvaluationContext(path)
return context.externalScope return context.externalRootScope
} }
override fun provideEvaluationContext(path: String): EvaluationContext { override fun provideEvaluationContext(path: String): EvaluationContext {

View File

@ -1,15 +1,10 @@
package gay.pizza.pork.evaluator package gay.pizza.pork.evaluator
class Scope( class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
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")
} }
@ -17,11 +12,6 @@ class Scope(
} }
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.")
@ -58,10 +48,8 @@ class Scope(
return value.call(arguments) return value.call(arguments)
} }
fun fork(inheritFastCache: Boolean = false): Scope { fun fork(): Scope =
val fastCache = if (inheritFastCache) fastVariableCache else FastVariableCache() Scope(this)
return Scope(this, fastVariableCache = fastCache)
}
fun leave(): Scope { fun leave(): Scope {
if (parent == null) { if (parent == null) {