source/projects/shoggoth/src/python/ichor/isa.py

247 lines
5.5 KiB
Python
Raw Normal View History

"""The instruction set for Shogoth."""
2022-07-16 01:33:32 +00:00
from abc import ABC
from dataclasses import dataclass
2022-07-16 01:33:32 +00:00
@dataclass
class Label(object):
name: str
def __hash__(self):
return hash(self.name)
class Opcode(ABC):
pass
@dataclass
class GOTO(Opcode):
"""() -> ()
2022-08-09 15:39:33 +00:00
Branch to another point within the same bytecode segment. The target MUST be
within the same module range as the current function. Branching does NOT
update the name or module of the current function.
2022-07-16 01:33:32 +00:00
"""
target: int
2022-08-09 15:39:33 +00:00
################################################################################
2022-07-16 01:33:32 +00:00
# Stack manipulation
2022-08-09 15:39:33 +00:00
################################################################################
2022-07-16 01:33:32 +00:00
# https://wiki.laptop.org/go/Forth_stack_operators
# 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
@dataclass
class DUP(Opcode):
"""(A, B, ...) -> (A, B, ...)
Duplicate the top N items of the stack.
"""
nargs: int = 1
2022-07-16 01:33:32 +00:00
@dataclass
class ROT(Opcode):
"""(A, B, ... Z) -> (Z, A, B, ...)
2022-07-16 01:33:32 +00:00
Rotate the top N elements of the stack.
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
nargs: int = 2
2022-07-16 01:33:32 +00:00
@dataclass
class DROP(Opcode):
"""(*) -> ()
2022-07-16 01:33:32 +00:00
Drop the top N items of the stack.
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
nargs: int = 1
2022-07-16 01:33:32 +00:00
@dataclass
class SLOT(Opcode):
"""(..., A) -> (A, ..., A)
2022-06-01 06:22:53 +00:00
2022-08-09 15:39:33 +00:00
Copy the Nth (counting up from 0 at the bottom of the stack) item to the top
of the stack. Intended to allow users to emulate (immutable) frame local
slots for reused values.
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
target: int
2022-08-09 15:39:33 +00:00
################################################################################
2022-07-16 01:33:32 +00:00
# Functional abstraction
2022-08-09 15:39:33 +00:00
################################################################################
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
class IDENTIFIERC(Opcode):
"""() -> (IDENTIFIER)
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
An inline constant which produces an identifier to the stack.
2022-07-16 01:33:32 +00:00
Identifiers name functions, fields and types but are not strings.
They are a VM-internal naming structure with reference to the module.
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
val: str
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
class FUNREF(Opcode):
"""(IDENTIFIER) -> (`FUNREF<... A to ... B>`)
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
Construct a reference to a static codepoint.
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
@dataclass
class CALLF(Opcode):
"""(`FUNREF<... A to ... B>`, ... A) -> (... B)
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
Call [funref]
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
Make a dynamic call to the function reference at the top of stack.
The callee will see a stack containg only the provided `nargs`.
A subsequent RETURN will return execution to the next point.
2022-07-16 01:33:32 +00:00
Executing a `CALL` pushes the name and module path of the current function.
2022-07-16 01:33:32 +00:00
"""
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
nargs: int = 0
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
class RETURN(Opcode):
"""(... A) -> ()
2022-08-09 15:39:33 +00:00
Return to the source of the last `CALL`. The returnee will see the top
`nargs` values of the present stack appended to theirs. All other values on
the stack will be discarded.
2022-06-01 06:22:53 +00:00
2022-08-09 15:39:33 +00:00
Executing a `RETURN` pops (restores) the name and module path of the current
function back to that of the caller.
2022-07-16 01:33:32 +00:00
If the call stack is empty, `RETURN` will exit the interpreter.
2022-07-16 01:33:32 +00:00
"""
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
class CLOSUREF(Opcode):
"""(`FUNREF<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
2022-08-09 15:39:33 +00:00
Construct a closure over the function reference at the top of the stack.
This may produce nullary closures.
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
nargs: int = 0
2022-07-16 01:33:32 +00:00
@dataclass
class CLOSUREC(Opcode):
"""(`CLOSURE<A, ... B to ... C>`, A) -> (`CLOSURE<... B to ... C>`)
2022-08-09 15:39:33 +00:00
Further close over the closure at the top of the stack. This may produce
nullary closures.
2022-07-16 01:33:32 +00:00
"""
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
nargs: int = 0
2022-06-01 06:22:53 +00:00
2022-06-01 06:11:14 +00:00
2022-07-16 01:33:32 +00:00
class CALLC(Opcode):
"""(`CLOSURE<... A to ... B>`, ... A) -> (... B)
2022-07-16 01:33:32 +00:00
Call [closure]
2022-06-01 06:22:53 +00:00
2022-08-09 15:39:33 +00:00
Make a dynamic call to the closure at the top of stack. The callee will see
a stack containg only the provided `nargs` and closed-overs. A subsequent
RETURN will return execution to the next point.
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
Executing a `CALL` pushes the name and module path of the current function.
2022-06-01 06:11:14 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-07-16 01:33:32 +00:00
nargs: int = 0
2022-06-01 06:22:53 +00:00
2022-08-09 15:39:33 +00:00
################################################################################
2022-07-16 01:33:32 +00:00
# Structures
2022-08-09 15:39:33 +00:00
################################################################################
2022-07-16 01:33:32 +00:00
# FIXME: This lacks any sort of way to do dynamic type/field references
2022-07-16 01:33:32 +00:00
@dataclass
class TYPEREF(Opcode):
"""(IDENTIFIER) -> (TYPEREF)
2022-06-01 06:22:53 +00:00
2022-07-16 01:33:32 +00:00
Produces a TYPEREF to the type named by the provided IDENTIFIER.
2022-07-16 01:33:32 +00:00
"""
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
2022-08-09 15:39:33 +00:00
class ARMREF(Opcode):
"""(TYPEREF, IDENTIFIER) -> (VARIANTREF)
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
Produce a VARIANTREF to an 'arm' of the given variant type.
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
2022-08-09 15:39:33 +00:00
class ARM(Opcode):
"""(ARMTREF<a ⊢ A ⊂ B>, ...) -> (B)
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
Construct an instance of an 'arm' of a variant.
The type of the 'arm' is considered to be the type of the whole variant.
2022-06-07 16:32:15 +00:00
2022-08-09 15:39:33 +00:00
The name and module path of the current function MUST match the name and
module path of `VARIANTREF`. The arity of this opcode MUST match the arity
of the arm. The signature of the arm MUST match the signature fo the top N
of the stack.
2022-07-16 01:33:32 +00:00
"""
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
nargs: int = 0
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
2022-08-09 15:39:33 +00:00
class ATEST(Opcode):
"""(ARMREF<a ⊢ A ⊂ B>, B) -> ()
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
Test whether B is a given arm of a variant A .
If it is, branch to the given target.
Otherwise fall through.
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
target: int
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
2022-08-09 15:39:33 +00:00
class ALOAD(Opcode):
"""(ARMREF<a ⊢ A ⊂ B>, B) -> (A)
2022-06-16 05:10:54 +00:00
2022-08-09 15:39:33 +00:00
Load the value of the variant arm. VLOAD errors (undefined) if B is not
within the variant. VLOAD errors (undefined) if the value in B is not an A -
use VTEST as needed.
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
"""
2022-06-07 16:32:15 +00:00
2022-07-16 01:33:32 +00:00
@dataclass
class BREAK(Opcode):
"""Abort the interpreter."""