Initial parse/read driver REPL

This commit is contained in:
Reid D. 'arrdem' McKenzie 2022-01-09 14:46:21 -07:00
parent 3dbb810074
commit 7cc79e5986
9 changed files with 178 additions and 0 deletions

35
projects/shogoth/BUILD Normal file
View file

@ -0,0 +1,35 @@
py_library(
name = "lib",
srcs = glob(["src/python/**/*"]),
imports = [
"src/python"
],
deps = [
py_requirement("lark"),
],
)
zapp_binary(
name = "shogothd",
main = "src/python/shogoth/server/__main__.py",
deps = [
":lib",
],
)
zapp_binary(
name = "shogoth",
main = "src/python/shogoth/client/__main__.py",
deps = [
":lib",
],
)
zapp_binary(
name = "repl",
main = "src/python/shogoth/repl/__main__.py",
shebang = "/usr/bin/env python3.10",
deps = [
":lib",
]
)

View file

@ -0,0 +1,9 @@
# Shogot'im
> "The shoggot'im, they're called: servitors. There are several kinds of advanced robotic systems made out of molecular components: they can change shape, restructure material at the atomic level -- act like corrosive acid, or secrete diamonds. Some of them are like a tenuous mist -- what Doctor Drexler at MIT calls a utility fog -- while others are more like an oily globule. Apparently they may be able to manufacture more of themselves, but they're not really alive in any meaning of the term we're familiar with. They're programmable, like robots, using a command language deduced from recovered records of the forerunners who left them here. The Molotov Raid of 1930 brought back a large consignment of them; all we have to go on are the scraps they missed, and reports by the Antarctic Survey. Professor Liebkunst's files in particular are most frustrating --''
>
> ~ Charlie Stross, "A Colder War"
## License
While the source for this project happens to be published no grant of rights is made.

View file

@ -0,0 +1,6 @@
"""Published interface to the shogoth parser."""
from .impl import parse
__all__ = ["parse"]

View file

@ -0,0 +1,44 @@
"""A quick and dirty parser for Shogoth."""
from typing import Any
from lark import Lark
PARSER = Lark('''\
start: expr
expr: plist | blist | mapping | quote | atom
plist: "(" expr* ")" // paren list
blist: "[" expr* "]" // brackets list
mapping: "{" kv* "}"
kv: expr expr
quote: "'" expr
atom: KEYWORD | PATTERN | INT | FLOAT | STRING | true | false | nil | SYMBOL
KEYWORD: ":" SYMBOL
SYMBOL: /[^(){}#'"\s]+/
STRING: /".*?"/
PATTERN: /\/.*?\//
true: TRUE
TRUE: /true/
false: FALSE
FALSE: /false/
nil: NIL
NIL: /nil/
INT: /[+-]?[0-9]+/
%import common.WORD // imports from terminal library
%import common.FLOAT // float
%ignore " " // Disregard spaces in text
%ignore "," // Treat commas as whitespace
%ignore /;.*/ // Disregard comments
''', start=["expr"])
def parse(input: str) -> Any:
"""Parse a string using the shogoth (lisp) gramar, returning an unmodified tree."""
return PARSER.parse(input)

View file

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

View file

@ -0,0 +1,66 @@
"""The shogoth reader."""
from typing import Any
from shogoth.parser import parse
from lark import Tree, Token
from lark import Lark, Transformer, v_args
# Monkeypatching for py3.10 matching
Tree.__match_args__ = ("data", "children")
Token.__match_args__ = ("type", "value")
class Reader(object):
"""An extension of parsing that produces meaningful trees. Can be extended with userland hooks."""
def __init__(self):
pass
def _parse(self, buffer):
return parse(buffer)
def symbol(self, x):
return ["read-eval", ["symbol", x]]
def keyword(self, x):
return ["read-eval", ["keyword", x]]
def _read(self, tree: Tree) -> Any:
match tree:
case Tree(Token('RULE', 'expr'), children):
return self._read(children[0])
case Tree(Token('RULE', 'plist'), children):
return [self._read(c) for c in children]
case Tree(Token('RULE', 'blist'), children):
return [self._read(c) for c in children]
case Tree(Token('RULE', 'mapping'), children):
return dict(self._read(c) for c in children)
case Tree(Token('RULE', 'kv'), [k, v]):
return (self._read(k), self._read(v))
case Tree(Token('RULE', 'atom'), [a]):
return self._read(a)
case Token('INT', x):
return int(x)
case Token('FLOAT', x):
return float(x)
case Token('KEYWORD', x):
return self.keyword(x)
case Token('SYMBOL', x):
return self.symbol(x)
case _:
return tree
def read(self, buffer):
return self._read(self._parse(buffer))

View file

@ -0,0 +1,13 @@
"""A testing REPL."""
import sys
from shogoth.parser import parse
from shogoth.reader import Reader
if __name__ == "__main__":
reader = Reader()
while (line := input(">>> ")):
read = reader.read(line)
print(read, type(read))