Renaming variant operations
This commit is contained in:
parent
8e19f22640
commit
99f456e0ee
12 changed files with 98 additions and 83 deletions
|
@ -1,12 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
Import everything out of the Ichor modules.
|
|
||||||
|
|
||||||
FIXME: A real public API here would be great, but somewhat un-pythonic.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ichor.bootstrap import * # noqa
|
|
||||||
from ichor.impl import * # noqa
|
|
||||||
from ichor.isa import * # noqa
|
|
||||||
from ichor.typing import * # noqa
|
|
|
@ -61,8 +61,8 @@ class FuncBuilder(object):
|
||||||
case isa.GOTO(isa.Label(_) as l):
|
case isa.GOTO(isa.Label(_) as l):
|
||||||
assembled.append(isa.GOTO(labels[l]))
|
assembled.append(isa.GOTO(labels[l]))
|
||||||
|
|
||||||
case isa.VTEST(isa.Label(_) as l):
|
case isa.ATEST(isa.Label(_) as l):
|
||||||
assembled.append(isa.VTEST(labels[l]))
|
assembled.append(isa.ATEST(labels[l]))
|
||||||
|
|
||||||
case o:
|
case o:
|
||||||
assembled.append(o)
|
assembled.append(o)
|
||||||
|
@ -84,7 +84,18 @@ class LocalBuilder(FuncBuilder):
|
||||||
self._labels = {}
|
self._labels = {}
|
||||||
|
|
||||||
def _write(self, op):
|
def _write(self, op):
|
||||||
pass
|
super()._write(op)
|
||||||
|
|
||||||
|
match op:
|
||||||
|
case isa.DROP(n):
|
||||||
|
self._stack -= n
|
||||||
|
case isa.DUP(n):
|
||||||
|
self._stack += n
|
||||||
|
case isa.ROT(_):
|
||||||
|
pass
|
||||||
|
case _:
|
||||||
|
self._stack -= getattr(op, 'nargs', 0)
|
||||||
|
self._stack += 1
|
||||||
|
|
||||||
def write_local(self, label: isa.Label):
|
def write_local(self, label: isa.Label):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -25,20 +25,20 @@ NOT1 = BOOTSTRAP.define_function(
|
||||||
isa.TYPEREF(), # <typeref bool> a
|
isa.TYPEREF(), # <typeref bool> a
|
||||||
isa.DUP(),
|
isa.DUP(),
|
||||||
isa.IDENTIFIERC("true"),
|
isa.IDENTIFIERC("true"),
|
||||||
isa.VARIANTREF(), # <variantref true:bool> <typeref bool> a
|
isa.ARMREF(), # <variantref true:bool> <typeref bool> a
|
||||||
isa.DUP(),
|
isa.DUP(),
|
||||||
isa.SLOT(0),
|
isa.SLOT(0),
|
||||||
isa.ROT(2),
|
isa.ROT(2),
|
||||||
isa.VTEST(11),
|
isa.ATEST(11),
|
||||||
|
|
||||||
isa.VARIANT(0),
|
isa.ARM(0),
|
||||||
isa.RETURN(1),
|
isa.RETURN(),
|
||||||
|
|
||||||
isa.DROP(1),
|
isa.DROP(1),
|
||||||
isa.IDENTIFIERC("false"),
|
isa.IDENTIFIERC("false"),
|
||||||
isa.VARIANTREF(),
|
isa.ARMREF(),
|
||||||
isa.VARIANT(0),
|
isa.ARM(0),
|
||||||
isa.RETURN(1),
|
isa.RETURN(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""The Ichor VM implementation.
|
"""The Ichor VM.interpreterementation.
|
||||||
|
|
||||||
The whole point of Shoggoth is that program executions are checkpointable and restartable. This requires that rather than
|
The whole point of Shoggoth is that program executions are checkpointable and restartable. This requires that rather than
|
||||||
using a traditional recursive interpreter which is difficult to snapshot, interpretation in shoggoth occur within a
|
using a traditional recursive interpreter which is difficult to snapshot, interpretation in shoggoth occur within a
|
||||||
|
@ -35,7 +35,7 @@ class InterpreterError(Exception):
|
||||||
|
|
||||||
|
|
||||||
class Interpreter(object):
|
class Interpreter(object):
|
||||||
"""A shit simple instruction pointer based interpreter."""
|
"""A shit .interpretere instruction pointer based interpreter."""
|
||||||
def __init__(self, bootstrap_module: Module):
|
def __init__(self, bootstrap_module: Module):
|
||||||
self.bootstrap = bootstrap_module
|
self.bootstrap = bootstrap_module
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class Interpreter(object):
|
||||||
|
|
||||||
stackframe.push(TypeRef(id.name))
|
stackframe.push(TypeRef(id.name))
|
||||||
|
|
||||||
case isa.VARIANTREF():
|
case isa.ARMREF():
|
||||||
id: Identifier = stackframe.pop()
|
id: Identifier = stackframe.pop()
|
||||||
if not isinstance(id, Identifier):
|
if not isinstance(id, Identifier):
|
||||||
_error("VARIANTREF consumes an identifier and a typeref")
|
_error("VARIANTREF consumes an identifier and a typeref")
|
||||||
|
@ -104,7 +104,7 @@ class Interpreter(object):
|
||||||
|
|
||||||
stackframe.push(VariantRef(t, id.name))
|
stackframe.push(VariantRef(t, id.name))
|
||||||
|
|
||||||
case isa.VARIANT(n):
|
case isa.ARM(n):
|
||||||
armref: VariantRef = stackframe.pop()
|
armref: VariantRef = stackframe.pop()
|
||||||
if not isinstance(armref, VariantRef):
|
if not isinstance(armref, VariantRef):
|
||||||
_error("VARIANT must be given a valid constructor reference")
|
_error("VARIANT must be given a valid constructor reference")
|
||||||
|
@ -122,7 +122,7 @@ class Interpreter(object):
|
||||||
stackframe.drop(n)
|
stackframe.drop(n)
|
||||||
stackframe.push(v)
|
stackframe.push(v)
|
||||||
|
|
||||||
case isa.VTEST(n):
|
case isa.ATEST(n):
|
||||||
armref: VariantRef = stackframe.pop()
|
armref: VariantRef = stackframe.pop()
|
||||||
if not isinstance(armref, VariantRef):
|
if not isinstance(armref, VariantRef):
|
||||||
_error("VTEST must be given a variant reference")
|
_error("VTEST must be given a variant reference")
|
||||||
|
@ -194,7 +194,8 @@ class Interpreter(object):
|
||||||
stackframe = stackframe.call(fun, ip)
|
stackframe = stackframe.call(fun, ip)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case isa.RETURN(n):
|
case isa.RETURN():
|
||||||
|
n = 1 # FIXME: clean this up
|
||||||
if (n > len(stackframe)):
|
if (n > len(stackframe)):
|
||||||
_error("Stack size violation")
|
_error("Stack size violation")
|
||||||
|
|
||||||
|
@ -265,6 +266,10 @@ class Interpreter(object):
|
||||||
stackframe = stackframe.call(fun, ip)
|
stackframe = stackframe.call(fun, ip)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
case isa.BREAK():
|
||||||
|
# FIXME: let users override this / set custom handlers
|
||||||
|
return stackframe._stack
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
raise Exception(f"Unhandled interpreter state {op}")
|
raise Exception(f"Unhandled interpreter state {op}")
|
||||||
|
|
|
@ -20,16 +20,17 @@ class Opcode(ABC):
|
||||||
class GOTO(Opcode):
|
class GOTO(Opcode):
|
||||||
"""() -> ()
|
"""() -> ()
|
||||||
|
|
||||||
Branch to another point within the same bytecode segment. The target MUST be within the same module range as the
|
Branch to another point within the same bytecode segment. The target MUST be
|
||||||
current function. Branching does NOT update the name or module of the current function.
|
within the same module range as the current function. Branching does NOT
|
||||||
|
update the name or module of the current function.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
target: int
|
target: int
|
||||||
|
|
||||||
####################################################################################################
|
################################################################################
|
||||||
# Stack manipulation
|
# Stack manipulation
|
||||||
####################################################################################################
|
################################################################################
|
||||||
# https://wiki.laptop.org/go/Forth_stack_operators
|
# https://wiki.laptop.org/go/Forth_stack_operators
|
||||||
# https://www.forth.com/starting-forth/2-stack-manipulation-operators-arithmetic/
|
# https://www.forth.com/starting-forth/2-stack-manipulation-operators-arithmetic/
|
||||||
# https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-6.html#jvms-6.5.swap
|
# https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-6.html#jvms-6.5.swap
|
||||||
|
@ -70,16 +71,17 @@ class DROP(Opcode):
|
||||||
class SLOT(Opcode):
|
class SLOT(Opcode):
|
||||||
"""(..., A) -> (A, ..., A)
|
"""(..., A) -> (A, ..., A)
|
||||||
|
|
||||||
Copy the Nth (counting up from 0 at the bottom of the stack) item to the top of the stack.
|
Copy the Nth (counting up from 0 at the bottom of the stack) item to the top
|
||||||
Intended to allow users to emulate (immutable) frame local slots for reused values.
|
of the stack. Intended to allow users to emulate (immutable) frame local
|
||||||
|
slots for reused values.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
target: int
|
target: int
|
||||||
|
|
||||||
####################################################################################################
|
################################################################################
|
||||||
# Functional abstraction
|
# Functional abstraction
|
||||||
####################################################################################################
|
################################################################################
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class IDENTIFIERC(Opcode):
|
class IDENTIFIERC(Opcode):
|
||||||
|
@ -123,23 +125,24 @@ class CALLF(Opcode):
|
||||||
class RETURN(Opcode):
|
class RETURN(Opcode):
|
||||||
"""(... A) -> ()
|
"""(... A) -> ()
|
||||||
|
|
||||||
Return to the source of the last `CALL`. The returnee will see the top `nargs` values of the present stack
|
Return to the source of the last `CALL`. The returnee will see the top
|
||||||
appended to theirs. All other values on the stack will be discarded.
|
`nargs` values of the present stack appended to theirs. All other values on
|
||||||
|
the stack will be discarded.
|
||||||
|
|
||||||
Executing a `RETURN` pops (restores) the name and module path of the current function back to that of the caller.
|
Executing a `RETURN` pops (restores) the name and module path of the current
|
||||||
|
function back to that of the caller.
|
||||||
|
|
||||||
If the call stack is empty, `RETURN` will exit the interpreter.
|
If the call stack is empty, `RETURN` will exit the interpreter.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
nargs: int
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CLOSUREF(Opcode):
|
class CLOSUREF(Opcode):
|
||||||
"""(`FUNREF<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
|
"""(`FUNREF<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
|
||||||
|
|
||||||
Construct a closure over the function reference at the top of the stack. This may produce nullary closures.
|
Construct a closure over the function reference at the top of the stack.
|
||||||
|
This may produce nullary closures.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -150,7 +153,8 @@ class CLOSUREF(Opcode):
|
||||||
class CLOSUREC(Opcode):
|
class CLOSUREC(Opcode):
|
||||||
"""(`CLOSURE<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
|
"""(`CLOSURE<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
|
||||||
|
|
||||||
Further close over the closure at the top of the stack. This may produce nullary closures.
|
Further close over the closure at the top of the stack. This may produce
|
||||||
|
nullary closures.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -162,9 +166,9 @@ class CALLC(Opcode):
|
||||||
|
|
||||||
Call [closure]
|
Call [closure]
|
||||||
|
|
||||||
Make a dynamic call to the closure at the top of stack.
|
Make a dynamic call to the closure at the top of stack. The callee will see
|
||||||
The callee will see a stack containg only the provided `nargs` and closed-overs.
|
a stack containg only the provided `nargs` and closed-overs. A subsequent
|
||||||
A subsequent RETURN will return execution to the next point.
|
RETURN will return execution to the next point.
|
||||||
|
|
||||||
Executing a `CALL` pushes the name and module path of the current function.
|
Executing a `CALL` pushes the name and module path of the current function.
|
||||||
|
|
||||||
|
@ -172,9 +176,9 @@ class CALLC(Opcode):
|
||||||
|
|
||||||
nargs: int = 0
|
nargs: int = 0
|
||||||
|
|
||||||
####################################################################################################
|
################################################################################
|
||||||
# Structures
|
# Structures
|
||||||
####################################################################################################
|
################################################################################
|
||||||
|
|
||||||
# FIXME: This lacks any sort of way to do dynamic type/field references
|
# FIXME: This lacks any sort of way to do dynamic type/field references
|
||||||
|
|
||||||
|
@ -188,8 +192,8 @@ class TYPEREF(Opcode):
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class VARIANTREF(Opcode):
|
class ARMREF(Opcode):
|
||||||
"""(IDENTIFIER, TYPEREF) -> (VARIANTREF)
|
"""(TYPEREF, IDENTIFIER) -> (VARIANTREF)
|
||||||
|
|
||||||
Produce a VARIANTREF to an 'arm' of the given variant type.
|
Produce a VARIANTREF to an 'arm' of the given variant type.
|
||||||
|
|
||||||
|
@ -197,23 +201,25 @@ class VARIANTREF(Opcode):
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class VARIANT(Opcode):
|
class ARM(Opcode):
|
||||||
"""(VARIANTREF<a ⊢ A ⊂ B>, ...) -> (B)
|
"""(ARMTREF<a ⊢ A ⊂ B>, ...) -> (B)
|
||||||
|
|
||||||
Construct an instance of an 'arm' of a variant.
|
Construct an instance of an 'arm' of a variant.
|
||||||
The type of the 'arm' is considered to be the type of the whole variant.
|
The type of the 'arm' is considered to be the type of the whole variant.
|
||||||
|
|
||||||
The name and module path of the current function MUST match the name and module path of `VARIANTREF`.
|
The name and module path of the current function MUST match the name and
|
||||||
The arity of this opcode MUST match the arity of the arm.
|
module path of `VARIANTREF`. The arity of this opcode MUST match the arity
|
||||||
The signature of the arm MUST match the signature fo the top N of the stack.
|
of the arm. The signature of the arm MUST match the signature fo the top N
|
||||||
|
of the stack.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
nargs: int = 0
|
nargs: int = 0
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class VTEST(Opcode):
|
class ATEST(Opcode):
|
||||||
"""(VARIANTREF<a ⊢ A ⊂ B>, B) -> ()
|
"""(ARMREF<a ⊢ A ⊂ B>, B) -> ()
|
||||||
|
|
||||||
Test whether B is a given arm of a variant A .
|
Test whether B is a given arm of a variant A .
|
||||||
If it is, branch to the given target.
|
If it is, branch to the given target.
|
||||||
|
@ -225,12 +231,12 @@ class VTEST(Opcode):
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class VLOAD(Opcode):
|
class ALOAD(Opcode):
|
||||||
"""(VARIANTREF<a ⊢ A ⊂ B>, B) -> (A)
|
"""(ARMREF<a ⊢ A ⊂ B>, B) -> (A)
|
||||||
|
|
||||||
Load the value of the variant arm.
|
Load the value of the variant arm. VLOAD errors (undefined) if B is not
|
||||||
VLOAD errors (undefined) if B is not within the variant.
|
within the variant. VLOAD errors (undefined) if the value in B is not an A -
|
||||||
VLOAD errors (undefined) if the value in B is not an A - use VTEST as needed.
|
use VTEST as needed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ class Variant(t.NamedTuple):
|
||||||
|
|
||||||
class Closure(t.NamedTuple):
|
class Closure(t.NamedTuple):
|
||||||
# Note that a closure over a closure is equivalent to a single closure which extends the captured stack fragment, so
|
# Note that a closure over a closure is equivalent to a single closure which extends the captured stack fragment, so
|
||||||
# there's no need for a union here as we can simply convert nested closures.
|
# there's no need for a union here as we can .interpretery convert nested closures.
|
||||||
funref: FunctionRef
|
funref: FunctionRef
|
||||||
frag: t.List[t.Any]
|
frag: t.List[t.Any]
|
||||||
|
|
||||||
|
@ -189,10 +189,10 @@ class Module(t.NamedTuple):
|
||||||
def translate(start: int, end: int, i: isa.Opcode):
|
def translate(start: int, end: int, i: isa.Opcode):
|
||||||
# FIXME: Consolidate bounds checks somehow
|
# FIXME: Consolidate bounds checks somehow
|
||||||
match i:
|
match i:
|
||||||
case isa.VTEST(t):
|
case isa.ATEST(t):
|
||||||
d = t + start
|
d = t + start
|
||||||
assert start <= d < end
|
assert start <= d < end
|
||||||
return isa.VTEST(d)
|
return isa.ATEST(d)
|
||||||
|
|
||||||
case isa.GOTO(t):
|
case isa.GOTO(t):
|
||||||
d = t + start
|
d = t + start
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""The implementation of Shogoth's lexical analyzer."""
|
"""The.interpreterementation of Shogoth's lexical analyzer."""
|
||||||
|
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from ichor import BOOTSTRAP, Interpreter
|
from ichor.bootstrap import BOOTSTRAP
|
||||||
|
from ichor.interpreter import Interpreter
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from ichor import FuncBuilder, isa
|
from ichor import isa
|
||||||
|
from ichor.assembler import FuncBuilder
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
from .fixtures import * # noqa
|
from .fixtures import * # noqa
|
||||||
|
|
||||||
from ichor import FALSE, isa, NOT1, TRUE
|
from ichor import isa
|
||||||
|
from ichor.bootstrap import FALSE, NOT1, TRUE
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ def test_not(vm, stack, ret):
|
||||||
isa.IDENTIFIERC(NOT1),
|
isa.IDENTIFIERC(NOT1),
|
||||||
isa.FUNREF(),
|
isa.FUNREF(),
|
||||||
isa.CALLF(1),
|
isa.CALLF(1),
|
||||||
isa.RETURN(1)
|
isa.RETURN()
|
||||||
], stack = stack) == ret
|
], stack = stack) == ret
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,47 +4,49 @@ Tests coverign the VM interpreter
|
||||||
|
|
||||||
from .fixtures import * # noqa
|
from .fixtures import * # noqa
|
||||||
|
|
||||||
from ichor import (
|
from ichor.bootstrap import (
|
||||||
FALSE,
|
FALSE,
|
||||||
InterpreterError,
|
|
||||||
isa,
|
|
||||||
TRUE,
|
TRUE,
|
||||||
)
|
)
|
||||||
|
from ichor import isa
|
||||||
|
from ichor.interpreter import InterpreterError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
def test_return(vm):
|
def test_return(vm):
|
||||||
assert vm.run([isa.RETURN(0)], stack=[TRUE, FALSE]) == []
|
with pytest.raises(InterpreterError):
|
||||||
assert vm.run([isa.RETURN(1)], stack=[TRUE, FALSE]) == [TRUE]
|
vm.run([isa.RETURN()], stack=[])
|
||||||
assert vm.run([isa.RETURN(2)], stack=[TRUE, FALSE]) == [TRUE, FALSE]
|
|
||||||
|
assert vm.run([isa.RETURN()], stack=[FALSE, TRUE]) == [FALSE]
|
||||||
|
assert vm.run([isa.DROP(1), isa.RETURN()], stack=[TRUE, FALSE]) == [TRUE]
|
||||||
|
|
||||||
|
|
||||||
def test_dup(vm):
|
def test_dup(vm):
|
||||||
assert vm.run([isa.DUP(1), isa.RETURN(3)], stack=[FALSE, TRUE]) == [FALSE, TRUE, TRUE]
|
assert vm.run([isa.DUP(1), isa.BREAK()], stack=[FALSE, TRUE]) == [FALSE, TRUE, TRUE]
|
||||||
assert vm.run([isa.DUP(2), isa.RETURN(4)], stack=[FALSE, TRUE]) == [FALSE, TRUE, FALSE, TRUE]
|
assert vm.run([isa.DUP(2), isa.BREAK()], stack=[FALSE, TRUE]) == [FALSE, TRUE, FALSE, TRUE]
|
||||||
|
|
||||||
|
|
||||||
def test_rot(vm):
|
def test_rot(vm):
|
||||||
assert vm.run([
|
assert vm.run([
|
||||||
isa.ROT(2),
|
isa.ROT(2),
|
||||||
isa.RETURN(2)
|
isa.BREAK()
|
||||||
], stack=[FALSE, TRUE]) == [TRUE, FALSE]
|
], stack=[FALSE, TRUE]) == [TRUE, FALSE]
|
||||||
|
|
||||||
assert vm.run([
|
assert vm.run([
|
||||||
isa.ROT(2),
|
isa.ROT(2),
|
||||||
isa.RETURN(5)
|
isa.BREAK()
|
||||||
], stack=[TRUE, TRUE, TRUE, FALSE, TRUE]) == [TRUE, TRUE, TRUE, TRUE, FALSE]
|
], stack=[TRUE, TRUE, TRUE, FALSE, TRUE]) == [TRUE, TRUE, TRUE, TRUE, FALSE]
|
||||||
|
|
||||||
assert vm.run([
|
assert vm.run([
|
||||||
isa.ROT(3),
|
isa.ROT(3),
|
||||||
isa.RETURN(3)
|
isa.BREAK()
|
||||||
], stack=[FALSE, TRUE, FALSE]) == [FALSE, FALSE, TRUE]
|
], stack=[FALSE, TRUE, FALSE]) == [FALSE, FALSE, TRUE]
|
||||||
|
|
||||||
|
|
||||||
def test_drop(vm):
|
def test_drop(vm):
|
||||||
assert vm.run([
|
assert vm.run([
|
||||||
isa.DROP(1),
|
isa.DROP(1),
|
||||||
isa.RETURN(1)
|
isa.BREAK()
|
||||||
], stack=[TRUE, FALSE]) == [TRUE]
|
], stack=[TRUE, FALSE]) == [TRUE]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
"""Tests covering the Ichor ISA and state model."""
|
"""Tests covering the Ichor ISA and state model."""
|
||||||
|
|
||||||
from ichor.impl import Stackframe
|
from ichor.interpreter import Stackframe
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue