Get CLOSUREC working

This commit is contained in:
Reid D. 'arrdem' McKenzie 2022-06-01 00:09:59 -06:00
parent 3debddf0b2
commit af65fbb6f6
4 changed files with 44 additions and 5 deletions

View file

@ -11,12 +11,13 @@ def main():
vm = Interpreter(BOOTSTRAP) vm = Interpreter(BOOTSTRAP)
ret = vm.run( ret = vm.run(
[ [
Opcode.FUNREF(XOR2), Opcode.FUNREF(XOR3),
Opcode.CLOSUREF(1), Opcode.CLOSUREF(1),
Opcode.CLOSUREC(1),
Opcode.CALLC(1), Opcode.CALLC(1),
Opcode.RETURN(1), Opcode.RETURN(1),
], ],
stack = [True, False] stack = [True, True, False]
) )
print(ret) print(ret)

View file

@ -11,11 +11,12 @@ context (a virtual machine) which DOES have an easily introspected and serialize
import sys import sys
assert sys.version_info > (3, 10, 0), "`match` support is required" assert sys.version_info > (3, 10, 0), "`match` support is required"
from copy import deepcopy from copy import deepcopy
from .isa import FunctionRef, Opcode, Closure from .isa import Closure, FunctionRef, Opcode
def rotate(l): def rotate(l):
@ -87,8 +88,9 @@ class Interpreter(object):
stack = Stackframe(stack=stack) stack = Stackframe(stack=stack)
mod = self.bootstrap.copy() mod = self.bootstrap.copy()
mod.define_function(";<entry>;;", opcodes) stack.ip = mod.functions[mod.define_function(";<main>;;", opcodes)]
stack.ip = mod.functions[";<entry>;;"]
print(mod)
def _error(msg=None): def _error(msg=None):
# Note this is pretty expensive because we have to snapshot the stack BEFORE we do anything # Note this is pretty expensive because we have to snapshot the stack BEFORE we do anything
@ -211,6 +213,22 @@ class Interpreter(object):
stack.drop(n) stack.drop(n)
stack.push(c) stack.push(c)
case Opcode.CLOSUREC(n):
c = stack.pop()
if not isinstance(c, Closure):
_error("CLOSUREC requires a closure at top of stack")
if n + len(c.frag) > len(c.funref.args):
_error("CLOSUREC target violation; too many parameters provided")
if n > len(stack):
_error("Stack size violation")
c = Closure(
c.funref,
stack.stack[:n] + c.frag
)
stack.drop(n)
stack.push(c)
case Opcode.CALLC(n): case Opcode.CALLC(n):
c = stack.pop() c = stack.pop()
if not isinstance(c, Closure): if not isinstance(c, Closure):

View file

@ -129,6 +129,7 @@ class Opcode:
Further close over the closure at the top of the stack. Further close over the closure at the top of the stack.
This may produce nullary closures. This may produce nullary closures.
""" """
nargs: int = 0
class CALLC(t.NamedTuple): class CALLC(t.NamedTuple):
"""(`CLOSURE<... A to ... B>`, ... A) -> (... B) """(`CLOSURE<... A to ... B>`, ... A) -> (... B)

View file

@ -84,3 +84,22 @@ def test_callc(vm, stack, ret):
Opcode.CALLC(1), Opcode.CALLC(1),
Opcode.RETURN(1), Opcode.RETURN(1),
], stack = stack) == ret ], stack = stack) == ret
@pytest.mark.parametrize("stack,ret", [
[[False, False, False], [False]],
[[True, False, False], [True]],
[[False, True, False], [True]],
[[True, True, False], [True]],
[[True, True, True], [False]],
[[False, True, True], [True]],
[[False, False, True], [True]],
])
def test_closurec(vm, stack, ret):
assert vm.run([
Opcode.FUNREF(XOR3),
Opcode.CLOSUREF(1),
Opcode.CLOSUREC(1),
Opcode.CALLC(1),
Opcode.RETURN(1),
], stack = stack) == ret