82 lines
2.0 KiB
Python
82 lines
2.0 KiB
Python
from .meta import print_version
|
|
from .lexer import LexerInfo, lexical_analysis
|
|
from .interpreter import InterpreterState
|
|
|
|
|
|
REPL_FILE_NAME = "<STDIN>"
|
|
|
|
|
|
def print_top_of_stack(interpreter: InterpreterState) -> None:
|
|
"""Pretty-print top of the stack."""
|
|
|
|
item = interpreter.top()
|
|
if item is None:
|
|
print("#0: <STACK IS EMPTY>")
|
|
return
|
|
|
|
t = item.type
|
|
|
|
if t == "Identifier":
|
|
print(f"#0: ::{item.value}")
|
|
elif t in {"i64", "i32", "i16", "i8"}:
|
|
print(f"#0: {item.value}:{t}")
|
|
elif t in {"u64", "u32", "u16", "u8"}:
|
|
print(f"#0: {item.value}:{t}")
|
|
elif t == "f32":
|
|
print(f"#0: {item.value}:f32")
|
|
elif t == "f64":
|
|
print(f"#0: {item.value}")
|
|
elif t == "char":
|
|
print(f"#0: {item.value}")
|
|
elif t == "bool":
|
|
print("#0: TRUE" if item.value else "#0: FALSE")
|
|
elif t == "TokenString":
|
|
print("#0: <TOKEN STRING>")
|
|
elif t == "Callable":
|
|
print("#0: <CALLABLE>")
|
|
else:
|
|
print(f"#0: <UNKNOWN {t}>")
|
|
|
|
|
|
def repl() -> int:
|
|
"""Interactive interpreter loop."""
|
|
|
|
print_version()
|
|
print("===== YREA SLS REPL =====")
|
|
print("Type `#exit` to exit.")
|
|
|
|
interpreter = InterpreterState()
|
|
|
|
while True:
|
|
try:
|
|
line = input("> ")
|
|
except EOFError:
|
|
break
|
|
|
|
if line.strip() == "#exit":
|
|
return 0
|
|
|
|
# Create a fresh lexer each iteration
|
|
lexer_info = LexerInfo(filename=REPL_FILE_NAME, source_code=line)
|
|
|
|
try:
|
|
tokens = lexical_analysis(lexer_info)
|
|
except Exception as err:
|
|
print(err)
|
|
continue
|
|
|
|
# Execute tokens in order
|
|
for token in tokens:
|
|
try:
|
|
ok = interpreter.execute(token)
|
|
if not ok:
|
|
print("A runtime error occurred!")
|
|
break
|
|
except Exception as err:
|
|
print(err)
|
|
break
|
|
|
|
print_top_of_stack(interpreter)
|
|
|
|
return 1
|