From 0a2d029c5c24c517b983bd3ece7846f551f769b6 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Tue, 21 Nov 2023 04:28:46 -0800 Subject: [PATCH] language: introduce the requirement to use return to return a value from a function --- README.md | 2 +- ast/src/main/ast/pork.yml | 5 ++++ ast/src/main/graph/types.dot | 3 ++ .../gay/pizza/pork/ast/gen/NodeCoalescer.kt | 3 ++ .../gay/pizza/pork/ast/gen/NodeParser.kt | 2 ++ .../pork/ast/gen/NodeParserExtensions.kt | 1 + .../kotlin/gay/pizza/pork/ast/gen/NodeType.kt | 1 + .../gay/pizza/pork/ast/gen/NodeVisitor.kt | 2 ++ .../pork/ast/gen/NodeVisitorExtensions.kt | 1 + .../kotlin/gay/pizza/pork/ast/gen/Return.kt | 28 +++++++++++++++++++ .../main/kotlin/gay/pizza/pork/bytecode/Op.kt | 10 ++++++- .../gay/pizza/pork/compiler/StubOpEmitter.kt | 6 ++++ .../gay/pizza/pork/evaluator/BlockFunction.kt | 2 +- .../pizza/pork/evaluator/EvaluationVisitor.kt | 15 ++++++---- .../pizza/pork/evaluator/FunctionContext.kt | 2 +- .../gay/pizza/pork/evaluator/ReturnValue.kt | 3 ++ examples/fib.pork | 4 +-- examples/gameoflife/SDL2.pork | 4 +-- examples/gameoflife/gameoflife.pork | 8 +++--- examples/numbers.pork | 1 - .../scope/ExternalSymbolUsageAnalyzer.kt | 4 +++ .../kotlin/gay/pizza/pork/parser/Parser.kt | 5 ++++ .../kotlin/gay/pizza/pork/parser/Printer.kt | 5 ++++ .../gay/pizza/pork/tokenizer/TokenType.kt | 1 + .../gay/pizza/pork/tool/CompileCommand.kt | 2 +- .../gay/pizza/pork/vm/VirtualMachine.kt | 2 ++ .../gay/pizza/pork/vm/ops/NoneOpHandler.kt | 12 ++++++++ 27 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 ast/src/main/kotlin/gay/pizza/pork/ast/gen/Return.kt create mode 100644 evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ReturnValue.kt create mode 100644 vm/src/main/kotlin/gay/pizza/pork/vm/ops/NoneOpHandler.kt diff --git a/README.md b/README.md index 9734c0a..7181582 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A work-in-progress programming language. ```pork /* fibonacci sequence */ func fib(n) { - if n < 2 { + return if n < 2 { n } else { fib(n - 1) + fib(n - 2) diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 5adb4e8..8ff561b 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -300,6 +300,11 @@ types: Continue: parent: Expression values: [] + Return: + parent: Expression + values: + - name: value + type: Expression NoneLiteral: parent: Expression values: [] diff --git a/ast/src/main/graph/types.dot b/ast/src/main/graph/types.dot index 397001e..03312f8 100644 --- a/ast/src/main/graph/types.dot +++ b/ast/src/main/graph/types.dot @@ -36,6 +36,7 @@ digraph A { type_ForIn [shape=box,label="ForIn"] type_Break [shape=box,label="Break"] type_Continue [shape=box,label="Continue"] + type_Return [shape=box,label="Return"] type_NoneLiteral [shape=box,label="NoneLiteral"] type_NativeFunctionDescriptor [shape=box,label="NativeFunctionDescriptor"] type_IndexedBy [shape=box,label="IndexedBy"] @@ -69,6 +70,7 @@ digraph A { type_Expression -> type_ForIn type_Expression -> type_Break type_Expression -> type_Continue + type_Expression -> type_Return type_Expression -> type_NoneLiteral type_Expression -> type_IndexedBy type_Definition -> type_FunctionDefinition @@ -116,6 +118,7 @@ digraph A { type_ForIn -> type_ForInItem [style=dotted] type_ForIn -> type_Expression [style=dotted] type_ForIn -> type_Block [style=dotted] + type_Return -> type_Expression [style=dotted] type_NativeFunctionDescriptor -> type_Symbol [style=dotted] type_NativeFunctionDescriptor -> type_StringLiteral [style=dotted] type_IndexedBy -> type_Expression [style=dotted] diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt index 19c0d62..f172721 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeCoalescer.kt @@ -77,6 +77,9 @@ class NodeCoalescer(val followChildren: Boolean = true, val handler: (Node) -> U override fun visitPrefixOperation(node: PrefixOperation): Unit = handle(node) + override fun visitReturn(node: Return): Unit = + handle(node) + override fun visitSetAssignment(node: SetAssignment): Unit = handle(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt index 7118477..88cc60d 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParser.kt @@ -58,6 +58,8 @@ interface NodeParser { fun parsePrefixOperation(): PrefixOperation + fun parseReturn(): Return + fun parseSetAssignment(): SetAssignment fun parseStringLiteral(): StringLiteral diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt index 4f637b7..40bf2a1 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeParserExtensions.kt @@ -35,6 +35,7 @@ fun NodeParser.parse(type: NodeType): Node = NodeType.ForIn -> parseForIn() NodeType.Break -> parseBreak() NodeType.Continue -> parseContinue() + NodeType.Return -> parseReturn() NodeType.NoneLiteral -> parseNoneLiteral() NodeType.NativeFunctionDescriptor -> parseNativeFunctionDescriptor() NodeType.IndexedBy -> parseIndexedBy() diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt index 5222510..157c785 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeType.kt @@ -31,6 +31,7 @@ enum class NodeType(val parent: NodeType? = null) { NoneLiteral(Expression), Parentheses(Expression), PrefixOperation(Expression), + Return(Expression), SetAssignment(Expression), StringLiteral(Expression), SuffixOperation(Expression), diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt index 5155b62..caf5ef9 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitor.kt @@ -52,6 +52,8 @@ interface NodeVisitor { fun visitPrefixOperation(node: PrefixOperation): T + fun visitReturn(node: Return): T + fun visitSetAssignment(node: SetAssignment): T fun visitStringLiteral(node: StringLiteral): T diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt index 1e12882..4e98113 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/NodeVisitorExtensions.kt @@ -32,6 +32,7 @@ fun NodeVisitor.visit(node: Node): T = is ForIn -> visitForIn(node) is Break -> visitBreak(node) is Continue -> visitContinue(node) + is Return -> visitReturn(node) is NoneLiteral -> visitNoneLiteral(node) is NativeFunctionDescriptor -> visitNativeFunctionDescriptor(node) is IndexedBy -> visitIndexedBy(node) diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/gen/Return.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/Return.kt new file mode 100644 index 0000000..8ed129e --- /dev/null +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/gen/Return.kt @@ -0,0 +1,28 @@ +// GENERATED CODE FROM PORK AST CODEGEN +package gay.pizza.pork.ast.gen + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("return") +class Return(val value: Expression) : Expression() { + override val type: NodeType = NodeType.Return + + override fun visitChildren(visitor: NodeVisitor): List = + visitor.visitNodes(value) + + override fun visit(visitor: NodeVisitor): T = + visitor.visitReturn(this) + + override fun equals(other: Any?): Boolean { + if (other !is Return) return false + return other.value == value + } + + override fun hashCode(): Int { + var result = value.hashCode() + result = 31 * result + type.hashCode() + return result + } +} diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt index 1779659..d2b07fb 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Op.kt @@ -3,4 +3,12 @@ package gay.pizza.pork.bytecode import kotlinx.serialization.Serializable @Serializable -data class Op(val code: Opcode, val args: List) +class Op(val code: Opcode, val args: List) { + override fun toString(): String = buildString { + append(code.name) + if (args.isNotEmpty()) { + append(" ") + append(args.joinToString(" ")) + } + } +} diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt index 78279b5..b9f5adc 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/StubOpEmitter.kt @@ -30,6 +30,7 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func fun exit() { code.localState.popScope() + code.emit(Opcode.None) code.emit(Opcode.Return) } @@ -211,6 +212,11 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func } } + override fun visitReturn(node: Return) { + node.value.visit(this) + code.emit(Opcode.Return) + } + override fun visitSetAssignment(node: SetAssignment) { val stubVarOrCall = code.localState.resolve(node.symbol) if (stubVarOrCall.stubVar == null) { 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 efb730b..6db1d10 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 abstract class BlockFunction { - abstract fun call(): Any + abstract fun call(isFunctionContext: Boolean): Any } 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 2e55783..c9699d9 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -28,7 +28,7 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito scoped(reuseScope, node = node) { currentScope.define(node.item.symbol.id, item ?: None) - result = blockFunction.call() + result = blockFunction.call(false) } } catch (_: BreakMarker) { break @@ -90,7 +90,7 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito if (reuseScope == null) { reuseScope = currentScope.fork(name = "While") } - scoped(reuseScope, node = node) { result = blockFunction.call() } + scoped(reuseScope, node = node) { result = blockFunction.call(false) } } catch (_: BreakMarker) { break } catch (_: ContinueMarker) { @@ -122,6 +122,8 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito } } + override fun visitReturn(node: Return): Any = ReturnValue(node.value.visit(this)) + private fun unaryNumericOperation(node: PrefixOperation, value: Number) = when (value) { is Double -> { unaryNumericOperation( @@ -186,10 +188,10 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito val condition = node.condition.visit(this) return if (condition == true) { val blockFunction = node.thenBlock.visit(this) as BlockFunction - scoped(node = node) { blockFunction.call() } + scoped(node = node) { blockFunction.call(false) } } else if (node.elseBlock != null) { val blockFunction = node.elseBlock!!.visit(this) as BlockFunction - scoped(node = node) { blockFunction.call() } + scoped(node = node) { blockFunction.call(false) } } else None } @@ -370,10 +372,13 @@ class EvaluationVisitor(root: Scope, val stack: CallStack) : FunctionLevelVisito override fun visitBlock(node: Block): BlockFunction { val visitor = this return object : BlockFunction() { - override fun call(): Any { + override fun call(isFunctionContext: Boolean): Any { var value: Any? = null for (expression in node.expressions) { value = expression.visit(visitor) + if (isFunctionContext && value is ReturnValue) { + return value.value + } } return value ?: None } 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 4474edd..f68bd55 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/FunctionContext.kt @@ -40,7 +40,7 @@ class FunctionContext(val slabContext: SlabContext, val node: FunctionDefinition stack.push(this) val blockFunction = visitor.visitBlock(node.block!!) try { - return blockFunction.call() + return blockFunction.call(true) } catch (e: PorkError) { throw e } catch (e: Exception) { diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ReturnValue.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ReturnValue.kt new file mode 100644 index 0000000..d78113d --- /dev/null +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/ReturnValue.kt @@ -0,0 +1,3 @@ +package gay.pizza.pork.evaluator + +class ReturnValue(val value: Any) diff --git a/examples/fib.pork b/examples/fib.pork index 01c9516..f093f48 100644 --- a/examples/fib.pork +++ b/examples/fib.pork @@ -1,6 +1,6 @@ /* fibonacci sequence */ func fib(n) { - if n < 2 { + return if n < 2 { n } else { fib(n - 1) + fib(n - 2) @@ -8,6 +8,6 @@ func fib(n) { } export func main() { - let result = fib(30) + let result = fib(20) println(result) } diff --git a/examples/gameoflife/SDL2.pork b/examples/gameoflife/SDL2.pork index 1161d0d..9581b0b 100644 --- a/examples/gameoflife/SDL2.pork +++ b/examples/gameoflife/SDL2.pork @@ -15,11 +15,11 @@ export func SDL_Quit() export let SDL_WINDOW_ALLOW_HIGHDPI = 8192 export let SDL_WINDOWPOS_UNDEFINED_MASK = 536805376 -export func SDL_WINDOWPOS_UNDEFINED_DISPLAY(x) { SDL_WINDOWPOS_UNDEFINED_MASK | x } +export func SDL_WINDOWPOS_UNDEFINED_DISPLAY(x) { return SDL_WINDOWPOS_UNDEFINED_MASK | x } export let SDL_WINDOWPOS_UNDEFINED = SDL_WINDOWPOS_UNDEFINED_DISPLAY(0) export let SDL_WINDOWPOS_CENTERED_MASK = 805240832 -export func SDL_WINDOWPOS_CENTERED_DISPLAY(x) { SDL_WINDOWPOS_CENTERED_MASK | x } +export func SDL_WINDOWPOS_CENTERED_DISPLAY(x) { return SDL_WINDOWPOS_CENTERED_MASK | x } export let SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED_DISPLAY(0) export func SDL_CreateWindow(title, x, y, w, h, flags) diff --git a/examples/gameoflife/gameoflife.pork b/examples/gameoflife/gameoflife.pork index 5017863..8e91dd4 100644 --- a/examples/gameoflife/gameoflife.pork +++ b/examples/gameoflife/gameoflife.pork @@ -56,15 +56,15 @@ func drawCells(renderer, cells, swap) { func createCellGrid() { let numCells = gridWidth * gridHeight - listInitWith(numCells, 0) + return listInitWith(numCells, 0) } func getCell(cells, swap, x, y) { if (x >= 0) and (y >= 0) and (x < gridWidth) and (y < gridHeight) { let mask = if swap { 2 } else { 1 } - (cells[x + y * gridWidth] & mask) != 0 + return (cells[x + y * gridWidth] & mask) != 0 } else { - false + return false } } @@ -88,7 +88,7 @@ func countNeighbours(cells, swap, x, y) { if getCell(cells, swap, x - 1, y + 1) { count++ } if getCell(cells, swap, x - 1, y) { count++ } if getCell(cells, swap, x - 1, y - 1) { count++ } - count + return count } func gameOfLife(cells, swap) { diff --git a/examples/numbers.pork b/examples/numbers.pork index 1ed2e9a..19f0834 100644 --- a/examples/numbers.pork +++ b/examples/numbers.pork @@ -1,5 +1,4 @@ export func main() { let pi = 3.141592653589793 println(pi) - } diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt index 7f4ae28..9a1d3bf 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt @@ -99,6 +99,10 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { node.visitChildren(this) } + override fun visitReturn(node: Return) { + node.visitChildren(this) + } + override fun visitSetAssignment(node: SetAssignment) { node.visitChildren(this) } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index 0a800bc..d7bb4b5 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -38,6 +38,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : TokenType.Break -> parseBreak() TokenType.Continue -> parseContinue() TokenType.None -> parseNoneLiteral() + TokenType.Return -> parseReturn() else -> { throw ParseError( @@ -332,6 +333,10 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : PrefixOperation(ParserHelpers.convertPrefixOperator(it), parseExpression()) } + override fun parseReturn(): Return = expect(NodeType.Return, TokenType.Return) { + Return(parseExpression()) + } + override fun parseSetAssignment(): SetAssignment = produce(NodeType.SetAssignment) { val symbol = parseSymbol() expect(TokenType.Equals) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt index 1dfaec6..a8b239c 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Printer.kt @@ -154,6 +154,11 @@ class Printer(buffer: StringBuilder) : NodeVisitor { visit(node.expression) } + override fun visitReturn(node: Return) { + append("return ") + visit(node.value) + } + override fun visitSuffixOperation(node: SuffixOperation) { visit(node.reference) append(node.op.token) diff --git a/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt b/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt index 32bd769..db70ebb 100644 --- a/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt +++ b/tokenizer/src/main/kotlin/gay/pizza/pork/tokenizer/TokenType.kt @@ -62,6 +62,7 @@ enum class TokenType(vararg val properties: TokenTypeProperty) { In(ManyChars("in"), KeywordFamily), Continue(ManyChars("continue"), KeywordFamily), Break(ManyChars("break"), KeywordFamily), + Return(ManyChars("return"), KeywordFamily), Import(AnyOf("import", "impork", "porkload"), KeywordFamily), Export(ManyChars("export"), KeywordFamily), Func(ManyChars("func"), KeywordFamily), diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt index af9725d..ee91f25 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -29,7 +29,7 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c if (annotations.isNotEmpty()) { annotation = " ; ${annotations.joinToString(", ") { it.text}}" } - println(" ${symbol.offset + index.toUInt()} ${op.code.name} ${op.args.joinToString(" ")}${annotation}") + println(" ${symbol.offset + index.toUInt()} ${op}${annotation}") } } val vm = VirtualMachine(compiledWorld) diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt index d762c64..72ff202 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachine.kt @@ -12,6 +12,8 @@ class VirtualMachine(world: CompiledWorld) : ExecutionContext { TrueOpHandler, FalseOpHandler, + NoneOpHandler, + ListMakeOpHandler, ListSizeOpHandler, diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NoneOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NoneOpHandler.kt new file mode 100644 index 0000000..0f1748d --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NoneOpHandler.kt @@ -0,0 +1,12 @@ +package gay.pizza.pork.vm.ops + +import gay.pizza.pork.bytecode.Op +import gay.pizza.pork.bytecode.Opcode +import gay.pizza.pork.vm.InternalMachine +import gay.pizza.pork.vm.OpHandler + +object NoneOpHandler : OpHandler(Opcode.None) { + override fun handle(machine: InternalMachine, op: Op) { + machine.push(Unit) + } +}