From bc7cb3e909e21dd26a11efeab6512b91ffb3b8fa Mon Sep 17 00:00:00 2001 From: "Reid D. 'arrdem' McKenzie" Date: Mon, 13 Jun 2022 11:44:28 -0600 Subject: [PATCH] [NO TESTS] WIP --- projects/garage/worktop.scad | 66 ++++++ projects/garage/worktop2.scad | 150 +++++++++++++ projects/public-dns/BUILD | 1 + projects/shoggoth/DOC.md | 212 ++++++++++++++++++ projects/shoggoth/README.md | 44 +++- .../shoggoth/src/python/ichor/bootstrap.py | 17 +- projects/shoggoth/src/python/ichor/isa.py | 92 +------- 7 files changed, 479 insertions(+), 103 deletions(-) create mode 100644 projects/garage/worktop.scad create mode 100644 projects/garage/worktop2.scad create mode 100644 projects/shoggoth/DOC.md diff --git a/projects/garage/worktop.scad b/projects/garage/worktop.scad new file mode 100644 index 0000000..a67423f --- /dev/null +++ b/projects/garage/worktop.scad @@ -0,0 +1,66 @@ +use + +module beam($fn=$fn) { + union() { + translate([2, 0, 0]) + cube([24, 2, 4]); + translate([26, 0, 2]) + rotate([-90, 0, 0]) + cylinder(r=2, h=2, $fn=$fn); + } +} + +module top() { + translate([0, 0, 4]) + cube([24, 96, 0.75]); + + translate([0, 2, 0]) + beam(); + + translate([0, 48, 0]) + beam(); + + translate([0, 94, 0]) + beam(); +} + + +module worktop() { + translate([0, 0, 40]) { + translate([6, 0, 0]) + cube([14, 2, 4]); + + translate([6, 92, 0]) + cube([14, 2, 4]); + + top(); + + // the wing + translate([52, 96, 0]) + rotate([0, 0, 180]) + top(); + + // supports + translate([0, 0, -4]) { + } + } + + for(x=[2, 20]) + for(y=[0, 92]) + translate([x, y, 0]) + cube([4, 2, 44]); + + translate([6, 0, 0]) + cube([14, 2, 4]); + + translate([0, 2, 0]) + cube([24, 2, 4]); + + translate([6, 92, 0]) + cube([14, 2, 4]); + + translate([0, 94, 0]) + cube([24, 2, 4]); +} + +worktop(); \ No newline at end of file diff --git a/projects/garage/worktop2.scad b/projects/garage/worktop2.scad new file mode 100644 index 0000000..c14758a --- /dev/null +++ b/projects/garage/worktop2.scad @@ -0,0 +1,150 @@ +// 2x4" nominal lumber is really 38mm x 89mm x Z +// Drawing unit: MM 1:1 + +use + +function in2mm(x) = 25.4 * x; + +module txf(height) { + cube([38, 89, height]); +} + +module post(height) { + txf(height); +} + +module dpost(height) { + post(height); + + translate([38, 0, 0]) + post(height); +} + +module frame(width, depth, height) { + translate([38, 38, 0]) { + dpost(height); + } + + translate([38, 38 + 89 + in2mm(30), 0]) { + dpost(height); + } + + translate([38, depth - 89 - 38, 0]) { + dpost(height); + } + + // bottom bar + translate([0, 0, 89]) + rotate([-90, 0, 0]) + txf(depth); + + // top bar + let(inset=in2mm(30) + 38 + 89) { + translate([0, inset, height]) + rotate([-90, 0, 0]) + txf(depth - inset); + } + + // support + translate([0, 0, height - in2mm(20)]) + rotate([-90, 0, 0]) + txf(in2mm(30) + 38 * 2 + 89 * 2); +} + +module shelf(width, depth, thickness) { + // FIXME: Is there more shelf geometry? A bottom box in 1x2 or something? + cube([width, depth, thickness]); +} + +module bench(width, depth, height, + top_thickness=in2mm(0.75), + shelf_width=in2mm(30), + shelf_depth=in2mm(20)) { + ch = 38 * 2 + 2; + ph = height - ch - top_thickness; + + // The frame, at relative to caster plane coordinates. + translate([0, 0, ch]) { + frame(width, depth, ph); + + translate([width, 0, 0]) + mirror([1, 0, 0]) + frame(width, depth, ph); + + // top + translate([0, 38 + 89 + in2mm(30), ph]) { + cube([width, depth - 38 - 89 - shelf_width, top_thickness]); + } + + translate([0, 0, ph]) { + cube([width, 38 + 89, top_thickness]); + } + + // Wing top + + // bottom bars + translate([38, 38, 89]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + translate([38, depth, 89]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + // "top" bars + translate([38, 38, ph - shelf_depth]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + translate([38, 38, ph]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + + translate([38, 38, ph - shelf_depth]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + translate([38, 38*2 + 89*2 + shelf_width, ph - in2mm(20)]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + translate([38, 38*2 + 89*2 + shelf_width, ph]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + translate([38, depth, ph]) + rotate([-90, 0, -90]) + txf(width - 38 * 2); + + // Reference shelf + translate([0, 38 + 89, ph - shelf_depth/2]) + shelf(width, shelf_width, top_thickness); + + } + + // The casters, at absolute coordinates + + for (dx=[0, width-(38*3)]) + for (dy=[38, 38 + 89 + in2mm(30), depth-38-89]) + translate([dx + 38, dy + 89/2, 0]) + caster( + // wheel (r, h) + 38, 30, + // axel (r, h) + 5, 1, + // bearing (r, h) + 10, 1, + $fn=16 + ); +} + + +module worktop2() { + // 1:1mm to 1:1in because I want to consume this model in the 1:1in garage sketch + scale([1/25.4, 1/25.4, 1/25.4]) { + bench(in2mm(32), in2mm(96), in2mm(40), in2mm(0.75)); + } +} + +worktop2(); \ No newline at end of file diff --git a/projects/public-dns/BUILD b/projects/public-dns/BUILD index 06bf1bf..e793e88 100644 --- a/projects/public-dns/BUILD +++ b/projects/public-dns/BUILD @@ -1,6 +1,7 @@ zapp_binary( name = "updater", main = "src/python/arrdem/updater/__main__.py", + shebang = "/usr/bin/env python3", imports = [ "src/python", ], diff --git a/projects/shoggoth/DOC.md b/projects/shoggoth/DOC.md new file mode 100644 index 0000000..c80ac78 --- /dev/null +++ b/projects/shoggoth/DOC.md @@ -0,0 +1,212 @@ +# "Documentation" + +## Ichor ISA + +### TRUE +```() -> (bool)``` + +Push the constant TRUE onto the stack. + +### FALSE +```() -> (bool)``` + +Push the constant FALSE onto the stack. + +### IF +```(bool) -> ()``` + +Branch to another point if the top item of the stack is TRUE. Otherwise fall through. + +Note that not, and, or, xor etc. can all be user or prelude defined functions given if. + +### GOTO +```() -> ()``` + +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. + +### DUP +```(A, B, ...) -> (A, B, A, B, ...)``` + +Duplicate the top N items of the stack. + +### ROT +```(A, B, ..., Z) -> (Z, A, B, ...)``` + +Rotate the top N elements of the stack by 1. + +FIXME: What if you want to rotate by more than 1? + +### DROP +```(...: n, ...) -> (...)``` + +Drop the top N items of the stack. + +### SLOT +```(..., A) -> (A, ..., A)``` + +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 locals for reused values. + +### IDENTIFIERC +```() -> (IDENTIFIER)``` + +An inline constant which produces an identifier to the stack. + +Identifiers name functions, fields and types but are not strings. +They are a VM-internal naming structure with reference to the module. + +#### Function identifiers + +Function identifiers are written `;;;`. + +For example the signature of `not` is `;not;bool;bool`. +Note that this name scheme allows for `;or;bool,bool;bool` and `;or;bool,bool,bool;bool` to co-exist simultaneously, and for overloading of names with type variables. + +One could also have written `or` as `T;or;,T,T;T` if one were able to provide a truly generic test + +This design is a deliberate reaction to the JVM which does not permit such name-overloading and is intended to enable semi-naive compilation of complex generic operations without munging or erasure. + +#### Type identifiers + +Type identifiers are written `;;` + +For example the signature of `bool` is `;bool;,` + +As with functions, this allows for generic overloading of names. +For example one could define `tuple` as `;tuple;`, `A;tuple;`, `A,B;tuple;`, and soforth simultaneously. + +### FUNREF +```(IDENTIFIER) -> ()``` + +Note that `;` ends a list here the arguments list and should be read as `to`. + +Construct a reference to a static codepoint. + +### CALLF +```(, ... A) -> (... B)``` + +Call [funref] + +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. + +Executing a `CALL` pushes the name and module path of the current function. + +### RETURN +```(...) -> ()``` + +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. + +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. + + +### CLOSUREF +```(FUNREF, A) -> (CLOSURE<... B; ... C>)``` + +Construct a closure over the function reference at the top of the stack. This may produce nullary closures. + +### CLOSUREC +```(CLOSURE, A) -> (CLOSURE<... B; ... C>)``` + +Further close over the closure at the top of the stack. This may produce nullary closures. + +### CALLC +```(CLOSURE<... A; .. B>, ... A) -> (... B)``` + +Call [closure] + +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. + +Executing a `CALL` pushes the name and module path of the current function. + +### TYPEREF +```(IDENTIFIER) -> (TYPEREF)``` + +Produces a TYPEREF to the type named by the provided IDENTIFIER. + +### FIELDREF +```(IDENTIFIER, TYPEREF) -> (FIELDREF)``` + + +Produces a FIELDREF to the field named by the provided IDENTIFIER. +The FIELDREF must be within and with reference to a sum type. + +### VARIANTREF +```(IDENTIFIER, TYPEREF) -> (VARIANTREF)``` + +Produce a VARIANTREF to an 'arm' of the given variant type. + +### STRUCT +```(STRUCTREF, ...) -> (S)``` + +Consume the top N items of the stack, producing a struct of the type `structref`. + +The name and module path of the current function MUST match the name and module path of `structref`. +The arity of this opcode MUST match the arity of the struct. +The signature of the struct MUST match the signature fo the top N of the stack. + +### FLOAD +```(FIELDREF, S) -> (T)``` +Consume the struct reference at the top of the stack, producing the value of the referenced field. + +### FSTORE +```(FIELDREF, S, T) -> (S)``` + +Consume the struct reference at the top of the stack and a value, producing a new copy of the struct in which +that field has been updated to the new value. + +### VARIANT +```(VARIANTREF, ...) -> (B)``` + +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 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. + +### VTEST +```(VARIANTREF, B) -> (bool)``` + +Test whether B is a given arm of a variant A . + +### VLOAD +```(VARIANTREF, B) -> (A)``` + +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. + +### ARRAY +```(TYPEREF, ... ∈ Y) -> (ARRAY)``` + +Consume the top N items of the stack, producing an array of the type `typeref`. + +### ALOAD +```(ARRAY, NAT) -> (T)``` + +Consume a reference to an array and an index, producing the value at that index. + +FIXME: Or a signal/fault. + +### ASTORE +```(ARRAY, NAT, T) -> (ARRAY)``` + +Consume a value T, storing it at an index in the given array. +Produces the updated array as the top of stack. + +### BREAK +Abort the interpreter + +## Appendix + +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 diff --git a/projects/shoggoth/README.md b/projects/shoggoth/README.md index 0c083bc..2a1d082 100644 --- a/projects/shoggoth/README.md +++ b/projects/shoggoth/README.md @@ -4,9 +4,49 @@ > > ~ Charlie Stross, "A Colder War" -Shoggoth is a language designed to provide highly durable, portable agents. +> The greatest performance improvement of all is when a system goes from not-working to working. +> +> ~ John Ousterhout -Shoggoth runs atop a custom platform named Ichor, which aims to trivialize providing these properties. +Shoggoth is a language designed to provide highly durable, portable processes. +Much like Eve, it's intended to be an experiment at enabling classes of programs and making some hard things easier. + +Shoggoth runs atop a custom platform named Ichor, which aims to trivialize providing these properties and help the implementer focus by eliminating context. + +## Ichor + +The Ichor virtual machine is a toy. +The implementation presented here is merely as an experimental platform providing a "clean slate" target for compilation. +Ichor should be somewhat familiar to students of JVM bytecode, Fourth or UXN but has different priorities. + +Ichor is perhaps best explained as a reaction to the JVM. +To be clear, the JVM is an incredible success story. +But it has some decisions baked in that can't be walked back, such as the existence of `Object.equals()` and the primacy of classes for structuring both data and code. + +Ichor exists because it's much easier to define "snapshotting" the state of a flat loop bytecode interpreter with a stack than a recursive interpreter. +The objectives of building durable and portable processes/actors in Shoggoth requires the ability to take a snapshot of program state and persist it to a shared store for REMOTE or EVENTUAL resumption. +Think call/cc except with suspend or await happening across a network and database and scheduler boundary. + +Like the JVM, Ichor is a high-level 'struct' or 'object' oriented VM. +Unlike the JVM which provides generics by using type erasure founded on casts and a shared bottom type (`Object`), Ichor has no `null` or ⊥ type. +Ichor has only user-defined closed variant types and structs without inheritance or methods. + +Unlike the JVM, Ichor names "functions" and "types" including their generic parameters. +This allows for pervasive name overloading on both argument and return signature without the need for renaming or munging. + +Unlike the JVM, Ichor does not make mutability readily available. +There is no concept of a mutable local value, or of a mutable variant or struct. +"Place oriented programming" can be achieved only through explicit use of a mutable reference type which cannot be defined by the user. +This is a bet that a platform founded on pervasive forwarding of immutability can prove viable. +It may not pan out. + +Unlike most VMs, Ichor makes no effort to make user-defined C extensions easy. +They're likely to remain difficult-to-impossible as they conflict directly with other design priorities. + +## Shoggoth + +The Shoggoth language is an ML in Lisp's clothing. +While notationally a Lisp due entirely to the implementer's preference, Shoggoth has far more in common with an ML or other statically and generically typed language than with a unityped Lisp or interpreted language. ## License diff --git a/projects/shoggoth/src/python/ichor/bootstrap.py b/projects/shoggoth/src/python/ichor/bootstrap.py index e81bf7d..027d295 100644 --- a/projects/shoggoth/src/python/ichor/bootstrap.py +++ b/projects/shoggoth/src/python/ichor/bootstrap.py @@ -146,17 +146,10 @@ XOR3 = BOOTSTRAP.define_function( ] ) -TRUE = BOOTSTRAP.define_type( - "true", - ProductExpr([]), -) - -FALSE = BOOTSTRAP.define_type( - "false", - ProductExpr([]), -) - BOOL = BOOTSTRAP.define_type( - "bool", - SumExpr([TRUE, FALSE]) + ";bool", + { + ";true;": [], + ";false;": [], + }, ) diff --git a/projects/shoggoth/src/python/ichor/isa.py b/projects/shoggoth/src/python/ichor/isa.py index 3f9430e..0b5c72b 100644 --- a/projects/shoggoth/src/python/ichor/isa.py +++ b/projects/shoggoth/src/python/ichor/isa.py @@ -192,15 +192,6 @@ class Opcode: """ - class FIELDREF(t.NamedTuple): - """(IDENTIFIER, TYPEREF) -> (FIELDREF) - - - Produces a FIELDREF to the field named by the provided IDENTIFIER. - The FIELDREF must be within and with reference to a sum type. - - """ - class VARIANTREF(t.NamedTuple): """(IDENTIFIER, TYPEREF) -> (VARIANTREF) @@ -208,37 +199,6 @@ class Opcode: """ - class STRUCT(t.NamedTuple): - """(STRUCTREF, ...) -> (S) - - Consume the top N items of the stack, producing a struct of the type `structref`. - - The name and module path of the current function MUST match the name and module path of `structref`. - The arity of this opcode MUST match the arity of the struct. - The signature of the struct MUST match the signature fo the top N of the stack. - """ - - nargs: int = 0 - - class FLOAD(t.NamedTuple): - """(FIELDREF, S) -> (T) - - Consume the struct reference at the top of the stack, producing the value of the referenced field. - - """ - - fieldref: str - - class FSTORE(t.NamedTuple): - """(FIELDREF, S, T) -> (S) - - Consume the struct reference at the top of the stack and a value, producing a new copy of the struct in which - that field has been updated to the new value. - - """ - - fieldref: str - class VARIANT(t.NamedTuple): """(VARIANTREF, ...) -> (B) @@ -268,50 +228,8 @@ class Opcode: """ - #################################################################################################### - # Arrays - #################################################################################################### - class ARRAY(t.NamedTuple): - """(*) -> (ARRAY) - - Consume the top N items of the stack, producing an array of the type `typeref`. - - """ - - typeref: str - nargs: int - - class ALOAD(t.NamedTuple): - """(ARRAY, NAT) -> (T) - - Consume a reference to an array and an index, producing the value at that index. - - FIXME: Or a signal/fault. - - """ - - class ASTORE(t.NamedTuple): - """(ARRAY, NAT, T) -> (ARRAY) - - Consume a value T, storing it at an index in the given array. - Produces the updated array as the top of stack. - - """ - - #################################################################################################### - # Naturals - #################################################################################################### - - #################################################################################################### - # Integers - #################################################################################################### - - #################################################################################################### - # Ratios - #################################################################################################### - - class BREAK(t.NamedTuple): + """Abort the interpreter.""" pass @@ -347,10 +265,6 @@ class Module(t.NamedTuple): return i def define_function(self, name, opcodes): - # FIXME: This is way way WAAAAAAY too minimal. Lots of other stuff goes on a "function." - # For instance how to install handlers? - # How to consume capabilities? - try: sig = FunctionRef.parse(name) assert sig.name @@ -364,8 +278,8 @@ class Module(t.NamedTuple): return name def define_type(self, name, signature): - # FIXME: What in TARNATION is this going to do - pass + self.types[name] = signature + return name def __str__(self): b = []