From df9aae1253ed415ade3a2b59e8a0996ff659543d Mon Sep 17 00:00:00 2001 From: "Reid D. 'arrdem' McKenzie" Date: Sun, 9 Jan 2022 16:32:11 -0700 Subject: [PATCH] Reader's 'done' --- .../shogoth/src/python/shogoth/parser/impl.py | 9 ++-- .../src/python/shogoth/reader/__init__.py | 1 + .../shogoth/src/python/shogoth/reader/impl.py | 54 +++++++++++++------ .../src/python/shogoth/repl/__main__.py | 2 - .../src/python/shogoth/types/__init__.py | 7 +++ .../src/python/shogoth/types/keyword.py | 5 ++ .../src/python/shogoth/types/symbol.py | 5 ++ 7 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 projects/shogoth/src/python/shogoth/types/__init__.py create mode 100644 projects/shogoth/src/python/shogoth/types/keyword.py create mode 100644 projects/shogoth/src/python/shogoth/types/symbol.py diff --git a/projects/shogoth/src/python/shogoth/parser/impl.py b/projects/shogoth/src/python/shogoth/parser/impl.py index 5945007..693105d 100644 --- a/projects/shogoth/src/python/shogoth/parser/impl.py +++ b/projects/shogoth/src/python/shogoth/parser/impl.py @@ -15,22 +15,19 @@ mapping: "{" kv* "}" kv: expr expr quote: "'" expr -atom: KEYWORD | PATTERN | INT | FLOAT | STRING | true | false | nil | SYMBOL +atom: KEYWORD | PATTERN | INT | FLOAT | STRING | TRUE | FALSE | NIL | SYMBOL KEYWORD: ":" SYMBOL SYMBOL: /[^(){}#'"\s]+/ +// FIXME: These two don't deal with escapes correctly at all 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 @@ -39,6 +36,6 @@ INT: /[+-]?[0-9]+/ def parse(input: str) -> Any: - """Parse a string using the shogoth (lisp) gramar, returning an unmodified tree.""" + '''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 index a2bc282..0f5eb24 100644 --- a/projects/shogoth/src/python/shogoth/reader/__init__.py +++ b/projects/shogoth/src/python/shogoth/reader/__init__.py @@ -2,4 +2,5 @@ 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 index a4b72f6..7b465c6 100644 --- a/projects/shogoth/src/python/shogoth/reader/impl.py +++ b/projects/shogoth/src/python/shogoth/reader/impl.py @@ -1,11 +1,19 @@ """The shogoth reader.""" +import re from typing import Any -from shogoth.parser import parse -from lark import Tree, Token -from lark import Lark, Transformer, v_args +from lark import ( + Lark, + Token, + Transformer, + Tree, + v_args, +) +from shogoth.parser import parse +from shogoth.types import Keyword, Symbol + # Monkeypatching for py3.10 matching Tree.__match_args__ = ("data", "children") @@ -22,41 +30,57 @@ class Reader(object): return parse(buffer) def symbol(self, x): - return ["read-eval", ["symbol", x]] + return Symbol(x) def keyword(self, x): - return ["read-eval", ["keyword", x]] + return Keyword(x) + + def pattern(self, x): + return re.compile(x[1:-1].replace("\\/", "/")) def _read(self, tree: Tree) -> Any: match tree: - case Tree(Token('RULE', 'expr'), children): + case Tree(Token("RULE", "expr"), children): return self._read(children[0]) - case Tree(Token('RULE', 'plist'), children): + case Tree(Token("RULE", "plist"), children): return [self._read(c) for c in children] - case Tree(Token('RULE', 'blist'), children): + case Tree(Token("RULE", "blist"), children): return [self._read(c) for c in children] - case Tree(Token('RULE', 'mapping'), children): + case Tree(Token("RULE", "mapping"), children): return dict(self._read(c) for c in children) - case Tree(Token('RULE', 'kv'), [k, v]): + case Tree(Token("RULE", "kv"), [k, v]): return (self._read(k), self._read(v)) - case Tree(Token('RULE', 'atom'), [a]): + case Tree(Token("RULE", "atom"), [a]): return self._read(a) - case Token('INT', x): + case Token("INT", x): return int(x) - case Token('FLOAT', x): + case Token("FLOAT", x): return float(x) - case Token('KEYWORD', x): + case Token("KEYWORD", x): return self.keyword(x) - case Token('SYMBOL', x): + case Token("PATTERN", x): + return self.pattern(x) + + case Token("TRUE", _): + return True + + case Token("FALSE", _): + return False + + case Token("NIL", _): + return None + + # Symbol is very much the catch-all of the grammar + case Token("SYMBOL", x): return self.symbol(x) case _: diff --git a/projects/shogoth/src/python/shogoth/repl/__main__.py b/projects/shogoth/src/python/shogoth/repl/__main__.py index f1e668b..c5e7305 100644 --- a/projects/shogoth/src/python/shogoth/repl/__main__.py +++ b/projects/shogoth/src/python/shogoth/repl/__main__.py @@ -1,8 +1,6 @@ """A testing REPL.""" -import sys -from shogoth.parser import parse from shogoth.reader import Reader diff --git a/projects/shogoth/src/python/shogoth/types/__init__.py b/projects/shogoth/src/python/shogoth/types/__init__.py new file mode 100644 index 0000000..a4e1c4b --- /dev/null +++ b/projects/shogoth/src/python/shogoth/types/__init__.py @@ -0,0 +1,7 @@ +"""The public interface for shogoth's baked-in types.""" + +from .keyword import Keyword +from .symbol import Symbol + + +__all__ = ["Keyword", "Symbol"] diff --git a/projects/shogoth/src/python/shogoth/types/keyword.py b/projects/shogoth/src/python/shogoth/types/keyword.py new file mode 100644 index 0000000..da154b2 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/types/keyword.py @@ -0,0 +1,5 @@ +from .symbol import Symbol + + +class Keyword(Symbol): + pass diff --git a/projects/shogoth/src/python/shogoth/types/symbol.py b/projects/shogoth/src/python/shogoth/types/symbol.py new file mode 100644 index 0000000..19b3709 --- /dev/null +++ b/projects/shogoth/src/python/shogoth/types/symbol.py @@ -0,0 +1,5 @@ +from typing import NamedTuple + + +class Symbol(NamedTuple): + name: str