mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 13:11:32 +00:00
ast: utilize extension functions to prevent larger stack frames from default interface methods
This commit is contained in:
@ -0,0 +1,57 @@
|
||||
package gay.pizza.pork.evaluator
|
||||
|
||||
import gay.pizza.pork.ast.CompilationUnit
|
||||
import gay.pizza.pork.ast.Definition
|
||||
import gay.pizza.pork.ast.FunctionDefinition
|
||||
import gay.pizza.pork.ast.ImportDeclaration
|
||||
|
||||
class CompilationUnitContext(
|
||||
val compilationUnit: CompilationUnit,
|
||||
val evaluator: Evaluator,
|
||||
rootScope: Scope
|
||||
) {
|
||||
val internalScope = rootScope.fork()
|
||||
val externalScope = rootScope.fork()
|
||||
|
||||
private var initialized = false
|
||||
|
||||
fun initIfNeeded() {
|
||||
if (initialized) {
|
||||
return
|
||||
}
|
||||
initialized = true
|
||||
processAllImports()
|
||||
processAllDefinitions()
|
||||
}
|
||||
|
||||
private fun processAllDefinitions() {
|
||||
for (definition in compilationUnit.definitions) {
|
||||
processDefinition(definition)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDefinition(definition: Definition) {
|
||||
val internalValue = definitionValue(definition)
|
||||
internalScope.define(definition.symbol.id, internalValue)
|
||||
if (definition.modifiers.export) {
|
||||
externalScope.define(definition.symbol.id, internalValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun definitionValue(definition: Definition): Any = when (definition) {
|
||||
is FunctionDefinition -> FunctionContext(definition, internalScope)
|
||||
}
|
||||
|
||||
private fun processAllImports() {
|
||||
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
|
||||
for (import in imports) {
|
||||
processImport(import)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processImport(import: ImportDeclaration) {
|
||||
val path = import.path.text
|
||||
val evaluationContext = evaluator.context(path)
|
||||
internalScope.inherit(evaluationContext.externalScope)
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package gay.pizza.pork.evaluator
|
||||
|
||||
import gay.pizza.pork.ast.CompilationUnit
|
||||
import gay.pizza.pork.ast.ImportDeclaration
|
||||
|
||||
class EvaluationContext(
|
||||
val compilationUnit: CompilationUnit,
|
||||
val evaluationContextProvider: EvaluationContextProvider,
|
||||
rootScope: Scope
|
||||
) {
|
||||
val internalRootScope = rootScope.fork()
|
||||
val externalRootScope = rootScope.fork()
|
||||
|
||||
private var initialized = false
|
||||
|
||||
fun init() {
|
||||
if (initialized) {
|
||||
return
|
||||
}
|
||||
initialized = true
|
||||
val imports = compilationUnit.declarations.filterIsInstance<ImportDeclaration>()
|
||||
for (import in imports) {
|
||||
val evaluationContext = evaluationContextProvider.provideEvaluationContext(import.path.text)
|
||||
internalRootScope.inherit(evaluationContext.externalRootScope)
|
||||
}
|
||||
|
||||
for (definition in compilationUnit.definitions) {
|
||||
val evaluationVisitor = EvaluationVisitor(internalRootScope)
|
||||
evaluationVisitor.visit(definition)
|
||||
if (!definition.modifiers.export) {
|
||||
continue
|
||||
}
|
||||
val internalValue = internalRootScope.value(definition.symbol.id)
|
||||
externalRootScope.define(definition.symbol.id, internalValue)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package gay.pizza.pork.evaluator
|
||||
|
||||
interface EvaluationContextProvider {
|
||||
fun provideEvaluationContext(path: String): EvaluationContext
|
||||
}
|
@ -2,23 +2,24 @@ package gay.pizza.pork.evaluator
|
||||
|
||||
import gay.pizza.pork.ast.*
|
||||
|
||||
class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
||||
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
||||
private var currentScope: Scope = root
|
||||
|
||||
override fun visitIntLiteral(node: IntLiteral): Any = node.value
|
||||
override fun visitStringLiteral(node: StringLiteral): Any = node.text
|
||||
override fun visitBooleanLiteral(node: BooleanLiteral): Any = node.value
|
||||
override fun visitListLiteral(node: ListLiteral): Any = node.items.map { visit(it) }
|
||||
override fun visitListLiteral(node: ListLiteral): Any =
|
||||
node.items.map { it.visit(this) }
|
||||
|
||||
override fun visitSymbol(node: Symbol): Any = None
|
||||
|
||||
override fun visitFunctionCall(node: FunctionCall): Any {
|
||||
val arguments = node.arguments.map { visit(it) }
|
||||
val arguments = node.arguments.map { it.visit(this) }
|
||||
return currentScope.call(node.symbol.id, Arguments(arguments))
|
||||
}
|
||||
|
||||
override fun visitLetAssignment(node: LetAssignment): Any {
|
||||
val value = visit(node.value)
|
||||
val value = node.value.visit(this)
|
||||
currentScope.define(node.symbol.id, value)
|
||||
return value
|
||||
}
|
||||
@ -35,7 +36,7 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
||||
try {
|
||||
var value: Any? = null
|
||||
for (expression in node.expressions) {
|
||||
value = visit(expression)
|
||||
value = expression.visit(this)
|
||||
}
|
||||
value ?: None
|
||||
} finally {
|
||||
@ -44,10 +45,11 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitParentheses(node: Parentheses): Any = visit(node.expression)
|
||||
override fun visitParentheses(node: Parentheses): Any =
|
||||
node.expression.visit(this)
|
||||
|
||||
override fun visitPrefixOperation(node: PrefixOperation): Any {
|
||||
val value = visit(node.expression)
|
||||
val value = node.expression.visit(this)
|
||||
return when (node.op) {
|
||||
PrefixOperator.Negate -> {
|
||||
if (value !is Boolean) {
|
||||
@ -59,21 +61,18 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
||||
}
|
||||
|
||||
override fun visitIf(node: If): Any {
|
||||
val condition = visit(node.condition)
|
||||
val condition = node.condition.visit(this)
|
||||
return if (condition == true) {
|
||||
visit(node.thenExpression)
|
||||
node.thenExpression.visit(this)
|
||||
} else {
|
||||
if (node.elseExpression != null) {
|
||||
visit(node.elseExpression!!)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
val elseExpression = node.elseExpression
|
||||
elseExpression?.visit(this) ?: None
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitInfixOperation(node: InfixOperation): Any {
|
||||
val left = visit(node.left)
|
||||
val right = visit(node.right)
|
||||
val left = node.left.visit(this)
|
||||
val right = node.right.visit(this)
|
||||
|
||||
when (node.op) {
|
||||
InfixOperator.Equals -> {
|
||||
@ -101,28 +100,21 @@ class EvaluationVisitor(val root: Scope) : NodeVisitor<Any> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
||||
val function = CallableFunction { arguments ->
|
||||
currentScope = root.fork()
|
||||
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
||||
currentScope.define(argumentSymbol.id, arguments.values[index])
|
||||
}
|
||||
val visitor = EvaluationVisitor(currentScope)
|
||||
val blockFunction = visitor.visitBlock(node.block) as BlockFunction
|
||||
return@CallableFunction blockFunction.call()
|
||||
}
|
||||
currentScope.define(node.symbol.id, function)
|
||||
return None
|
||||
}
|
||||
|
||||
override fun visitBlock(node: Block): Any = BlockFunction {
|
||||
override fun visitBlock(node: Block): BlockFunction = BlockFunction {
|
||||
var value: Any? = null
|
||||
for (expression in node.expressions) {
|
||||
value = visit(expression)
|
||||
value = expression.visit(this)
|
||||
}
|
||||
value ?: None
|
||||
}
|
||||
|
||||
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
||||
throw RuntimeException(
|
||||
"Function declarations cannot be visited in an EvaluationVisitor. " +
|
||||
"Utilize a FunctionContext."
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitImportDeclaration(node: ImportDeclaration): Any {
|
||||
throw RuntimeException(
|
||||
"Import declarations cannot be visited in an EvaluationVisitor. " +
|
||||
|
@ -2,21 +2,19 @@ package gay.pizza.pork.evaluator
|
||||
|
||||
import gay.pizza.pork.frontend.World
|
||||
|
||||
class Evaluator(val world: World, val scope: Scope) : EvaluationContextProvider {
|
||||
private val contexts = mutableMapOf<String, EvaluationContext>()
|
||||
class Evaluator(val world: World, val scope: Scope) {
|
||||
private val contexts = mutableMapOf<String, CompilationUnitContext>()
|
||||
|
||||
fun evaluate(path: String): Scope {
|
||||
val context = provideEvaluationContext(path)
|
||||
return context.externalRootScope
|
||||
}
|
||||
fun evaluate(path: String): Scope =
|
||||
context(path).externalScope
|
||||
|
||||
override fun provideEvaluationContext(path: String): EvaluationContext {
|
||||
fun context(path: String): CompilationUnitContext {
|
||||
val unit = world.load(path)
|
||||
val identity = world.contentSource.stableContentIdentity(path)
|
||||
val context = contexts.computeIfAbsent(identity) {
|
||||
EvaluationContext(unit, this, scope)
|
||||
CompilationUnitContext(unit, this, scope)
|
||||
}
|
||||
context.init()
|
||||
context.initIfNeeded()
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package gay.pizza.pork.evaluator
|
||||
|
||||
import gay.pizza.pork.ast.FunctionDefinition
|
||||
|
||||
class FunctionContext(val node: FunctionDefinition, val internalScope: Scope) : CallableFunction {
|
||||
override fun call(arguments: Arguments): Any {
|
||||
val scope = internalScope.fork()
|
||||
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
||||
scope.define(argumentSymbol.id, arguments.values[index])
|
||||
}
|
||||
val visitor = EvaluationVisitor(scope)
|
||||
val blockFunction = visitor.visitBlock(node.block)
|
||||
return blockFunction.call()
|
||||
}
|
||||
}
|
@ -14,8 +14,8 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
|
||||
|
||||
fun value(name: String): Any {
|
||||
val value = valueOrNotFound(name)
|
||||
if (value == NotFound) {
|
||||
throw RuntimeException("Variable '${name}' not defined.")
|
||||
if (value === NotFound) {
|
||||
throw RuntimeException("Variable '${name}' not defined")
|
||||
}
|
||||
return value
|
||||
}
|
||||
@ -25,14 +25,14 @@ class Scope(val parent: Scope? = null, inherits: List<Scope> = emptyList()) {
|
||||
if (value == null) {
|
||||
if (parent != null) {
|
||||
val parentMaybeFound = parent.valueOrNotFound(name)
|
||||
if (parentMaybeFound != NotFound) {
|
||||
if (parentMaybeFound !== NotFound) {
|
||||
return parentMaybeFound
|
||||
}
|
||||
}
|
||||
|
||||
for (inherit in inherited) {
|
||||
val inheritMaybeFound = inherit.valueOrNotFound(name)
|
||||
if (inheritMaybeFound != NotFound) {
|
||||
if (inheritMaybeFound !== NotFound) {
|
||||
return inheritMaybeFound
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user