Knock together a quick REPL

This commit is contained in:
Reid 'arrdem' McKenzie 2020-07-18 20:30:34 -06:00
parent 8e72dcd64f
commit 2943bd02e1
3 changed files with 78 additions and 10 deletions

View file

@ -24,9 +24,13 @@ setup(
packages=[ packages=[
"flowmetal", "flowmetal",
], ],
scripts=[ entry_points = {
], 'console_scripts': [
'iflow=flowmetal.repl:main'
],
},
install_requires=[ install_requires=[
'prompt-toolkit~=3.0.0',
], ],
extras_require={ extras_require={
} }

View file

@ -216,16 +216,21 @@ class Parser(SexpParser):
@classmethod @classmethod
def parse(cls, f: PosTrackingBufferedReader): def parse(cls, f: PosTrackingBufferedReader):
if f.peek() == "(": if not f.peek():
return cls.parse_list(f) raise SyntaxError(f"Got end of file ({f.pos()}) while parsing")
elif f.peek() == "[": elif cls.ispunct(f.peek()):
return cls.parse_sqlist(f) if f.peek() == "(":
elif f.peek() == '"': return cls.parse_list(f)
return cls.parse_str(f) elif f.peek() == "[":
return cls.parse_sqlist(f)
elif f.peek() == '"':
return cls.parse_str(f)
elif f.peek() == ";":
return cls.parse_comment(f)
else:
raise SyntaxError(f"Got unexpected punctuation {f.read()!r} at {f.pos()} while parsing")
elif cls.isspace(f.peek()): elif cls.isspace(f.peek()):
return cls.parse_whitespace(f) return cls.parse_whitespace(f)
elif f.peek() == ";":
return cls.parse_comment(f)
else: else:
return cls.parse_symbol(f) return cls.parse_symbol(f)
@ -258,6 +263,8 @@ class Parser(SexpParser):
pos = rtb.pos() pos = rtb.pos()
acc = [] acc = []
while f.peek() != closec: while f.peek() != closec:
if not f.peek():
raise SyntaxError(f"Got end of file ({f.pos()}) while parsing {openc!r}...{closec!r} starting at {pos}")
acc.append(cls.parse(rtb)) acc.append(cls.parse(rtb))
assert rtb.read() == closec # Discard the trailing delimeter assert rtb.read() == closec # Discard the trailing delimeter
return ctor(acc, str(rtb), pos) return ctor(acc, str(rtb), pos)

View file

@ -0,0 +1,57 @@
#!/usr/bin/env python3
import argparse
import logging
import sys
import pprint
from flowmetal.syntax_analyzer import analyzes
from prompt_toolkit import print_formatted_text, prompt, PromptSession
from prompt_toolkit.formatted_text import FormattedText
from prompt_toolkit.history import FileHistory
from prompt_toolkit.styles import Style
STYLE = Style.from_dict({
# User input (default text).
"": "",
"prompt": "ansigreen",
"time": "ansiyellow"
})
class InterpreterInterrupt(Exception):
"""An exception used to break the prompt or evaluation."""
parser = argparse.ArgumentParser()
def main():
"""REPL entry point."""
args = parser.parse_args(sys.argv[1:])
logger = logging.getLogger("arrdem.datalog")
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)
session = PromptSession(history=FileHistory(".datalog.history"))
line_no = 0
while True:
try:
line = session.prompt([("class:prompt", ">>> ")], style=STYLE)
except (InterpreterInterrupt, KeyboardInterrupt):
continue
except EOFError:
break
try:
pprint.pprint(analyzes(line, source_name=f"repl@{line_no}"))
except Exception as e:
print(e)
finally:
line_no += 1