Allow nonterminals to be renamed

This commit is contained in:
John Doty 2024-05-30 19:15:20 -07:00
parent 4b8fef9ad6
commit 561dcd87ff
3 changed files with 43 additions and 11 deletions

View file

@ -76,7 +76,7 @@ class FineGrammar(Grammar):
] ]
) )
@rule @rule("File")
def file(self) -> Rule: def file(self) -> Rule:
return self._file_statement_list return self._file_statement_list
@ -94,7 +94,7 @@ class FineGrammar(Grammar):
def import_statement(self) -> Rule: def import_statement(self) -> Rule:
return seq(IMPORT, STRING, AS, IDENTIFIER, SEMICOLON) return seq(IMPORT, STRING, AS, IDENTIFIER, SEMICOLON)
@rule @rule("ClassDeclaration")
def class_declaration(self) -> Rule: def class_declaration(self) -> Rule:
return seq(CLASS, IDENTIFIER, self.class_body) return seq(CLASS, IDENTIFIER, self.class_body)

View file

@ -18,6 +18,11 @@ import parser
# from parser import Token, Grammar, rule, seq # from parser import Token, Grammar, rule, seq
###############################################################################
# Parsing Stuff
###############################################################################
def trace_state(stack, input, input_index, action): def trace_state(stack, input, input_index, action):
print( print(
"{stack: <20} {input: <50} {action: <5}".format( "{stack: <20} {input: <50} {action: <5}".format(
@ -133,6 +138,10 @@ def parse(table: parser.ParseTable, tokens, trace=None) -> typing.Tuple[Tree | N
raise ValueError(f"Unknown action type: {action}") raise ValueError(f"Unknown action type: {action}")
###############################################################################
# Screen Stuff
###############################################################################
# https://en.wikipedia.org/wiki/ANSI_escape_code # https://en.wikipedia.org/wiki/ANSI_escape_code
# https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 # https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
@ -176,6 +185,11 @@ def leave_alt_screen():
sys.stdout.buffer.write(CSI(b"?1049l")) sys.stdout.buffer.write(CSI(b"?1049l"))
###############################################################################
# Dynamic Modules: Detect and Reload Modules when they Change
###############################################################################
class DynamicModule: class DynamicModule:
file_name: str file_name: str
member_name: str | None member_name: str | None
@ -384,7 +398,7 @@ if __name__ == "__main__":
enter_alt_screen() enter_alt_screen()
h = Harness( h = Harness(
start_rule="file", start_rule="File",
source_path=source_path, source_path=source_path,
) )
h.run() h.run()

View file

@ -1745,15 +1745,19 @@ def seq(*args: Rule) -> Rule:
return result return result
# @typing.overload @typing.overload
# def rule(f: None | str = None) -> typing.Callable[[typing.Callable], Rule]: ... def rule(f: typing.Callable, /) -> Rule: ...
# @typing.overload @typing.overload
# def rule(f: typing.Callable) -> Rule: ... def rule(
name: str | None = None, transparent: bool | None = None
) -> typing.Callable[[typing.Callable[[typing.Any], Rule]], Rule]: ...
def rule(f: typing.Callable) -> Rule: def rule(
name: str | None | typing.Callable = None, transparent: bool | None = None
) -> Rule | typing.Callable[[typing.Callable[[typing.Any], Rule]], Rule]:
"""The decorator that marks a method in a Grammar object as a nonterminal """The decorator that marks a method in a Grammar object as a nonterminal
rule. rule.
@ -1761,9 +1765,23 @@ def rule(f: typing.Callable) -> Rule:
If called with one argument, that argument is a name that overrides the name If called with one argument, that argument is a name that overrides the name
of the nonterminal, which defaults to the name of the function. of the nonterminal, which defaults to the name of the function.
""" """
name = f.__name__ if callable(name):
transparent = name.startswith("_") return rule()(name)
return NonTerminal(f, name, transparent)
def wrapper(f: typing.Callable[[typing.Any], Rule]):
nonlocal name
nonlocal transparent
if name is None:
name = f.__name__
assert isinstance(name, str)
if transparent is None:
transparent = name.startswith("_")
return NonTerminal(f, name, transparent)
return wrapper
PrecedenceList = list[typing.Tuple[Assoc, list[Rule]]] PrecedenceList = list[typing.Tuple[Assoc, list[Rule]]]