From 0b7b67b7972abf0e6dcacdc79e21efb751d26dfe Mon Sep 17 00:00:00 2001 From: "Reid D. 'arrdem' McKenzie" Date: Sun, 9 Jan 2022 14:46:21 -0700 Subject: [PATCH] Initial parse/read driver REPL --- projects/shogoth/BUILD | 35 ++++++++++ projects/shogoth/README.md | 9 +++ .../src/python/shogoth/client/__main__.py | 0 .../src/python/shogoth/parser/__init__.py | 6 ++ .../shogoth/src/python/shogoth/parser/impl.py | 44 +++++++++++++ .../src/python/shogoth/reader/__init__.py | 5 ++ .../shogoth/src/python/shogoth/reader/impl.py | 66 +++++++++++++++++++ .../src/python/shogoth/repl/__main__.py | 13 ++++ .../src/python/shogoth/server/__main__.py | 0 9 files changed, 178 insertions(+) create mode 100644 projects/shogoth/BUILD create mode 100644 projects/shogoth/README.md create mode 100644 projects/shogoth/src/python/shogoth/client/__main__.py create mode 100644 projects/shogoth/src/python/shogoth/parser/__init__.py create mode 100644 projects/shogoth/src/python/shogoth/parser/impl.py create mode 100644 projects/shogoth/src/python/shogoth/reader/__init__.py create mode 100644 projects/shogoth/src/python/shogoth/reader/impl.py create mode 100644 projects/shogoth/src/python/shogoth/repl/__main__.py create mode 100644 projects/shogoth/src/python/shogoth/server/__main__.py diff --git a/projects/shogoth/BUILD b/projects/shogoth/BUILD new file mode 100644 index 0000000..5159119 --- /dev/null +++ b/projects/shogoth/BUILD @@ -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", + ] +) diff --git a/projects/shogoth/README.md b/projects/shogoth/README.md new file mode 100644 index 0000000..023566c --- /dev/null +++ b/projects/shogoth/README.md @@ -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. diff --git a/projects/shogoth/src/python/shogoth/client/__main__.py b/projects/shogoth/src/python/shogoth/client/__main__.py new file mode 100644 index 0000000..e69de29 diff --git a/projects/shogoth/src/python/shogoth/parser/__init__.py b/projects/shogoth/src/python/shogoth/parser/__init__.py new file mode 100644 index 0000000..f3ab289 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/parser/__init__.py @@ -0,0 +1,6 @@ +"""Published interface to the shogoth parser.""" + +from .impl import parse + + +__all__ = ["parse"] diff --git a/projects/shogoth/src/python/shogoth/parser/impl.py b/projects/shogoth/src/python/shogoth/parser/impl.py new file mode 100644 index 0000000..5945007 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/parser/impl.py @@ -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) diff --git a/projects/shogoth/src/python/shogoth/reader/__init__.py b/projects/shogoth/src/python/shogoth/reader/__init__.py new file mode 100644 index 0000000..a2bc282 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/reader/__init__.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 + +from .impl import Reader + +__all__ = ["Reader"] diff --git a/projects/shogoth/src/python/shogoth/reader/impl.py b/projects/shogoth/src/python/shogoth/reader/impl.py new file mode 100644 index 0000000..a4b72f6 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/reader/impl.py @@ -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)) diff --git a/projects/shogoth/src/python/shogoth/repl/__main__.py b/projects/shogoth/src/python/shogoth/repl/__main__.py new file mode 100644 index 0000000..f1e668b --- /dev/null +++ b/projects/shogoth/src/python/shogoth/repl/__main__.py @@ -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)) diff --git a/projects/shogoth/src/python/shogoth/server/__main__.py b/projects/shogoth/src/python/shogoth/server/__main__.py new file mode 100644 index 0000000..e69de29