Harness uses grammar-generated token stream
This commit is contained in:
parent
0be0075cfe
commit
d03dc6e3d9
1 changed files with 67 additions and 14 deletions
81
harness.py
81
harness.py
|
|
@ -22,11 +22,6 @@ from parser import runtime
|
||||||
# from parser import Token, Grammar, rule, seq
|
# from parser import Token, Grammar, rule, seq
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Parsing Stuff
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Screen Stuff
|
# Screen Stuff
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
@ -84,13 +79,18 @@ def goto_cursor(x: int, y: int):
|
||||||
# Dynamic Modules: Detect and Reload Modules when they Change
|
# Dynamic Modules: Detect and Reload Modules when they Change
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
VERSION = 0
|
||||||
|
|
||||||
class DynamicModule:
|
MT = typing.TypeVar("MT")
|
||||||
|
|
||||||
|
|
||||||
|
class DynamicModule[MT]:
|
||||||
file_name: str
|
file_name: str
|
||||||
member_name: str | None
|
member_name: str | None
|
||||||
|
|
||||||
last_time: float | None
|
last_time: float | None
|
||||||
module: types.ModuleType | None
|
module: types.ModuleType | None
|
||||||
|
value: MT | None
|
||||||
|
|
||||||
def __init__(self, file_name, member_name):
|
def __init__(self, file_name, member_name):
|
||||||
self.file_name = file_name
|
self.file_name = file_name
|
||||||
|
|
@ -110,15 +110,18 @@ class DynamicModule:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _transform(self, value):
|
def _transform(self, value) -> MT:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get(self):
|
def get(self) -> MT:
|
||||||
st = os.stat(self.file_name)
|
st = os.stat(self.file_name)
|
||||||
if self.last_time == st.st_mtime:
|
if self.last_time == st.st_mtime:
|
||||||
assert self.value is not None
|
assert self.value is not None
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
global VERSION
|
||||||
|
VERSION += 1
|
||||||
|
|
||||||
self.value = None
|
self.value = None
|
||||||
|
|
||||||
if self.module is None:
|
if self.module is None:
|
||||||
|
|
@ -150,7 +153,7 @@ class DynamicModule:
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class DynamicGrammarModule(DynamicModule):
|
class DynamicGrammarModule(DynamicModule[parser.ParseTable]):
|
||||||
def __init__(self, file_name, member_name, start_rule):
|
def __init__(self, file_name, member_name, start_rule):
|
||||||
super().__init__(file_name, member_name)
|
super().__init__(file_name, member_name)
|
||||||
|
|
||||||
|
|
@ -169,16 +172,24 @@ class DynamicGrammarModule(DynamicModule):
|
||||||
return value().build_table(start=self.start_rule)
|
return value().build_table(start=self.start_rule)
|
||||||
|
|
||||||
|
|
||||||
class DynamicLexerModule(DynamicModule):
|
class DynamicLexerModule(DynamicModule[typing.Callable[[str], runtime.TokenStream]]):
|
||||||
def _predicate(self, member) -> bool:
|
def _predicate(self, member) -> bool:
|
||||||
if not super()._predicate(member):
|
if not super()._predicate(member):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if getattr(member, "tokens", None):
|
if getattr(member, "terminals", None):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _transform(self, value):
|
||||||
|
lexer_table = parser.compile_lexer(value())
|
||||||
|
|
||||||
|
def get_tokens(src: str) -> runtime.TokenStream:
|
||||||
|
return runtime.GenericTokenStream(src, lexer_table)
|
||||||
|
|
||||||
|
return get_tokens
|
||||||
|
|
||||||
|
|
||||||
class DisplayMode(enum.Enum):
|
class DisplayMode(enum.Enum):
|
||||||
TREE = 0
|
TREE = 0
|
||||||
|
|
@ -220,6 +231,8 @@ class Harness:
|
||||||
line_start: int
|
line_start: int
|
||||||
last_cols: int
|
last_cols: int
|
||||||
|
|
||||||
|
last_version: int
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, grammar_file, grammar_member, lexer_file, lexer_member, start_rule, source_path
|
self, grammar_file, grammar_member, lexer_file, lexer_member, start_rule, source_path
|
||||||
):
|
):
|
||||||
|
|
@ -230,9 +243,12 @@ class Harness:
|
||||||
self.start_rule = start_rule
|
self.start_rule = start_rule
|
||||||
self.source_path = source_path
|
self.source_path = source_path
|
||||||
|
|
||||||
|
self.last_version = -1
|
||||||
|
|
||||||
self.mode = DisplayMode.TREE
|
self.mode = DisplayMode.TREE
|
||||||
|
|
||||||
self.source = None
|
self.source = None
|
||||||
|
|
||||||
self.table = None
|
self.table = None
|
||||||
self.tokens = None
|
self.tokens = None
|
||||||
self.tree = None
|
self.tree = None
|
||||||
|
|
@ -250,7 +266,7 @@ class Harness:
|
||||||
self.grammar_file, self.grammar_member, self.start_rule
|
self.grammar_file, self.grammar_member, self.start_rule
|
||||||
)
|
)
|
||||||
|
|
||||||
self.lexer_module = DynamicLexerModule(self.lexer_file, self.lexer_member)
|
self.lexer_module = DynamicLexerModule(self.lexer_file, self.grammar_member)
|
||||||
|
|
||||||
self.log_handler = ListHandler()
|
self.log_handler = ListHandler()
|
||||||
logging.basicConfig(level=logging.INFO, handlers=[self.log_handler])
|
logging.basicConfig(level=logging.INFO, handlers=[self.log_handler])
|
||||||
|
|
@ -286,15 +302,25 @@ class Harness:
|
||||||
return self.grammar_module.get()
|
return self.grammar_module.get()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.log_handler.clear()
|
global VERSION
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
try:
|
try:
|
||||||
table = self.load_grammar()
|
table = self.load_grammar()
|
||||||
lexer_func = self.lexer_module.get()
|
lexer_func = self.lexer_module.get()
|
||||||
|
|
||||||
with open(self.source_path, "r", encoding="utf-8") as f:
|
with open(self.source_path, "r", encoding="utf-8") as f:
|
||||||
self.source = f.read()
|
source = f.read()
|
||||||
|
if source != self.source:
|
||||||
|
VERSION += 1
|
||||||
|
self.source = source
|
||||||
|
|
||||||
|
if VERSION == self.last_version:
|
||||||
|
return # Just stop, do nothing, it's all the same.
|
||||||
|
self.last_version = VERSION
|
||||||
|
assert self.source is not None
|
||||||
|
|
||||||
|
self.log_handler.clear()
|
||||||
self.tokens = lexer_func(self.source)
|
self.tokens = lexer_func(self.source)
|
||||||
lex_time = time.time()
|
lex_time = time.time()
|
||||||
|
|
||||||
|
|
@ -321,6 +347,33 @@ class Harness:
|
||||||
self.average_entries = 0
|
self.average_entries = 0
|
||||||
self.max_entries = 0
|
self.max_entries = 0
|
||||||
|
|
||||||
|
# WHAT
|
||||||
|
try:
|
||||||
|
with open("tree.txt", "w", encoding="utf-8") as f:
|
||||||
|
lines = []
|
||||||
|
if self.tree is not None:
|
||||||
|
self.format_node(lines, self.tree)
|
||||||
|
f.writelines([f"{l}\n" for l in lines])
|
||||||
|
except Exception as e:
|
||||||
|
self.errors.extend([f"Unable to write tree.txt: {e}"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("errors.txt", "w", encoding="utf-8") as f:
|
||||||
|
f.writelines([f"{l}\n" for l in self.errors])
|
||||||
|
except Exception as e:
|
||||||
|
self.errors.extend([f"Unable to write errors.txt: {e}"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("parse.log", "w", encoding="utf-8") as f:
|
||||||
|
f.writelines([f"{l}\n" for l in self.log_handler.logs])
|
||||||
|
except Exception as e:
|
||||||
|
self.errors.extend([f"Unable to write parse.log: {e}"])
|
||||||
|
|
||||||
|
if hasattr(self.tokens, "dump"):
|
||||||
|
lines = self.tokens.dump()
|
||||||
|
with open("tokens.txt", "w", encoding="utf-8") as f:
|
||||||
|
f.writelines([f"{l}\n" for l in lines])
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
sys.stdout.buffer.write(CLEAR)
|
sys.stdout.buffer.write(CLEAR)
|
||||||
rows, cols = termios.tcgetwinsize(sys.stdout.fileno())
|
rows, cols = termios.tcgetwinsize(sys.stdout.fileno())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue