From 4758e926765d90f65402f7b0989ae9ebdc7aa412 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Thu, 21 Sep 2023 17:21:53 -0700 Subject: [PATCH] evaluator: significant performance enhancements --- .../gay/pizza/pork/evaluator/Arguments.kt | 2 +- .../gay/pizza/pork/evaluator/BlockFunction.kt | 4 +- .../gay/pizza/pork/evaluator/CallStack.kt | 20 ++++ .../pizza/pork/evaluator/CallableFunction.kt | 2 +- .../pork/evaluator/CompilationUnitContext.kt | 4 +- .../pizza/pork/evaluator/EvaluationVisitor.kt | 52 +++++++--- .../pizza/pork/evaluator/FunctionContext.kt | 27 ++++-- .../pork/evaluator/InternalNativeProvider.kt | 27 ++++-- .../gay/pizza/pork/evaluator/PorkError.kt | 3 + .../kotlin/gay/pizza/pork/evaluator/Scope.kt | 94 +++++++++++++++---- .../gay/pizza/pork/evaluator/ScopeCache.kt | 18 ++++ .../gay/pizza/pork/evaluator/ValueStore.kt | 20 +++- .../pizza/pork/evaluator/ValueStoreCache.kt | 18 ++++ .../pizza/pork/evaluator/ValueStoreType.kt | 3 +- examples/gameoflife/gameoflife.pork | 12 +-- .../gay/pizza/pork/ffi/JavaNativeProvider.kt | 2 +- .../gay/pizza/pork/ffi/JnaNativeProvider.kt | 8 +- .../kotlin/gay/pizza/pork/minimal/Tool.kt | 2 +- .../kotlin/gay/pizza/pork/minimal/main.kt | 3 +- stdlib/src/main/pork/lang/prelude.pork | 6 ++ .../kotlin/gay/pizza/pork/tool/RunCommand.kt | 4 +- 21 files changed, 260 insertions(+), 71 deletions(-) create mode 100644 evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallStack.kt create mode 100644 evaluator/src/main/kotlin/gay/pizza/pork/evaluator/PorkError.kt create mode 100644 evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ScopeCache.kt create mode 100644 evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreCache.kt diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt index 000dd75..b4f87b0 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Arguments.kt @@ -1,3 +1,3 @@ package gay.pizza.pork.evaluator -class Arguments(val values: List) +typealias ArgumentList = List diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/BlockFunction.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/BlockFunction.kt index d3059ff..efb730b 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/BlockFunction.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/BlockFunction.kt @@ -1,5 +1,5 @@ package gay.pizza.pork.evaluator -fun interface BlockFunction { - fun call(): Any +abstract class BlockFunction { + abstract fun call(): Any } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallStack.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallStack.kt new file mode 100644 index 0000000..d961eb3 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallStack.kt @@ -0,0 +1,20 @@ +package gay.pizza.pork.evaluator + +class CallStack(val functionStack: MutableList = 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()) +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt index 8168a5b..aed6bdd 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CallableFunction.kt @@ -1,5 +1,5 @@ package gay.pizza.pork.evaluator fun interface CallableFunction { - fun call(arguments: Arguments): Any + fun call(arguments: ArgumentList, stack: CallStack): Any } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt index 2f13558..4f11883 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/CompilationUnitContext.kt @@ -7,7 +7,7 @@ class CompilationUnitContext( val compilationUnit: CompilationUnit, val evaluator: Evaluator, rootScope: Scope, - name: String = "unknown" + val name: String = "unknown" ) { val internalScope = rootScope.fork("internal $name") val externalScope = rootScope.fork("external $name") @@ -40,7 +40,7 @@ class CompilationUnitContext( private fun definitionValue(definition: Definition): Any = when (definition) { is FunctionDefinition -> FunctionContext(this, definition) is LetDefinition -> { - EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}")) + EvaluationVisitor(internalScope.fork("let ${definition.symbol.id}"), CallStack()) .visit(definition.value) } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index f93c2c4..7ce0f1b 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -3,7 +3,8 @@ package gay.pizza.pork.evaluator import gay.pizza.pork.ast.* import kotlin.math.abs -class EvaluationVisitor(root: Scope) : NodeVisitor { +@Suppress("JavaIoSerializableObjectMustHaveReadResolve") +class EvaluationVisitor(root: Scope, val stack: CallStack) : NodeVisitor { private var currentScope: Scope = root override fun visitIntegerLiteral(node: IntegerLiteral): Any = node.value @@ -16,9 +17,15 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { throw RuntimeException("Unable to iterate on value that is not a iterable.") } + var reuseScope: Scope? = null + for (item in value) { try { - scoped { + if (reuseScope == null) { + reuseScope = currentScope.fork(name = "ForIn") + } + + scoped(reuseScope, node = node) { currentScope.define(node.symbol.id, item ?: None) result = blockFunction.call() } @@ -28,6 +35,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { continue } } + reuseScope?.disown() return result ?: None } @@ -46,7 +54,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { override fun visitFunctionCall(node: FunctionCall): Any { val arguments = node.arguments.map { it.visit(this) } 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 { @@ -71,6 +79,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { override fun visitWhile(node: While): Any { val blockFunction = node.block.visit(this) as BlockFunction var result: Any? = null + var reuseScope: Scope? = null while (true) { val value = node.condition.visit(this) if (value !is Boolean) { @@ -78,13 +87,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { } if (!value) break try { - scoped { result = blockFunction.call() } + if (reuseScope == null) { + reuseScope = currentScope.fork(name = "While") + } + scoped(reuseScope, node = node) { result = blockFunction.call() } } catch (_: BreakMarker) { break } catch (_: ContinueMarker) { continue } } + reuseScope?.disown() return result ?: None } @@ -173,10 +186,10 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { val condition = node.condition.visit(this) return if (condition == true) { val blockFunction = node.thenBlock.visit(this) as BlockFunction - scoped { blockFunction.call() } + scoped(node = node) { blockFunction.call() } } else if (node.elseBlock != null) { val blockFunction = node.elseBlock!!.visit(this) as BlockFunction - scoped { blockFunction.call() } + scoped(node = node) { blockFunction.call() } } else None } @@ -350,12 +363,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { } } - override fun visitBlock(node: Block): BlockFunction = BlockFunction { - var value: Any? = null - for (expression in node.expressions) { - value = expression.visit(this) + override fun visitBlock(node: Block): BlockFunction { + val visitor = this + return object : BlockFunction() { + 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 { @@ -393,12 +411,18 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { override fun visitContinue(node: Continue): Any = ContinueMarker - private inline fun scoped(block: () -> T): T { - currentScope = currentScope.fork() + private inline fun scoped(reuseScope: Scope? = null, node: Node? = null, block: () -> T): T { + val previousScope = currentScope + currentScope = reuseScope ?: currentScope.fork(name = node?.type?.name) try { return block() } finally { - currentScope = currentScope.leave() + if (reuseScope == null) { + currentScope = currentScope.leave(disown = true) + } else { + reuseScope.markForReuse() + currentScope = previousScope + } } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt index 997f6a3..addaf81 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt @@ -3,6 +3,8 @@ package gay.pizza.pork.evaluator import gay.pizza.pork.ast.FunctionDefinition 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) { null } else { @@ -14,19 +16,19 @@ class FunctionContext(val compilationUnitContext: CompilationUnitContext, val no private val nativeCached by lazy { resolveMaybeNative() } - override fun call(arguments: Arguments): Any { + override fun call(arguments: ArgumentList, stack: CallStack): Any { 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()) { 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) break } 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") } - val visitor = EvaluationVisitor(scope) + val visitor = EvaluationVisitor(scope, stack) + stack.push(this) 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() + } } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt index 9fc2490..309e587 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/InternalNativeProvider.kt @@ -5,22 +5,37 @@ import gay.pizza.pork.ast.ArgumentSpec class InternalNativeProvider(val quiet: Boolean = false) : NativeProvider { private val functions = mutableMapOf( "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): CallableFunction { return functions[definition] ?: throw RuntimeException("Unknown Internal Function: $definition") } - private fun printValues(arguments: Arguments): Any { - if (quiet || arguments.values.isEmpty()) return None - print(arguments.values.joinToString(" ")) + private fun printValues(arguments: ArgumentList, stack: CallStack): Any { + if (quiet || arguments.isEmpty()) return None + print(arguments.joinToString(" ")) return None } - private fun printLine(arguments: Arguments): Any { + private fun printLine(arguments: ArgumentList, stack: CallStack): Any { if (quiet) return None - println(arguments.values.joinToString(" ")) + println(arguments.joinToString(" ")) return None } + + private fun setInList(arguments: ArgumentList, stack: CallStack): Any { + @Suppress("UNCHECKED_CAST") + val list = arguments[0] as MutableList + 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] } + } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/PorkError.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/PorkError.kt new file mode 100644 index 0000000..0e55588 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/PorkError.kt @@ -0,0 +1,3 @@ +package gay.pizza.pork.evaluator + +class PorkError(cause: Exception, stack: CallStack) : RuntimeException(stack.toString(), cause) diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt index b581f25..a76187a 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/Scope.kt @@ -1,19 +1,25 @@ package gay.pizza.pork.evaluator class Scope( - val parent: Scope? = null, - inherits: List = emptyList(), - val name: String? = null + var parent: Scope? = null, + var inherits: List = emptyList(), + var name: String? = null ) { - private val inherited = inherits.toMutableList() + private var isCurrentlyFree = false private val variables = mutableMapOf() fun define(name: String, value: Any, type: ValueStoreType = ValueStoreType.Let) { - val previous = variables.put(name, ValueStore(value, type)) - if (previous != null) { - variables[name] = previous + val existing = variables[name] + if (existing != null) { + if (existing.type == ValueStoreType.ReuseReady) { + existing.type = type + existing.value = value + return + } throw RuntimeException("Variable '${name}' is already defined") } + val store = ValueStoreCache.obtain(value, type) + variables[name] = store } fun set(name: String, value: Any) { @@ -40,13 +46,13 @@ class Scope( val holder = variables[name] if (holder == null) { if (parent != null) { - val parentMaybeFound = parent.valueHolderOrNotFound(name) + val parentMaybeFound = parent!!.valueHolderOrNotFound(name) if (parentMaybeFound !== NotFound.Holder) { return parentMaybeFound } } - for (inherit in inherited) { + for (inherit in inherits) { val inheritMaybeFound = inherit.valueHolderOrNotFound(name) if (inheritMaybeFound !== NotFound.Holder) { return inheritMaybeFound @@ -54,21 +60,29 @@ class Scope( } return NotFound.Holder } + if (holder.type == ValueStoreType.ReuseReady) { + throw RuntimeException("Attempt to reuse ValueStore in the reused state, prior to definition.") + } return holder } fun fork(name: String? = null): Scope = - Scope(this, name = name) + ScopeCache.obtain(this, name = name) internal fun inherit(scope: Scope) { - inherited.add(scope) + val copy = inherits.toMutableList() + copy.add(scope) + inherits = copy } - fun leave(): Scope { - if (parent == null) { - throw RuntimeException("Attempted to leave the root scope!") + fun leave(disown: Boolean = false): Scope { + val currentParent = parent ?: throw RuntimeException("Attempted to leave the root scope!") + + if (disown) { + disown() } - return parent + + return currentParent } fun crawlScopePath( @@ -79,7 +93,7 @@ class Scope( block(key, path) } - for (inherit in inherited) { + for (inherit in inherits) { val mutablePath = path.toMutableList() mutablePath.add("inherit ${inherit.name ?: "unknown"}") inherit.crawlScopePath(mutablePath, block) @@ -87,12 +101,56 @@ class Scope( if (parent != null) { val mutablePath = path.toMutableList() - mutablePath.add("parent ${parent.name ?: "unknown"}") - parent.crawlScopePath(mutablePath, block) + mutablePath.add("parent ${parent?.name ?: "unknown"}") + 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, 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 { val Holder = ValueStore(NotFound, ValueStoreType.Let) } + + val path: String + get() = buildString { + val list = mutableListOf() + 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") + } } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ScopeCache.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ScopeCache.kt new file mode 100644 index 0000000..80e43b4 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ScopeCache.kt @@ -0,0 +1,18 @@ +package gay.pizza.pork.evaluator + +object ScopeCache { + private val cache = mutableListOf() + + fun obtain(parent: Scope? = null, inherits: List = 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) + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt index 6121344..5d437c6 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStore.kt @@ -1,5 +1,23 @@ 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" } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreCache.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreCache.kt new file mode 100644 index 0000000..4e6c0f2 --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreCache.kt @@ -0,0 +1,18 @@ +package gay.pizza.pork.evaluator + +object ValueStoreCache { + private val cache = mutableListOf() + + 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) + } +} diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt index 0db02e6..92e0494 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ValueStoreType.kt @@ -2,5 +2,6 @@ package gay.pizza.pork.evaluator enum class ValueStoreType { Let, - Var + Var, + ReuseReady } diff --git a/examples/gameoflife/gameoflife.pork b/examples/gameoflife/gameoflife.pork index e982000..5017863 100644 --- a/examples/gameoflife/gameoflife.pork +++ b/examples/gameoflife/gameoflife.pork @@ -1,7 +1,4 @@ import local SDL2 -import java java.util.List -import java java.util.ArrayList -import java java.util.Collections let cellSize = 16 let gridWidth = 64 @@ -59,8 +56,7 @@ func drawCells(renderer, cells, swap) { func createCellGrid() { let numCells = gridWidth * gridHeight - let init = java_util_Collections_nCopies(numCells, 0) - java_util_ArrayList_new_collection(init) + listInitWith(numCells, 0) } 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 idx = x + y * gridWidth let value = cells[idx] - if state { java_util_ArrayList_set(cells, idx, value | mask) } - else { java_util_ArrayList_set(cells, idx, value & (~mask)) } + if state { listSet(cells, idx, value | mask) } + else { listSet(cells, idx, value & (~mask)) } } } @@ -156,7 +152,7 @@ export func main() { drawGrid(rend) drawCells(rend, cells, page) - if (modifiers & KMOD_LSHIFT) == KMOD_LSHIFT { + if (modifiers & KMOD_LSHIFT) != KMOD_LSHIFT { page = not page gameOfLife(cells, page) } diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt index 4008e83..f929f71 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JavaNativeProvider.kt @@ -22,7 +22,7 @@ class JavaNativeProvider : NativeProvider { returnTypeClass, parameterClasses ) - return CallableFunction { functionArguments -> handle.invokeWithArguments(functionArguments.values) ?: None } + return CallableFunction { functionArguments, _ -> handle.invokeWithArguments(functionArguments) ?: None } } private fun lookupClass(name: String): Class<*> = when (name) { diff --git a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt index 77382e4..cb3ad17 100644 --- a/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt +++ b/ffi/src/main/kotlin/gay/pizza/pork/ffi/JnaNativeProvider.kt @@ -13,17 +13,17 @@ class JnaNativeProvider : NativeProvider { val library = NativeLibrary.getInstance(functionDefinition.library) val function = library.getFunction(functionDefinition.function) ?: throw RuntimeException("Failed to find function ${functionDefinition.function} in library ${functionDefinition.library}") - return CallableFunction { functionArgs -> + return CallableFunction { functionArgs, _ -> val ffiArgs = mutableListOf() for ((index, spec) in arguments.withIndex()) { val ffiType = functionDefinition.parameters[index] if (spec.multiple) { - val variableArguments = functionArgs.values - .subList(index, functionArgs.values.size) + val variableArguments = functionArgs + .subList(index, functionArgs.size) ffiArgs.addAll(variableArguments) break } else { - val converted = convert(ffiType, functionArgs.values[index]) + val converted = convert(ffiType, functionArgs[index]) ffiArgs.add(converted) } } diff --git a/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt b/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt index e27dce4..f761a8d 100644 --- a/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt +++ b/minimal/src/main/kotlin/gay/pizza/pork/minimal/Tool.kt @@ -58,6 +58,6 @@ abstract class Tool { addNativeProvider("ffi", JnaNativeProvider()) addNativeProvider("java", JavaNativeProvider()) }) - main.call(Arguments(emptyList())) + main.call(emptyList(), CallStack()) } } diff --git a/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt b/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt index 4b1124b..cf4a195 100644 --- a/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt +++ b/minimal/src/main/kotlin/gay/pizza/pork/minimal/main.kt @@ -11,6 +11,5 @@ fun main(args: Array) { } val path = PlatformFsProvider.resolve(args[0]) val tool = FileTool(path) - val scope = Scope() - tool.run(scope) + tool.run(Scope.root()) } diff --git a/stdlib/src/main/pork/lang/prelude.pork b/stdlib/src/main/pork/lang/prelude.pork index 71da5b6..42a96a3 100644 --- a/stdlib/src/main/pork/lang/prelude.pork +++ b/stdlib/src/main/pork/lang/prelude.pork @@ -3,3 +3,9 @@ export func print(values...) export func println(values...) native internal "println" + +export func listSet(list, index, value) + native internal "listSet" + +export func listInitWith(size, value) + native internal "listInitWith" diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt index 49c4554..40979b3 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/RunCommand.kt @@ -19,7 +19,7 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") { override fun run() { val tool = FileTool(PlatformFsProvider.resolve(path)) - val scope = Scope() + val scope = Scope.root() val main = tool.loadMainFunction(scope, setupEvaluator = { addNativeProvider("internal", InternalNativeProvider(quiet = quiet)) addNativeProvider("ffi", JnaNativeProvider()) @@ -35,7 +35,7 @@ class RunCommand : CliktCommand(help = "Run Program", name = "run") { } maybeLoopAndMeasure(loop, measure) { - main.call(Arguments(emptyList())) + main.call(emptyList(), CallStack()) } } }