From dc888b5958ae4c9606da54eab6ec990fa8da6be3 Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Wed, 26 Oct 2022 22:23:41 -0600 Subject: [PATCH] WIP --- projects/shoggoth/BUILD | 7 +- projects/shoggoth/README.md | 2 +- .../shoggoth/src/python/ichor/__main__.py | 16 ++-- .../shoggoth/src/python/shoggoth/analyzer.py | 81 ++++++++++++------- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/projects/shoggoth/BUILD b/projects/shoggoth/BUILD index 22b3cf9..563d7bb 100644 --- a/projects/shoggoth/BUILD +++ b/projects/shoggoth/BUILD @@ -5,17 +5,20 @@ py_project( py_requirement("prompt_toolkit"), py_requirement("yaspin"), py_requirement("pyrsistent"), + py_requirement("flask"), ], lib_deps = [ py_requirement("lark"), py_requirement("flask"), + "//projects/anosql", + "//projects/anosql-migrations", ], ) zapp_binary( - name="ichor", + name ="ichor", main = "src/python/ichor/__main__.py", - shebang="/usr/bin/env python3", + shebang ="/usr/bin/env python3", deps = [ ":lib", ], diff --git a/projects/shoggoth/README.md b/projects/shoggoth/README.md index 2a1d082..c03b7c4 100644 --- a/projects/shoggoth/README.md +++ b/projects/shoggoth/README.md @@ -50,4 +50,4 @@ While notationally a Lisp due entirely to the implementer's preference, Shoggoth ## License -While the source for this project happens to be published no grant of rights is made. +While the source for this project happens to be published, no grant of rights or right to usage is made. diff --git a/projects/shoggoth/src/python/ichor/__main__.py b/projects/shoggoth/src/python/ichor/__main__.py index f74cd07..db49042 100644 --- a/projects/shoggoth/src/python/ichor/__main__.py +++ b/projects/shoggoth/src/python/ichor/__main__.py @@ -4,23 +4,21 @@ ichor entrypoint """ -from . import ( +from ichor.bootstrap import ( BOOTSTRAP, - Interpreter, NOT1, - Opcode, TRUE, ) +from ichor import isa +from ichor.interpreter import Interpreter def main(): vm = Interpreter(BOOTSTRAP) - ret = vm.run([ - Opcode.IDENTIFIERC(NOT1), - Opcode.FUNREF(), - Opcode.CALLF(1), - Opcode.RETURN(1) - ], stack = [TRUE]) + ret = vm.run( + [isa.IDENTIFIERC(NOT1), isa.FUNREF(), isa.CALLF(1), isa.RETURN()], + stack=[TRUE], + ) print(ret) diff --git a/projects/shoggoth/src/python/shoggoth/analyzer.py b/projects/shoggoth/src/python/shoggoth/analyzer.py index 11e660e..d11a985 100644 --- a/projects/shoggoth/src/python/shoggoth/analyzer.py +++ b/projects/shoggoth/src/python/shoggoth/analyzer.py @@ -9,28 +9,6 @@ import typing as t from shoggoth.types import Keyword, List, 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 @@ -79,8 +57,43 @@ class FnExpr(Expr): body: Expr +# Related reading - +# - http://www-formal.stanford.edu/jmc/elephant/elephant.html +# - https://www.cs.utah.edu/plt/scope-sets/ +# +# FIXME: Do I make the multiverse directly durable? Or does that live elsewhere? +@dataclass +class Multiverse: + """A namespace with branches. + + We can think about a universe or multiverse of program states as existing within histories of names and evaluations. + + When we evaluate a form, four things can happen: + - We can do program effects (I/O, generate heat, consume time) + - Produce a value (returned or raised/thrown error) + - Produce definition(s) with which other evaluation will occur + - Produce context with which other evaluation will occur + + In a sense, there exists a 'multiverse' of naming into which all top level values are entered. + + Each alteration to the 'multiverse' produces a new 'universe' of names - you could call this a fork or session - + which maps a name in that universe to a value in the multiverse. + + A universe is a sequential or causal history. + Traveling backwards in time and deviating produces a different universe. + Truncating or discarding that history produces a different although in some sense equivalent universe. + + """ + + soup: t.Dict[] + + @dataclass + class Namespace: + pass + + BOOTSTRAP = "lang.shoggoth.v0.bootstrap" -SPECIALS = Namespace(Symbol(BOOTSTRAP), { +SPECIALS = Multiverse.Namespace(Symbol(BOOTSTRAP), { Symbol("if*"): None, # FIXME: This isn't really if anymore, it's MATCH or TEST. Something. Unless bool is in bootstrap. Symbol("let*"): None, Symbol("fn*"): None, @@ -100,21 +113,35 @@ class Analyzer: def resolve(self, module, name: Symbol): return module.resolve(name) or self._globals.resolve(name) or self._specials.resolve(name) + def macroexpand1(self, module, form): + """macroexpand¹""" + + def macroexpand(self, module, form): + """Perform macroexpansion.""" + def analyze(self, module: Namespace, expr: t.Any): + """Perform analysis, of which macroexpansion is part.""" def _analyze(e): return self.analyze(module, e) match expr: - case int() | float() | str(): + case int() | float() | str() | Keyword(): return ConstExpr(expr) - case Keyword(): - raise ValueError() + case Symbol(): + return ConstExpr(expr) case List() if len(expr) > 1 and isinstance(expr[0], Symbol): + expr = self.macroexpand(module, expr) if (target := self.resolve(module, expr[0])): match target: + # FIXME: Macros go here? Or is macroexpansion separate? + # Macroexpansion needs to go here + + # in-ns or equivalent needs to go here + # ns / module needs to go here + case Symbol("if*", BOOTSTRAP): assert len(expr) == 4 return IfExpr(_analyze(expr[1]), _analyze(expr[2]), _analyze(expr[3])) @@ -127,8 +154,6 @@ class Analyzer: assert len(expr) == 3 return FnExpr(expr[1], _analyze(expr[2])) - # FIXME: Macros go here? Or is macroexpansion separate? - case _: pass