Allow nonterminals to be renamed
This commit is contained in:
parent
4b8fef9ad6
commit
561dcd87ff
3 changed files with 43 additions and 11 deletions
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
16
harness.py
16
harness.py
|
|
@ -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()
|
||||||
|
|
|
||||||
28
parser.py
28
parser.py
|
|
@ -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,10 +1765,24 @@ 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.
|
||||||
"""
|
"""
|
||||||
|
if callable(name):
|
||||||
|
return rule()(name)
|
||||||
|
|
||||||
|
def wrapper(f: typing.Callable[[typing.Any], Rule]):
|
||||||
|
nonlocal name
|
||||||
|
nonlocal transparent
|
||||||
|
|
||||||
|
if name is None:
|
||||||
name = f.__name__
|
name = f.__name__
|
||||||
|
assert isinstance(name, str)
|
||||||
|
|
||||||
|
if transparent is None:
|
||||||
transparent = name.startswith("_")
|
transparent = name.startswith("_")
|
||||||
|
|
||||||
return NonTerminal(f, name, transparent)
|
return NonTerminal(f, name, transparent)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
PrecedenceList = list[typing.Tuple[Assoc, list[Rule]]]
|
PrecedenceList = list[typing.Tuple[Assoc, list[Rule]]]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue