This commit is contained in:
Reid 'arrdem' McKenzie 2022-10-26 22:23:41 -06:00
parent d102083a64
commit 8737b7456b
4 changed files with 66 additions and 40 deletions

View file

@ -5,10 +5,13 @@ 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",
],
)

View file

@ -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.

View file

@ -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)

View file

@ -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