[NO TESTS] WIP
This commit is contained in:
parent
13355aeef4
commit
56b6ddd3ea
12 changed files with 264 additions and 57 deletions
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
printer_rack();
|
||||
echo(prusa);
|
|
@ -7,5 +7,6 @@ py_project(
|
|||
],
|
||||
lib_deps = [
|
||||
py_requirement("lark"),
|
||||
py_requirement("flask"),
|
||||
],
|
||||
)
|
||||
|
|
5
projects/shogoth/src/python/shogoth/analyzer/__init__.py
Normal file
5
projects/shogoth/src/python/shogoth/analyzer/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""A syntax analyzer for Shogoth."""
|
||||
|
||||
from .impl import *
|
135
projects/shogoth/src/python/shogoth/analyzer/impl.py
Normal file
135
projects/shogoth/src/python/shogoth/analyzer/impl.py
Normal 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)})")
|
|
@ -1,6 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from .impl import Reader
|
||||
|
||||
|
||||
__all__ = ["Reader"]
|
||||
from .impl import *
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
26
projects/shogoth/src/python/shogoth/server/impl.py
Normal file
26
projects/shogoth/src/python/shogoth/server/impl.py
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue