Knock together a quick REPL
This commit is contained in:
parent
8e72dcd64f
commit
2943bd02e1
3 changed files with 78 additions and 10 deletions
8
setup.py
8
setup.py
|
@ -24,9 +24,13 @@ setup(
|
|||
packages=[
|
||||
"flowmetal",
|
||||
],
|
||||
scripts=[
|
||||
],
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'iflow=flowmetal.repl:main'
|
||||
],
|
||||
},
|
||||
install_requires=[
|
||||
'prompt-toolkit~=3.0.0',
|
||||
],
|
||||
extras_require={
|
||||
}
|
||||
|
|
|
@ -216,16 +216,21 @@ class Parser(SexpParser):
|
|||
|
||||
@classmethod
|
||||
def parse(cls, f: PosTrackingBufferedReader):
|
||||
if f.peek() == "(":
|
||||
return cls.parse_list(f)
|
||||
elif f.peek() == "[":
|
||||
return cls.parse_sqlist(f)
|
||||
elif f.peek() == '"':
|
||||
return cls.parse_str(f)
|
||||
if not f.peek():
|
||||
raise SyntaxError(f"Got end of file ({f.pos()}) while parsing")
|
||||
elif cls.ispunct(f.peek()):
|
||||
if f.peek() == "(":
|
||||
return cls.parse_list(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()):
|
||||
return cls.parse_whitespace(f)
|
||||
elif f.peek() == ";":
|
||||
return cls.parse_comment(f)
|
||||
else:
|
||||
return cls.parse_symbol(f)
|
||||
|
||||
|
@ -258,6 +263,8 @@ class Parser(SexpParser):
|
|||
pos = rtb.pos()
|
||||
acc = []
|
||||
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))
|
||||
assert rtb.read() == closec # Discard the trailing delimeter
|
||||
return ctor(acc, str(rtb), pos)
|
||||
|
|
57
src/python/flowmetal/repl.py
Normal file
57
src/python/flowmetal/repl.py
Normal 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
|
Loading…
Reference in a new issue