mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
evaluator: significant performance enhancements
This commit is contained in:
parent
1a759b9746
commit
4758e92676
@ -1,3 +1,3 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
class Arguments(val values: List<Any>)
|
typealias ArgumentList = List<Any>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
fun interface BlockFunction {
|
abstract class BlockFunction {
|
||||||
fun call(): Any
|
abstract fun call(): Any
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
class CallStack(val functionStack: MutableList<FunctionContext> = mutableListOf()) {
|
||||||
|
fun push(context: FunctionContext) {
|
||||||
|
functionStack.add(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop() {
|
||||||
|
functionStack.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = buildString {
|
||||||
|
appendLine("Pork Stacktrace:")
|
||||||
|
for (item in functionStack.asReversed()) {
|
||||||
|
appendLine(" at ${item.name}")
|
||||||
|
}
|
||||||
|
}.trimEnd()
|
||||||
|
|
||||||
|
fun copy(): CallStack = CallStack(functionStack.toMutableList())
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
fun interface CallableFunction {
|
fun interface CallableFunction {
|
||||||
fun call(arguments: Arguments): Any
|
fun call(arguments: ArgumentList, stack: CallStack): Any
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ class CompilationUnitContext(
|
|||||||
val compilationUnit: CompilationUnit,
|
val compilationUnit: CompilationUnit,
|
||||||
val evaluator: Evaluator,
|
val evaluator: Evaluator,
|
||||||
rootScope: Scope,
|
rootScope: Scope,
|
||||||
name: String = "unknown"
|
val name: String = "unknown"
|
||||||
) {
|
) {
|
||||||
val internalScope = rootScope.fork("internal $name")
|
val internalScope = rootScope.fork("internal $name")
|
||||||
val externalScope = rootScope.fork("external $name")
|
val externalScope = rootScope.fork("external $name")
|
||||||
@ -40,7 +40,7 @@ class CompilationUnitContext(
|
|||||||
private fun definitionValue(definition: Definition): Any = when (definition) {
|
private fun definitionValue(definition: Definition): Any = when (definition) {
|
||||||
is FunctionDefinition -> FunctionContext(this, definition)
|
is FunctionDefinition -> FunctionContext(this, definition)
|
||||||
is LetDefinition -> {
|
is LetDefinition -> {
|
||||||
EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}"))
|
EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}"), CallStack())
|
||||||
.visit(definition.value)
|
.visit(definition.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ package gay.pizza.pork.evaluator
|
|||||||
import gay.pizza.pork.ast.*
|
import gay.pizza.pork.ast.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
|
||||||
|
class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor<Any> {
|
||||||
private var currentScope: Scope = root
|
private var currentScope: Scope = root
|
||||||
|
|
||||||
override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value
|
override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value
|
||||||
@ -16,9 +17,15 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
throw RuntimeException("Unable to iterate on value that is not a iterable.")
|
throw RuntimeException("Unable to iterate on value that is not a iterable.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reuseScope: Scope? = null
|
||||||
|
|
||||||
for (item in value) {
|
for (item in value) {
|
||||||
try {
|
try {
|
||||||
scoped {
|
if (reuseScope == null) {
|
||||||
|
reuseScope = currentScope.fork(name = "ForIn")
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped(reuseScope, node = node) {
|
||||||
currentScope.define(node.symbol.id, item ?: None)
|
currentScope.define(node.symbol.id, item ?: None)
|
||||||
result = blockFunction.call()
|
result = blockFunction.call()
|
||||||
}
|
}
|
||||||
@ -28,6 +35,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reuseScope?.disown()
|
||||||
return result ?: None
|
return result ?: None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +54,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
override fun visitFunctionCall(node: FunctionCall): Any {
|
override fun visitFunctionCall(node: FunctionCall): Any {
|
||||||
val arguments = node.arguments.map { it.visit(this) }
|
val arguments = node.arguments.map { it.visit(this) }
|
||||||
val functionValue = currentScope.value(node.symbol.id) as CallableFunction
|
val functionValue = currentScope.value(node.symbol.id) as CallableFunction
|
||||||
return functionValue.call(Arguments(arguments))
|
return functionValue.call(arguments, stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLetAssignment(node: LetAssignment): Any {
|
override fun visitLetAssignment(node: LetAssignment): Any {
|
||||||
@ -71,6 +79,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
override fun visitWhile(node: While): Any {
|
override fun visitWhile(node: While): Any {
|
||||||
val blockFunction = node.block.visit(this) as BlockFunction
|
val blockFunction = node.block.visit(this) as BlockFunction
|
||||||
var result: Any? = null
|
var result: Any? = null
|
||||||
|
var reuseScope: Scope? = null
|
||||||
while (true) {
|
while (true) {
|
||||||
val value = node.condition.visit(this)
|
val value = node.condition.visit(this)
|
||||||
if (value !is Boolean) {
|
if (value !is Boolean) {
|
||||||
@ -78,13 +87,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
if (!value) break
|
if (!value) break
|
||||||
try {
|
try {
|
||||||
scoped { result = blockFunction.call() }
|
if (reuseScope == null) {
|
||||||
|
reuseScope = currentScope.fork(name = "While")
|
||||||
|
}
|
||||||
|
scoped(reuseScope, node = node) { result = blockFunction.call() }
|
||||||
} catch (_: BreakMarker) {
|
} catch (_: BreakMarker) {
|
||||||
break
|
break
|
||||||
} catch (_: ContinueMarker) {
|
} catch (_: ContinueMarker) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reuseScope?.disown()
|
||||||
return result ?: None
|
return result ?: None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,10 +186,10 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
val condition = node.condition.visit(this)
|
val condition = node.condition.visit(this)
|
||||||
return if (condition == true) {
|
return if (condition == true) {
|
||||||
val blockFunction = node.thenBlock.visit(this) as BlockFunction
|
val blockFunction = node.thenBlock.visit(this) as BlockFunction
|
||||||
scoped { blockFunction.call() }
|
scoped(node = node) { blockFunction.call() }
|
||||||
} else if (node.elseBlock != null) {
|
} else if (node.elseBlock != null) {
|
||||||
val blockFunction = node.elseBlock!!.visit(this) as BlockFunction
|
val blockFunction = node.elseBlock!!.visit(this) as BlockFunction
|
||||||
scoped { blockFunction.call() }
|
scoped(node = node) { blockFunction.call() }
|
||||||
} else None
|
} else None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,12 +363,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(node: Block): BlockFunction = BlockFunction {
|
override fun visitBlock(node: Block): BlockFunction {
|
||||||
var value: Any? = null
|
val visitor = this
|
||||||
for (expression in node.expressions) {
|
return object : BlockFunction() {
|
||||||
value = expression.visit(this)
|
override fun call(): Any {
|
||||||
|
var value: Any? = null
|
||||||
|
for (expression in node.expressions) {
|
||||||
|
value = expression.visit(visitor)
|
||||||
|
}
|
||||||
|
return value ?: None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
value ?: None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
override fun visitFunctionDefinition(node: FunctionDefinition): Any {
|
||||||
@ -393,12 +411,18 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
|
|||||||
|
|
||||||
override fun visitContinue(node: Continue): Any = ContinueMarker
|
override fun visitContinue(node: Continue): Any = ContinueMarker
|
||||||
|
|
||||||
private inline fun <T> scoped(block: () -> T): T {
|
private inline fun <T> scoped(reuseScope: Scope? = null, node: Node? = null, block: () -> T): T {
|
||||||
currentScope = currentScope.fork()
|
val previousScope = currentScope
|
||||||
|
currentScope = reuseScope ?: currentScope.fork(name = node?.type?.name)
|
||||||
try {
|
try {
|
||||||
return block()
|
return block()
|
||||||
} finally {
|
} finally {
|
||||||
currentScope = currentScope.leave()
|
if (reuseScope == null) {
|
||||||
|
currentScope = currentScope.leave(disown = true)
|
||||||
|
} else {
|
||||||
|
reuseScope.markForReuse()
|
||||||
|
currentScope = previousScope
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ package gay.pizza.pork.evaluator
|
|||||||
import gay.pizza.pork.ast.FunctionDefinition
|
import gay.pizza.pork.ast.FunctionDefinition
|
||||||
|
|
||||||
class FunctionContext(val compilationUnitContext: CompilationUnitContext, val node: FunctionDefinition) : CallableFunction {
|
class FunctionContext(val compilationUnitContext: CompilationUnitContext, val node: FunctionDefinition) : CallableFunction {
|
||||||
|
val name: String = "${compilationUnitContext.name} ${node.symbol.id}"
|
||||||
|
|
||||||
private fun resolveMaybeNative(): CallableFunction? = if (node.native == null) {
|
private fun resolveMaybeNative(): CallableFunction? = if (node.native == null) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
@ -14,19 +16,19 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no
|
|||||||
|
|
||||||
private val nativeCached by lazy { resolveMaybeNative() }
|
private val nativeCached by lazy { resolveMaybeNative() }
|
||||||
|
|
||||||
override fun call(arguments: Arguments): Any {
|
override fun call(arguments: ArgumentList, stack: CallStack): Any {
|
||||||
if (nativeCached != null) {
|
if (nativeCached != null) {
|
||||||
return nativeCached!!.call(arguments)
|
return nativeCached!!.call(arguments, stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
val scope = compilationUnitContext.internalScope.fork()
|
val scope = compilationUnitContext.internalScope.fork(node.symbol.id)
|
||||||
for ((index, spec) in node.arguments.withIndex()) {
|
for ((index, spec) in node.arguments.withIndex()) {
|
||||||
if (spec.multiple) {
|
if (spec.multiple) {
|
||||||
val list = arguments.values.subList(index, arguments.values.size - 1)
|
val list = arguments.subList(index, arguments.size - 1)
|
||||||
scope.define(spec.symbol.id, list)
|
scope.define(spec.symbol.id, list)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
scope.define(spec.symbol.id, arguments.values[index])
|
scope.define(spec.symbol.id, arguments[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +36,19 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no
|
|||||||
throw RuntimeException("Native or Block is required for FunctionDefinition")
|
throw RuntimeException("Native or Block is required for FunctionDefinition")
|
||||||
}
|
}
|
||||||
|
|
||||||
val visitor = EvaluationVisitor(scope)
|
val visitor = EvaluationVisitor(scope, stack)
|
||||||
|
stack.push(this)
|
||||||
val blockFunction = visitor.visitBlock(node.block!!)
|
val blockFunction = visitor.visitBlock(node.block!!)
|
||||||
return blockFunction.call()
|
try {
|
||||||
|
return blockFunction.call()
|
||||||
|
} catch (e: PorkError) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
val stackForError = stack.copy()
|
||||||
|
throw PorkError(e, stackForError)
|
||||||
|
} finally {
|
||||||
|
scope.disown()
|
||||||
|
stack.pop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,22 +5,37 @@ import gay.pizza.pork.ast.ArgumentSpec
|
|||||||
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
|
class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider {
|
||||||
private val functions = mutableMapOf(
|
private val functions = mutableMapOf(
|
||||||
"print" to CallableFunction(::printValues),
|
"print" to CallableFunction(::printValues),
|
||||||
"println" to CallableFunction(::printLine)
|
"println" to CallableFunction(::printLine),
|
||||||
|
"listSet" to CallableFunction(::setInList),
|
||||||
|
"listInitWith" to CallableFunction(::listInitWith)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
|
override fun provideNativeFunction(definition: String, arguments: List<ArgumentSpec>): CallableFunction {
|
||||||
return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
|
return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printValues(arguments: Arguments): Any {
|
private fun printValues(arguments: ArgumentList, stack: CallStack): Any {
|
||||||
if (quiet || arguments.values.isEmpty()) return None
|
if (quiet || arguments.isEmpty()) return None
|
||||||
print(arguments.values.joinToString(" "))
|
print(arguments.joinToString(" "))
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printLine(arguments: Arguments): Any {
|
private fun printLine(arguments: ArgumentList, stack: CallStack): Any {
|
||||||
if (quiet) return None
|
if (quiet) return None
|
||||||
println(arguments.values.joinToString(" "))
|
println(arguments.joinToString(" "))
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setInList(arguments: ArgumentList, stack: CallStack): Any {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val list = arguments[0] as MutableList<Any>
|
||||||
|
val value = arguments[2]
|
||||||
|
list[(arguments[1] as Number).toInt()] = value
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listInitWith(arguments: ArgumentList, stack: CallStack): Any {
|
||||||
|
val size = (arguments[0] as Number).toInt()
|
||||||
|
return MutableList(size) { arguments[1] }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
class PorkError(cause: Exception, stack: CallStack) : RuntimeException(stack.toString(), cause)
|
@ -1,19 +1,25 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
class Scope(
|
class Scope(
|
||||||
val parent: Scope? = null,
|
var parent: Scope? = null,
|
||||||
inherits: List<Scope> = emptyList(),
|
var inherits: List<Scope> = emptyList(),
|
||||||
val name: String? = null
|
var name: String? = null
|
||||||
) {
|
) {
|
||||||
private val inherited = inherits.toMutableList()
|
private var isCurrentlyFree = false
|
||||||
private val variables = mutableMapOf<String, ValueStore>()
|
private val variables = mutableMapOf<String, ValueStore>()
|
||||||
|
|
||||||
fun define(name: String, value: Any, type: ValueStoreType = ValueStoreType.Let) {
|
fun define(name: String, value: Any, type: ValueStoreType = ValueStoreType.Let) {
|
||||||
val previous = variables.put(name, ValueStore(value, type))
|
val existing = variables[name]
|
||||||
if (previous != null) {
|
if (existing != null) {
|
||||||
variables[name] = previous
|
if (existing.type == ValueStoreType.ReuseReady) {
|
||||||
|
existing.type = type
|
||||||
|
existing.value = value
|
||||||
|
return
|
||||||
|
}
|
||||||
throw RuntimeException("Variable '${name}' is already defined")
|
throw RuntimeException("Variable '${name}' is already defined")
|
||||||
}
|
}
|
||||||
|
val store = ValueStoreCache.obtain(value, type)
|
||||||
|
variables[name] = store
|
||||||
}
|
}
|
||||||
|
|
||||||
fun set(name: String, value: Any) {
|
fun set(name: String, value: Any) {
|
||||||
@ -40,13 +46,13 @@ class Scope(
|
|||||||
val holder = variables[name]
|
val holder = variables[name]
|
||||||
if (holder == null) {
|
if (holder == null) {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
val parentMaybeFound = parent.valueHolderOrNotFound(name)
|
val parentMaybeFound = parent!!.valueHolderOrNotFound(name)
|
||||||
if (parentMaybeFound !== NotFound.Holder) {
|
if (parentMaybeFound !== NotFound.Holder) {
|
||||||
return parentMaybeFound
|
return parentMaybeFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (inherit in inherited) {
|
for (inherit in inherits) {
|
||||||
val inheritMaybeFound = inherit.valueHolderOrNotFound(name)
|
val inheritMaybeFound = inherit.valueHolderOrNotFound(name)
|
||||||
if (inheritMaybeFound !== NotFound.Holder) {
|
if (inheritMaybeFound !== NotFound.Holder) {
|
||||||
return inheritMaybeFound
|
return inheritMaybeFound
|
||||||
@ -54,21 +60,29 @@ class Scope(
|
|||||||
}
|
}
|
||||||
return NotFound.Holder
|
return NotFound.Holder
|
||||||
}
|
}
|
||||||
|
if (holder.type == ValueStoreType.ReuseReady) {
|
||||||
|
throw RuntimeException("Attempt to reuse ValueStore in the reused state, prior to definition.")
|
||||||
|
}
|
||||||
return holder
|
return holder
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fork(name: String? = null): Scope =
|
fun fork(name: String? = null): Scope =
|
||||||
Scope(this, name = name)
|
ScopeCache.obtain(this, name = name)
|
||||||
|
|
||||||
internal fun inherit(scope: Scope) {
|
internal fun inherit(scope: Scope) {
|
||||||
inherited.add(scope)
|
val copy = inherits.toMutableList()
|
||||||
|
copy.add(scope)
|
||||||
|
inherits = copy
|
||||||
}
|
}
|
||||||
|
|
||||||
fun leave(): Scope {
|
fun leave(disown: Boolean = false): Scope {
|
||||||
if (parent == null) {
|
val currentParent = parent ?: throw RuntimeException("Attempted to leave the root scope!")
|
||||||
throw RuntimeException("Attempted to leave the root scope!")
|
|
||||||
|
if (disown) {
|
||||||
|
disown()
|
||||||
}
|
}
|
||||||
return parent
|
|
||||||
|
return currentParent
|
||||||
}
|
}
|
||||||
|
|
||||||
fun crawlScopePath(
|
fun crawlScopePath(
|
||||||
@ -79,7 +93,7 @@ class Scope(
|
|||||||
block(key, path)
|
block(key, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (inherit in inherited) {
|
for (inherit in inherits) {
|
||||||
val mutablePath = path.toMutableList()
|
val mutablePath = path.toMutableList()
|
||||||
mutablePath.add("inherit ${inherit.name ?: "unknown"}")
|
mutablePath.add("inherit ${inherit.name ?: "unknown"}")
|
||||||
inherit.crawlScopePath(mutablePath, block)
|
inherit.crawlScopePath(mutablePath, block)
|
||||||
@ -87,12 +101,56 @@ class Scope(
|
|||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
val mutablePath = path.toMutableList()
|
val mutablePath = path.toMutableList()
|
||||||
mutablePath.add("parent ${parent.name ?: "unknown"}")
|
mutablePath.add("parent ${parent?.name ?: "unknown"}")
|
||||||
parent.crawlScopePath(mutablePath, block)
|
parent?.crawlScopePath(mutablePath, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markForReuse() {
|
||||||
|
for (store in variables.values) {
|
||||||
|
store.type = ValueStoreType.ReuseReady
|
||||||
|
store.value = None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disown() {
|
||||||
|
for (store in variables.values) {
|
||||||
|
store.disown()
|
||||||
|
}
|
||||||
|
|
||||||
|
name = null
|
||||||
|
parent = null
|
||||||
|
inherits = emptyList()
|
||||||
|
variables.clear()
|
||||||
|
isCurrentlyFree = true
|
||||||
|
ScopeCache.put(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun adopt(parent: Scope? = null, inherits: List<Scope>, name: String? = null) {
|
||||||
|
if (!isCurrentlyFree) {
|
||||||
|
throw RuntimeException("Scope is not free, but adopt() was attempted.")
|
||||||
|
}
|
||||||
|
this.parent = parent
|
||||||
|
this.inherits = inherits
|
||||||
|
this.name = name
|
||||||
|
}
|
||||||
|
|
||||||
private object NotFound {
|
private object NotFound {
|
||||||
val Holder = ValueStore(NotFound, ValueStoreType.Let)
|
val Holder = ValueStore(NotFound, ValueStoreType.Let)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val path: String
|
||||||
|
get() = buildString {
|
||||||
|
val list = mutableListOf<String?>()
|
||||||
|
var current: Scope? = this@Scope
|
||||||
|
while (current != null) {
|
||||||
|
list.add(current.name ?: "unknown")
|
||||||
|
current = current.parent
|
||||||
|
}
|
||||||
|
append(list.reversed().joinToString(" -> "))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun root(): Scope = Scope(name = "root")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
object ScopeCache {
|
||||||
|
private val cache = mutableListOf<Scope>()
|
||||||
|
|
||||||
|
fun obtain(parent: Scope? = null, inherits: List<Scope> = emptyList(), name: String? = null): Scope {
|
||||||
|
val cachedScope = cache.removeFirstOrNull()
|
||||||
|
if (cachedScope != null) {
|
||||||
|
cachedScope.adopt(parent = parent, inherits = inherits, name = name)
|
||||||
|
return cachedScope
|
||||||
|
}
|
||||||
|
return Scope(parent = parent, inherits = inherits, name = name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun put(scope: Scope) {
|
||||||
|
cache.add(scope)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,23 @@
|
|||||||
package gay.pizza.pork.evaluator
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
class ValueStore(var value: Any, val type: ValueStoreType) {
|
class ValueStore(var value: Any, var type: ValueStoreType) {
|
||||||
|
var isCurrentlyFree = false
|
||||||
|
|
||||||
|
fun disown() {
|
||||||
|
isCurrentlyFree = true
|
||||||
|
value = None
|
||||||
|
type = ValueStoreType.ReuseReady
|
||||||
|
ValueStoreCache.put(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun adopt(value: Any, type: ValueStoreType) {
|
||||||
|
if (!isCurrentlyFree) {
|
||||||
|
throw RuntimeException("Attempted to adopt a ValueStore that is not free.")
|
||||||
|
}
|
||||||
|
isCurrentlyFree = false
|
||||||
|
this.value = value
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String = "${type.name}: $value"
|
override fun toString(): String = "${type.name}: $value"
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package gay.pizza.pork.evaluator
|
||||||
|
|
||||||
|
object ValueStoreCache {
|
||||||
|
private val cache = mutableListOf<ValueStore>()
|
||||||
|
|
||||||
|
fun obtain(value: Any, type: ValueStoreType): ValueStore {
|
||||||
|
val cached = cache.removeFirstOrNull()
|
||||||
|
if (cached != null) {
|
||||||
|
cached.adopt(value, type)
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
return ValueStore(value, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun put(store: ValueStore) {
|
||||||
|
cache.add(store)
|
||||||
|
}
|
||||||
|
}
|
@ -2,5 +2,6 @@ package gay.pizza.pork.evaluator
|
|||||||
|
|
||||||
enum class ValueStoreType {
|
enum class ValueStoreType {
|
||||||
Let,
|
Let,
|
||||||
Var
|
Var,
|
||||||
|
ReuseReady
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import local SDL2
|
import local SDL2
|
||||||
import java java.util.List
|
|
||||||
import java java.util.ArrayList
|
|
||||||
import java java.util.Collections
|
|
||||||
|
|
||||||
let cellSize = 16
|
let cellSize = 16
|
||||||
let gridWidth = 64
|
let gridWidth = 64
|
||||||
@ -59,8 +56,7 @@ func drawCells(renderer, cells, swap) {
|
|||||||
|
|
||||||
func createCellGrid() {
|
func createCellGrid() {
|
||||||
let numCells = gridWidth * gridHeight
|
let numCells = gridWidth * gridHeight
|
||||||
let init = java_util_Collections_nCopies(numCells, 0)
|
listInitWith(numCells, 0)
|
||||||
java_util_ArrayList_new_collection(init)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCell(cells, swap, x, y) {
|
func getCell(cells, swap, x, y) {
|
||||||
@ -77,8 +73,8 @@ func setCell(cells, swap, x, y, state) {
|
|||||||
let mask = if swap { 2 } else { 1 }
|
let mask = if swap { 2 } else { 1 }
|
||||||
let idx = x + y * gridWidth
|
let idx = x + y * gridWidth
|
||||||
let value = cells[idx]
|
let value = cells[idx]
|
||||||
if state { java_util_ArrayList_set(cells, idx, value | mask) }
|
if state { listSet(cells, idx, value | mask) }
|
||||||
else { java_util_ArrayList_set(cells, idx, value & (~mask)) }
|
else { listSet(cells, idx, value & (~mask)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +152,7 @@ export func main() {
|
|||||||
drawGrid(rend)
|
drawGrid(rend)
|
||||||
drawCells(rend, cells, page)
|
drawCells(rend, cells, page)
|
||||||
|
|
||||||
if (modifiers & KMOD_LSHIFT) == KMOD_LSHIFT {
|
if (modifiers & KMOD_LSHIFT) != KMOD_LSHIFT {
|
||||||
page = not page
|
page = not page
|
||||||
gameOfLife(cells, page)
|
gameOfLife(cells, page)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class JavaNativeProvider : NativeProvider {
|
|||||||
returnTypeClass,
|
returnTypeClass,
|
||||||
parameterClasses
|
parameterClasses
|
||||||
)
|
)
|
||||||
return CallableFunction { functionArguments -> handle.invokeWithArguments(functionArguments.values) ?: None }
|
return CallableFunction { functionArguments, _ -> handle.invokeWithArguments(functionArguments) ?: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lookupClass(name: String): Class<*> = when (name) {
|
private fun lookupClass(name: String): Class<*> = when (name) {
|
||||||
|
@ -13,17 +13,17 @@ class JnaNativeProvider : NativeProvider {
|
|||||||
val library = NativeLibrary.getInstance(functionDefinition.library)
|
val library = NativeLibrary.getInstance(functionDefinition.library)
|
||||||
val function = library.getFunction(functionDefinition.function)
|
val function = library.getFunction(functionDefinition.function)
|
||||||
?: throw RuntimeException("Failed to find function ${functionDefinition.function} in library ${functionDefinition.library}")
|
?: throw RuntimeException("Failed to find function ${functionDefinition.function} in library ${functionDefinition.library}")
|
||||||
return CallableFunction { functionArgs ->
|
return CallableFunction { functionArgs, _ ->
|
||||||
val ffiArgs = mutableListOf<Any?>()
|
val ffiArgs = mutableListOf<Any?>()
|
||||||
for ((index, spec) in arguments.withIndex()) {
|
for ((index, spec) in arguments.withIndex()) {
|
||||||
val ffiType = functionDefinition.parameters[index]
|
val ffiType = functionDefinition.parameters[index]
|
||||||
if (spec.multiple) {
|
if (spec.multiple) {
|
||||||
val variableArguments = functionArgs.values
|
val variableArguments = functionArgs
|
||||||
.subList(index, functionArgs.values.size)
|
.subList(index, functionArgs.size)
|
||||||
ffiArgs.addAll(variableArguments)
|
ffiArgs.addAll(variableArguments)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
val converted = convert(ffiType, functionArgs.values[index])
|
val converted = convert(ffiType, functionArgs[index])
|
||||||
ffiArgs.add(converted)
|
ffiArgs.add(converted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,6 @@ abstract class Tool {
|
|||||||
addNativeProvider("ffi", JnaNativeProvider())
|
addNativeProvider("ffi", JnaNativeProvider())
|
||||||
addNativeProvider("java", JavaNativeProvider())
|
addNativeProvider("java", JavaNativeProvider())
|
||||||
})
|
})
|
||||||
main.call(Arguments(emptyList()))
|
main.call(emptyList(), CallStack())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,5 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
val path = PlatformFsProvider.resolve(args[0])
|
val path = PlatformFsProvider.resolve(args[0])
|
||||||
val tool = FileTool(path)
|
val tool = FileTool(path)
|
||||||
val scope = Scope()
|
tool.run(Scope.root())
|
||||||
tool.run(scope)
|
|
||||||
}
|
}
|
||||||
|
@ -3,3 +3,9 @@ export func print(values...)
|
|||||||
|
|
||||||
export func println(values...)
|
export func println(values...)
|
||||||
native internal "println"
|
native internal "println"
|
||||||
|
|
||||||
|
export func listSet(list, index, value)
|
||||||
|
native internal "listSet"
|
||||||
|
|
||||||
|
export func listInitWith(size, value)
|
||||||
|
native internal "listInitWith"
|
||||||
|
@ -19,7 +19,7 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
|||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val tool = FileTool(PlatformFsProvider.resolve(path))
|
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||||
val scope = Scope()
|
val scope = Scope.root()
|
||||||
val main = tool.loadMainFunction(scope, setupEvaluator = {
|
val main = tool.loadMainFunction(scope, setupEvaluator = {
|
||||||
addNativeProvider("internal", InternalNativeProvider(quiet = quiet))
|
addNativeProvider("internal", InternalNativeProvider(quiet = quiet))
|
||||||
addNativeProvider("ffi", JnaNativeProvider())
|
addNativeProvider("ffi", JnaNativeProvider())
|
||||||
@ -35,7 +35,7 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybeLoopAndMeasure(loop, measure) {
|
maybeLoopAndMeasure(loop, measure) {
|
||||||
main.call(Arguments(emptyList()))
|
main.call(emptyList(), CallStack())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user