From b6e1a61a85eaea97cdb62d27bf3de50d0d7d7825 Mon Sep 17 00:00:00 2001 From: "Reid D. 'arrdem' McKenzie" Date: Tue, 31 May 2022 23:08:29 -0600 Subject: [PATCH] An evening of hacking --- projects/shoggoth/BUILD | 9 ++++ projects/shoggoth/README.md | 4 ++ .../shoggoth/src/python/ichor/__main__.py | 23 ++++++++ .../shoggoth/src/python/ichor/bootstrap.py | 53 ++++++++++++++++--- projects/shoggoth/src/python/ichor/impl.py | 33 +++++++----- projects/shoggoth/src/python/ichor/isa.py | 24 +++++++++ projects/shoggoth/src/python/ichor/typing.py | 8 --- .../test/python/ichor/test_bootstrap.py | 28 +++++++--- .../test/python/ichor/test_interpreter.py | 7 +++ 9 files changed, 151 insertions(+), 38 deletions(-) create mode 100644 projects/shoggoth/src/python/ichor/__main__.py diff --git a/projects/shoggoth/BUILD b/projects/shoggoth/BUILD index d8fe06e..d694b36 100644 --- a/projects/shoggoth/BUILD +++ b/projects/shoggoth/BUILD @@ -10,3 +10,12 @@ py_project( py_requirement("flask"), ], ) + +zapp_binary( + name="ichor", + main = "src/python/ichor/__main__.py", + shebang="/usr/bin/env python3", + deps = [ + ":lib", + ], +) diff --git a/projects/shoggoth/README.md b/projects/shoggoth/README.md index 5ee126a..0c083bc 100644 --- a/projects/shoggoth/README.md +++ b/projects/shoggoth/README.md @@ -4,6 +4,10 @@ > > ~ Charlie Stross, "A Colder War" +Shoggoth is a language designed to provide highly durable, portable agents. + +Shoggoth runs atop a custom platform named Ichor, which aims to trivialize providing these properties. + ## License While the source for this project happens to be published no grant of rights is made. diff --git a/projects/shoggoth/src/python/ichor/__main__.py b/projects/shoggoth/src/python/ichor/__main__.py new file mode 100644 index 0000000..8f6c156 --- /dev/null +++ b/projects/shoggoth/src/python/ichor/__main__.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +""" +ichor entrypoint +""" + +from . import * + + +def main(): + vm = Interpreter(BOOTSTRAP) + ret = vm.run( + [ + Opcode.CALLS(XOR3), + Opcode.RETURN(1) + ], + stack = [True, False, False] + ) + print(ret) + + +if __name__ == "__main__": + main() diff --git a/projects/shoggoth/src/python/ichor/bootstrap.py b/projects/shoggoth/src/python/ichor/bootstrap.py index 75b9467..7ecea4b 100644 --- a/projects/shoggoth/src/python/ichor/bootstrap.py +++ b/projects/shoggoth/src/python/ichor/bootstrap.py @@ -11,7 +11,7 @@ from .typing import ProductExpr, SumExpr BOOTSTRAP = Module() -NOT = BOOTSTRAP.define_function( +NOT1 = BOOTSTRAP.define_function( ";/lang/shoggoth/v0/bootstrap/not;bool;bool", [ Opcode.IF(target=3), @@ -22,7 +22,7 @@ NOT = BOOTSTRAP.define_function( ], ) -OR = BOOTSTRAP.define_function( +OR2 = BOOTSTRAP.define_function( ";/lang/shoggoth/v0/bootstrap/or;bool,bool;bool", [ Opcode.IF(target=3), @@ -36,7 +36,17 @@ OR = BOOTSTRAP.define_function( ], ) -AND = BOOTSTRAP.define_function( +OR3 = BOOTSTRAP.define_function( + ";/lang/shoggoth/v0/bootstrap/or;bool,bool,bool;bool", + [ + # A B C + Opcode.CALLS(OR2), # A|B C + Opcode.CALLS(OR2), # A|B|C + Opcode.RETURN(1), + ] +) + +AND2 = BOOTSTRAP.define_function( ";/lang/shoggoth/v0/bootstrap/and;bool,bool;bool", [ Opcode.IF(target=3), @@ -49,20 +59,30 @@ AND = BOOTSTRAP.define_function( ], ) -XOR = BOOTSTRAP.define_function( +AND3 = BOOTSTRAP.define_function( + ";/lang/shoggoth/v0/bootstrap/and;bool,bool,bool;bool", + [ + # A B C + Opcode.CALLS(AND2), # A&B C + Opcode.CALLS(AND2), # A&B&C + Opcode.RETURN(1), + ], +) + +XOR2 = BOOTSTRAP.define_function( ";/lang/shoggoth/v0/bootstrap/xor;bool,bool;bool", [ Opcode.DUP(nargs=2), # !A && B - Opcode.CALLS(NOT), - Opcode.CALLS(AND), + Opcode.CALLS(NOT1), + Opcode.CALLS(AND2), Opcode.IF(target=6), Opcode.TRUE(), Opcode.RETURN(1), # !B && A Opcode.ROT(2), - Opcode.CALLS(NOT), - Opcode.CALLS(AND), + Opcode.CALLS(NOT1), + Opcode.CALLS(AND2), Opcode.IF(target=12), Opcode.TRUE(), Opcode.RETURN(1), @@ -72,6 +92,23 @@ XOR = BOOTSTRAP.define_function( ], ) +XOR3 = BOOTSTRAP.define_function( + ";/lang/shoggoth/v0/bootstrap/xor;bool,bool,bool;bool", + [ + # A B C + Opcode.ROT(nargs=3), # C A B + Opcode.ROT(nargs=3), # B C A + Opcode.DUP(nargs=1), # B B C A + Opcode.ROT(nargs=4), # A B B C + Opcode.CALLS(XOR2), # A^B B C + Opcode.ROT(nargs=3), # C A^B B + Opcode.ROT(nargs=3), # B C A^B + Opcode.CALLS(XOR2), # B^C A^B + Opcode.CALLS(OR2), # A^B|B^C + Opcode.RETURN(1), + ] +) + TRUE = BOOTSTRAP.define_type( "/lang/shoggoth/v0/true", ProductExpr([]), diff --git a/projects/shoggoth/src/python/ichor/impl.py b/projects/shoggoth/src/python/ichor/impl.py index 6e7a8a8..ee47716 100644 --- a/projects/shoggoth/src/python/ichor/impl.py +++ b/projects/shoggoth/src/python/ichor/impl.py @@ -24,11 +24,12 @@ def rotate(l): class Stackframe(object): - def __init__(self, stack=None, name=None, ip=None, parent=None): + def __init__(self, stack=None, name=None, ip=None, parent=None, depth=0): self.stack = stack or [] self.name = name or ";unknown;;" self.ip = ip or 0 self.parent = parent + self.depth = depth def push(self, obj): self.stack.insert(0, obj) @@ -37,15 +38,16 @@ class Stackframe(object): return self.stack.pop(0) def call(self, signature: FunctionRef, ip): - print(signature) + self.ip += 1 nargs = len(signature.args) args, self.stack = self.stack[:nargs], self.stack[nargs:] return Stackframe( - stack=args, - name=signature.raw, - ip=ip, - parent=self - ) + stack=args, + name=signature.raw, + ip=ip, + parent=self, + depth=self.depth+1 + ) def ret(self, nargs): self.parent.stack = self.stack[:nargs] + self.parent.stack @@ -96,6 +98,8 @@ class Interpreter(object): while True: op = mod.opcodes[stack.ip] + # print("{0}{1: <50} {2}: {3}".format(" " * stack.depth, str(stack.stack), stack.ip, op)) + match op: case Opcode.TRUE(): stack.push(True) @@ -151,15 +155,16 @@ class Interpreter(object): if (n > len(stack)): _error("Stack size violation") - if stack.parent: - sig = FunctionRef.parse(stack.name) - if (len(sig.ret) != n): - _error("Signature violation") - - stack = stack.ret(n) - else: + if stack.depth == 0: return stack[:n] + sig = FunctionRef.parse(stack.name) + if (len(sig.ret) != n): + _error("Signature violation") + + stack = stack.ret(n) + continue + case Opcode.GOTO(n, _): if (n < 0): _error("Illegal branch target") diff --git a/projects/shoggoth/src/python/ichor/isa.py b/projects/shoggoth/src/python/ichor/isa.py index c2c9998..542b0b1 100644 --- a/projects/shoggoth/src/python/ichor/isa.py +++ b/projects/shoggoth/src/python/ichor/isa.py @@ -7,6 +7,9 @@ from .typing import FunctionRef class Opcode: + #################################################################################################### + # Logic + #################################################################################################### class TRUE(NamedTuple): """() -> (bool) Push the constant TRUE onto the stack. @@ -189,6 +192,18 @@ class Opcode: Produces the updated array as the top of stack. """ + #################################################################################################### + # Naturals + #################################################################################################### + + #################################################################################################### + # Integers + #################################################################################################### + + #################################################################################################### + # Ratios + #################################################################################################### + class Module(NamedTuple): opcodes: list = [] @@ -241,3 +256,12 @@ class Module(NamedTuple): def define_type(self, name, signature): # FIXME: What in TARNATION is this going to do pass + + def __str__(self): + b = [] + marks = {v: k for k, v in self.functions.items()} + for i, o in zip(range(1<<64), self.opcodes): + if(i in marks): + b.append(f"{marks[i]}:") + b.append(f"{i: >10}: {o}") + return "\n".join(b) diff --git a/projects/shoggoth/src/python/ichor/typing.py b/projects/shoggoth/src/python/ichor/typing.py index c9235b7..e3a753c 100644 --- a/projects/shoggoth/src/python/ichor/typing.py +++ b/projects/shoggoth/src/python/ichor/typing.py @@ -26,10 +26,6 @@ class ProductExpr(t.NamedTuple): #################################################################################################### #################################################################################################### -class Function(t.NamedTuple): - """The type of a function; a subset of its signature.""" - - class FunctionRef(t.NamedTuple): raw: str type_params: list @@ -79,7 +75,3 @@ class FunctionSignature(t.NamedTuple): cls.parse_list(args), cls.parse_list(ret) ) - - -class Function(t.NamedTuple): - """The type of a function; a subset of its signature.""" diff --git a/projects/shoggoth/test/python/ichor/test_bootstrap.py b/projects/shoggoth/test/python/ichor/test_bootstrap.py index 75188a1..897e03f 100644 --- a/projects/shoggoth/test/python/ichor/test_bootstrap.py +++ b/projects/shoggoth/test/python/ichor/test_bootstrap.py @@ -11,7 +11,7 @@ from ichor import * [[True], [False]], ]) def test_not(vm, stack, ret): - assert vm.run([Opcode.CALLS(NOT)], stack = stack) == ret + assert vm.run([Opcode.CALLS(NOT1)], stack = stack) == ret @pytest.mark.parametrize("stack,ret", [ @@ -21,7 +21,7 @@ def test_not(vm, stack, ret): [[True, True], [True]], ]) def test_or(vm, stack, ret): - assert vm.run([Opcode.CALLS(OR)], stack = stack) == ret + assert vm.run([Opcode.CALLS(OR2)], stack = stack) == ret @pytest.mark.parametrize("stack,ret", [ @@ -31,7 +31,7 @@ def test_or(vm, stack, ret): [[True, True], [True]], ]) def test_and(vm, stack, ret): - assert vm.run([Opcode.CALLS(AND)], stack = stack) == ret + assert vm.run([Opcode.CALLS(AND2)], stack = stack) == ret @pytest.mark.parametrize("stack,ret", [ @@ -40,19 +40,31 @@ def test_and(vm, stack, ret): [[False, True], [True]], [[True, True], [False]], ]) -def test_xor(vm, stack, ret): - assert vm.run([Opcode.CALLS(XOR)], stack = stack) == ret +def test_xor2(vm, stack, ret): + assert vm.run([Opcode.CALLS(XOR2)], 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_xor3(vm, stack, ret): + assert vm.run([Opcode.CALLS(XOR3)], stack = stack) == ret @pytest.mark.parametrize("stack,ret", [ - [[], [FunctionRef.parse(NOT)]] + [[], [FunctionRef.parse(NOT1)]] ]) def test_funref(vm, stack, ret): - assert vm.run([Opcode.FUNREF(NOT), Opcode.RETURN(1)], stack = stack) == ret + assert vm.run([Opcode.FUNREF(NOT1), Opcode.RETURN(1)], stack = stack) == ret @pytest.mark.parametrize("stack,ret", [ [[], [True]] ]) def test_callf(vm, stack, ret): - assert vm.run([Opcode.FALSE(), Opcode.FUNREF(NOT), Opcode.CALLF(1)], stack = stack) == ret + assert vm.run([Opcode.FALSE(), Opcode.FUNREF(NOT1), Opcode.CALLF(1)], stack = stack) == ret diff --git a/projects/shoggoth/test/python/ichor/test_interpreter.py b/projects/shoggoth/test/python/ichor/test_interpreter.py index 2cfcd9b..99b2c1d 100644 --- a/projects/shoggoth/test/python/ichor/test_interpreter.py +++ b/projects/shoggoth/test/python/ichor/test_interpreter.py @@ -86,3 +86,10 @@ def test_drop_too_many(vm): with pytest.raises(InterpreterError): vm.run([Opcode.TRUE(), Opcode.DROP(2)]) + + +def test_frames(): + assert len(list(Stackframe().frames())) == 1 + assert len(list(Stackframe(parent=Stackframe()).frames())) == 2 + assert len(list(Stackframe(parent=Stackframe(parent=Stackframe())).frames())) == 3 + assert len(list(Stackframe(parent=Stackframe(parent=Stackframe(parent=Stackframe()))).frames())) == 4