[NO TESTS] WIP

This commit is contained in:
Reid D. 'arrdem' McKenzie 2022-05-31 09:36:47 -06:00
parent a65702be42
commit 65091be070
12 changed files with 264 additions and 57 deletions

View file

@ -2,6 +2,8 @@ use <steel-shelving.scad>
use <Z4M.scad>
use <tire-loft.scad>
use <printer-rack.scad>
use <worktop.scad>
use <worktop2.scad>
// Note 16" stud spacing
// Note 2.5" downgrade over run of garage; height to minimums
@ -136,9 +138,8 @@ translate([4, 232 - 37 - 1 - toolchest_size, 0]) {
//// worktop
let(tops=2)
translate([24 + 1, 232 - 1 - 37 - 1 - toolchest_size - 1- (48 * tops), 0]) {
rotate([0, 0, 90])
shelving(48 * tops, 24, 32, shelves=3);
translate([4, 232 - 1 - 37 - 1 - toolchest_size - 1- (48 * tops), 0]) {
worktop2();
label("Worktop", pos=[-12, (48*tops)/2, 32]);
}

View file

@ -1,14 +1,16 @@
use <box.scad>
use <casters.scad>
padding = 1.5;
function mm2in(x) = x * 0.0393701;
mdf_thickness = 0.75;
padding = mdf_thickness;
pin_inset = 3;
function padded(dims, padding) = [for(e=dims) e+padding];
// dimensions for things
prusa = padded([31.5, 31.5, 35.5], padding);
prusa = padded([mm2in(180 * 2 + 504), mm2in(115 + 660), mm2in(910)], padding);
cr10 = padded([19, 27, 25], padding);
repbox = padded([19, 12.5, 12.5], padding);
cart = [prusa.x, prusa.y, 6.75 + mdf_thickness];
@ -35,14 +37,15 @@ module printer_rack() {
translate([0, 0, 0])
cart();
//translate([0, 0, cart.z])
//box(prusa, mdf_thickness);
translate([0, 0, cart.z])
box(prusa, mdf_thickness);
translate([0, 0, cart.z + prusa.z])
box([prusa.x, prusa.y, repbox.z], mdf_thickness);
translate([0, 0, cart.z + repbox.z + mdf_thickness * 2])
translate([0, 0, cart.z + prusa.z + repbox.z + mdf_thickness * 2])
box([prusa.x, prusa.y, cr10.z], mdf_thickness);
}
printer_rack();
echo(prusa);

View file

@ -7,5 +7,6 @@ py_project(
],
lib_deps = [
py_requirement("lark"),
py_requirement("flask"),
],
)

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python3
"""A syntax analyzer for Shogoth."""
from .impl import *

View file

@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""The implementation of Shogoth's lexical analyzer."""
from abc import ABC
from dataclasses import dataclass
import typing as t
from shogoth.types import List, Vec, Keyword, Symbol
@dataclass
class Namespace:
name: Symbol
mappings: t.Mapping[Symbol, t.Any]
def resolve(self, name: Symbol) -> t.Optional[Symbol]:
if name in self.mappings:
return name.qualify(self.name.name)
def __contains__(self, item):
return item.namespace == self.name and item.unqualified() in self.mappings
def __getitem__(self, key: Symbol):
return self.mappings[key.unqualified()]
def get(self, key: Symbol, default=None):
if key in self:
return self[key]
else:
return default
class Expr(ABC):
pass
@dataclass
class ConstExpr(Expr):
val: t.Any
@dataclass
class ListExpr(Expr):
children: t.List[t.Any]
@dataclass
class MapExpr(Expr):
kvs: t.List[t.Tuple[t.Any, t.Any]]
@dataclass
class InvokeExpr(Expr):
target: Expr
args: t.List[Expr]
# FIXME: kwargs/star-args?
@dataclass
class IfExpr(Expr):
"""(if* test then else)"""
test: Expr
pos_branch: Expr
neg_branch: Expr
@dataclass
class LetExpr(Expr):
"""(let* [name binding name2 binding2] body)"""
bindings: t.List[t.Tuple[Symbol, Expr]]
body: Expr
@dataclass
class FnExpr(Expr):
"""(fn* args body)"""
args: t.List[Symbol]
body: Expr
BOOTSTRAP = "lang.shogoth.v0.bootstrap"
SPECIALS = Namespace(Symbol(BOOTSTRAP), {
Symbol("if*"): None,
Symbol("let*"): None,
Symbol("fn*"): None,
})
GLOBALS = Namespace(Symbol("lang.shogoth.v0.core"), {
})
# FIXME: This is really expand... isn't it.
class Analyzer:
def __init__(self, specials, globals):
self._specials = specials
self._globals = globals
def resolve(self, module, name: Symbol):
return module.resolve(name) or self._globals.resolve(name) or self._specials.resolve(name)
def analyze(self, module: Namespace, expr: t.Any):
def _analyze(e):
return self.analyze(module, e)
if isinstance(expr, (int, float, str, Keyword)):
return ConstExpr(expr)
if isinstance(expr, Vec):
return ListExpr([self.analyze(module, e) for e in expr])
if isinstance(expr, List) and len(expr) > 1 and isinstance(expr[0], Symbol):
if (target := self.resolve(module, expr[0])):
match target:
case Symbol("if*", BOOTSTRAP):
assert len(expr) == 4
return IfExpr(_analyze(expr[1]), _analyze(expr[2]), _analyze(expr[3]))
case Symbol("let*", BOOTSTRAP):
assert len(expr) == 3
return LetExpr([(name, _analyze(e)) for name, e in expr[1]], _analyze(expr[2]))
case Symbol("fn*", BOOTSTRAP):
assert len(expr) == 3
return FnExpr(expr[1], _analyze(expr[2]))
# FIXME: Macros go here? Or is macroexpansion separate?
case _:
return InvokeExpr(_analyze(target), [_analyze(e) for e in expr[1:]])
raise ValueError(f"Unable to analyze {expr!r} ({type(expr)})")

View file

@ -1,6 +1,3 @@
#!/usr/bin/env python3
from .impl import Reader
__all__ = ["Reader"]
from .impl import *

View file

@ -10,7 +10,7 @@ from typing import Any
from lark import Token, Tree
from shogoth.parser import parse
from shogoth.types import Keyword, Symbol
from shogoth.types import Keyword, Symbol, List, Vec
# Monkeypatching for py3.10 matching
@ -42,10 +42,10 @@ class Reader(object):
return self._read(children[0])
case Tree(Token("RULE", "plist"), children):
return [self._read(c) for c in children]
return List([self._read(c) for c in children])
case Tree(Token("RULE", "blist"), children):
return [self._read(c) for c in children]
return Vec([self._read(c) for c in children])
case Tree(Token("RULE", "mapping"), children):
return dict(self._read(c) for c in children)

View file

@ -1,7 +1,8 @@
"""A testing REPL."""
from shogoth.reader import Reader
from shogoth.types import Symbol
from shogoth.analyzer import Analyzer, SPECIALS, GLOBALS, Namespace
from prompt_toolkit import (
print_formatted_text,
@ -24,12 +25,16 @@ STYLE = Style.from_dict(
}
)
SPINNER = Spinner(["|", "/", "-", "\\"], 200)
SPINNER = Spinner("|/-\\", 200)
def main():
reader = Reader()
analyzer = Analyzer(SPECIALS, GLOBALS)
ns = Namespace(Symbol("user"), {})
session = PromptSession(history=FileHistory(".shogoth.history"))
while True:
try:
line = session.prompt([("class:prompt", ">>> ")], style=STYLE)
@ -40,9 +45,12 @@ def main():
with yaspin(SPINNER):
read = reader.read(line)
print(read, type(read))
with yaspin(SPINNER):
expr = analyzer.analyze(ns, read)
print('analyze ]', expr, type(expr))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,26 @@
#!/usr/bin/env python3
"""The implementation of a Shogoth evaluation server."""
import flask
app = flask.Flask(__name__)
@app.route("/api/v0/login", method=["POST"])
def login():
pass
@app.route("/api/v0/logout", method=["POST"])
def logout():
pass
@app.route("/api/v0/session", method=["GET"])
def get_session():
pass
@app.route("/api/v0/session", method=["POST"])
def make_session():
pass

View file

@ -4,37 +4,37 @@ from .keyword import Keyword
from .symbol import Symbol
from abc import ABC
from typing import NamedTuple, List, Mapping, Any
import typing as t
from uuid import UUID, uuid4
class TypeVariable(NamedTuple):
class TypeVariable(t.NamedTuple):
name: str
id: UUID = uuid4()
class ArrayExpr(NamedTuple):
child: Any
class ArrayExpr(t.NamedTuple):
child: t.Any
class SumExpr(NamedTuple):
children: List[Any]
class SumExpr(t.NamedTuple):
children: t.List[t.Any]
class ProductExpr(NamedTuple):
children: Mapping[str, Any]
class ProductExpr(t.NamedTuple):
children: t.Mapping[str, t.Any]
####################################################################################################
####################################################################################################
####################################################################################################
class Function(NamedTuple):
class Function(t.NamedTuple):
"""The type of a function; a subset of its signature."""
class FunctionRef(NamedTuple):
class FunctionRef(t.NamedTuple):
raw: str
type_params: list
name: str
@ -55,3 +55,18 @@ class FunctionRef(NamedTuple):
cls.parse_list(args),
cls.parse_list(ret)
)
class Closure(t.NamedTuple):
target: t.Union["Closure", FunctionRef]
args: t.List[t.Any]
# FIXME (arrdem 2022-05-30):
# Find a better name for this
class Vec(list):
pass
class List(list):
pass

View file

@ -1,5 +1,21 @@
from typing import NamedTuple
import typing as t
class Symbol(NamedTuple):
class Symbol(t.NamedTuple):
name: str
namespace: t.Optional[str] = None
def qualify(self, ns: str):
return Symbol(self.name, ns)
def unqualified(self):
if not self.namespace:
return self
else:
return Symbol(self.name)
def __str__(self):
if self.namespace:
return f"{self.namespace}/{self.name}"
else:
return self.name

View file

@ -127,7 +127,7 @@ class Opcode:
"""
class CALLC(NamedTuple):
"""(`CLOSURE<... A, ... B>`, ... A) -> (... B)
"""(`CLOSURE<... A to ... B>`, ... A) -> (... B)
Call [closure]
Make a dynamic call to the closure at the top of stack.
@ -139,32 +139,32 @@ class Opcode:
nargs: int = 0
# ####################################################################################################
# # Structures
# ####################################################################################################
# class STRUCT(NamedTuple):
# """(*) -> (T)
# 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`.
# """
#
# structref: str
# nargs: int
####################################################################################################
# Structures
####################################################################################################
class STRUCT(NamedTuple):
"""(*) -> (T)
Consume the top N items of the stack, producing a struct of the type `structref`.
# class FLOAD(NamedTuple):
# """(A) -> (B)
# Consume the struct reference at the top of the stack, producing the value of the referenced field.
# """
#
# fieldref: str
The name and module path of the current function MUST match the name and module path of `structref`.
"""
# class FSTORE(NamedTuple):
# """(A) -> (B)
# Consume the struct reference at the top of the stack, producing the value of the referenced field.
# """
#
# fieldref: str
structref: str
nargs: int
class FLOAD(NamedTuple):
"""(A) -> (B)
Consume the struct reference at the top of the stack, producing the value of the referenced field.
"""
fieldref: str
class FSTORE(NamedTuple):
"""(A) -> (B)
Consume the struct reference at the top of the stack, producing the value of the referenced field.
"""
fieldref: str
####################################################################################################
# Arrays