feat(repl): add dedicated REPL class
This commit is contained in:
3
main.py
3
main.py
@@ -4,6 +4,7 @@ import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from src.repl import REPL
|
||||
from src.runner import Runner
|
||||
|
||||
|
||||
@@ -23,7 +24,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.script is None:
|
||||
Runner.repl()
|
||||
REPL().run()
|
||||
else:
|
||||
Runner.run_file(args.script)
|
||||
|
||||
|
||||
113
src/repl.py
Normal file
113
src/repl.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import atexit
|
||||
import readline
|
||||
from pathlib import Path
|
||||
|
||||
from src.ast.stmt import Stmt
|
||||
from src.interpreter.interpreter import Interpreter
|
||||
from src.interpreter.resolver import Resolver
|
||||
from src.parser.parser import Parser
|
||||
from src.pebble import Pebble
|
||||
from src.token.lexer import Lexer
|
||||
from src.token.token import Token, TokenType
|
||||
|
||||
|
||||
class REPL:
|
||||
HIST_FILE: Path = Path("~").expanduser() / ".pebble_history"
|
||||
|
||||
def __init__(self):
|
||||
self.interpreter: Interpreter = Interpreter()
|
||||
|
||||
@staticmethod
|
||||
def greet():
|
||||
print(f"Welcome to Pebble v{Pebble.version()}!")
|
||||
print("Press CTRL+D to quit")
|
||||
|
||||
def init_history(self):
|
||||
h_len: int = 0
|
||||
try:
|
||||
readline.read_history_file(self.HIST_FILE)
|
||||
h_len = readline.get_current_history_length()
|
||||
except FileNotFoundError:
|
||||
with open(self.HIST_FILE, "wb"):
|
||||
pass
|
||||
|
||||
def save(prev_h_len: int, hist_file: Path):
|
||||
new_h_len: int = readline.get_current_history_length()
|
||||
readline.set_history_length(1000)
|
||||
readline.append_history_file(new_h_len - prev_h_len, hist_file)
|
||||
|
||||
atexit.register(save, h_len, self.HIST_FILE)
|
||||
|
||||
def run(self):
|
||||
line: str
|
||||
tokens: list[Token]
|
||||
program: list[Stmt]
|
||||
|
||||
self.greet()
|
||||
self.init_history()
|
||||
|
||||
buf: str = ""
|
||||
while True:
|
||||
try:
|
||||
line = input(">>> " if len(buf) == 0 else "... ")
|
||||
except EOFError:
|
||||
print()
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
buf = ""
|
||||
print()
|
||||
continue
|
||||
|
||||
buf += line + "\n"
|
||||
try:
|
||||
tokens = Lexer(buf).process()
|
||||
except:
|
||||
continue
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
if self.unfinished_statement(tokens):
|
||||
continue
|
||||
|
||||
program = Parser(tokens).parse()
|
||||
buf = ""
|
||||
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
Resolver(self.interpreter).resolve(*program)
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
try:
|
||||
self.interpreter.interpret(program)
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
|
||||
if Pebble.had_runtime_error:
|
||||
Pebble.had_runtime_error = False
|
||||
continue
|
||||
|
||||
@staticmethod
|
||||
def unfinished_statement(tokens: list[Token]) -> bool:
|
||||
brace_depth: int = 0
|
||||
paren_depth: int = 0
|
||||
fstring_depth: int = 0
|
||||
for token in tokens:
|
||||
match token.type:
|
||||
case TokenType.LEFT_BRACE:
|
||||
brace_depth += 1
|
||||
case TokenType.RIGHT_BRACE:
|
||||
brace_depth = max(0, brace_depth - 1)
|
||||
case TokenType.LEFT_PAREN:
|
||||
paren_depth += 1
|
||||
case TokenType.RIGHT_PAREN:
|
||||
paren_depth = max(0, paren_depth - 1)
|
||||
case TokenType.FSTRING_START:
|
||||
fstring_depth += 1
|
||||
case TokenType.FSTRING_END:
|
||||
fstring_depth = max(0, fstring_depth - 1)
|
||||
return brace_depth > 0 or paren_depth > 0 or fstring_depth > 0
|
||||
@@ -5,10 +5,10 @@ from src.ast.stmt import Stmt
|
||||
from src.formatter import Formatter
|
||||
from src.interpreter.interpreter import Interpreter
|
||||
from src.interpreter.resolver import Resolver
|
||||
from src.token.lexer import Lexer
|
||||
from src.parser.parser import Parser
|
||||
from src.pebble import Pebble
|
||||
from src.token.token import Token, TokenType
|
||||
from src.token.lexer import Lexer
|
||||
from src.token.token import Token
|
||||
|
||||
|
||||
class Runner:
|
||||
@@ -55,77 +55,3 @@ class Runner:
|
||||
formatter: Formatter = Formatter()
|
||||
with open("formatted.peb", "w") as f:
|
||||
f.write(formatter.print(program))
|
||||
|
||||
@staticmethod
|
||||
def repl():
|
||||
line: str
|
||||
lexer: Lexer
|
||||
tokens: list[Token]
|
||||
parser: Parser
|
||||
program: list[Stmt]
|
||||
interpreter: Interpreter = Interpreter()
|
||||
resolver: Resolver
|
||||
|
||||
print(f"Welcome to Pebble v{Pebble.version()}!")
|
||||
print("Press CTRL+D to quit")
|
||||
|
||||
brace_depth: int
|
||||
paren_depth: int
|
||||
buf: str = ""
|
||||
while True:
|
||||
try:
|
||||
line = input(">>> " if len(buf) == 0 else "... ")
|
||||
except EOFError:
|
||||
print()
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
buf = ""
|
||||
print()
|
||||
continue
|
||||
|
||||
buf += line + "\n"
|
||||
lexer = Lexer(buf)
|
||||
tokens = lexer.process()
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
brace_depth = 0
|
||||
paren_depth = 0
|
||||
for token in tokens:
|
||||
match token.type:
|
||||
case TokenType.LEFT_BRACE:
|
||||
brace_depth += 1
|
||||
case TokenType.RIGHT_BRACE:
|
||||
brace_depth = max(0, brace_depth - 1)
|
||||
case TokenType.LEFT_PAREN:
|
||||
paren_depth += 1
|
||||
case TokenType.RIGHT_PAREN:
|
||||
paren_depth = max(0, paren_depth - 1)
|
||||
|
||||
if brace_depth > 0 or paren_depth > 0:
|
||||
continue
|
||||
|
||||
parser = Parser(tokens)
|
||||
program = parser.parse()
|
||||
buf = ""
|
||||
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
resolver: Resolver = Resolver(interpreter)
|
||||
|
||||
resolver.resolve(*program)
|
||||
if Pebble.had_error:
|
||||
Pebble.had_error = False
|
||||
continue
|
||||
|
||||
try:
|
||||
interpreter.interpret(program)
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
|
||||
if Pebble.had_runtime_error:
|
||||
Pebble.had_runtime_error = False
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user