Get CLOSUREC working
This commit is contained in:
parent
3debddf0b2
commit
af65fbb6f6
4 changed files with 44 additions and 5 deletions
|
@ -11,12 +11,13 @@ def main():
|
|||
vm = Interpreter(BOOTSTRAP)
|
||||
ret = vm.run(
|
||||
[
|
||||
Opcode.FUNREF(XOR2),
|
||||
Opcode.FUNREF(XOR3),
|
||||
Opcode.CLOSUREF(1),
|
||||
Opcode.CLOSUREC(1),
|
||||
Opcode.CALLC(1),
|
||||
Opcode.RETURN(1),
|
||||
],
|
||||
stack = [True, False]
|
||||
stack = [True, True, False]
|
||||
)
|
||||
print(ret)
|
||||
|
||||
|
|
|
@ -11,11 +11,12 @@ context (a virtual machine) which DOES have an easily introspected and serialize
|
|||
|
||||
import sys
|
||||
|
||||
|
||||
assert sys.version_info > (3, 10, 0), "`match` support is required"
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from .isa import FunctionRef, Opcode, Closure
|
||||
from .isa import Closure, FunctionRef, Opcode
|
||||
|
||||
|
||||
def rotate(l):
|
||||
|
@ -87,8 +88,9 @@ class Interpreter(object):
|
|||
|
||||
stack = Stackframe(stack=stack)
|
||||
mod = self.bootstrap.copy()
|
||||
mod.define_function(";<entry>;;", opcodes)
|
||||
stack.ip = mod.functions[";<entry>;;"]
|
||||
stack.ip = mod.functions[mod.define_function(";<main>;;", opcodes)]
|
||||
|
||||
print(mod)
|
||||
|
||||
def _error(msg=None):
|
||||
# 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.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):
|
||||
c = stack.pop()
|
||||
if not isinstance(c, Closure):
|
||||
|
|
|
@ -129,6 +129,7 @@ class Opcode:
|
|||
Further close over the closure at the top of the stack.
|
||||
This may produce nullary closures.
|
||||
"""
|
||||
nargs: int = 0
|
||||
|
||||
class CALLC(t.NamedTuple):
|
||||
"""(`CLOSURE<... A to ... B>`, ... A) -> (... B)
|
||||
|
|
|
@ -84,3 +84,22 @@ def test_callc(vm, stack, ret):
|
|||
Opcode.CALLC(1),
|
||||
Opcode.RETURN(1),
|
||||
], 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
|
||||
|
|
Loading…
Reference in a new issue