[parser] More usability improvements
Implicit sequences in arguments, and now you can use terminals when constructing regular expressions.
This commit is contained in:
parent
3bffe98df0
commit
c23dbe3e8f
1 changed files with 38 additions and 8 deletions
|
|
@ -1807,14 +1807,23 @@ def seq(*args: Rule) -> Rule:
|
||||||
|
|
||||||
|
|
||||||
def opt(*args: Rule) -> Rule:
|
def opt(*args: Rule) -> Rule:
|
||||||
|
"""Mark a sequence as optional."""
|
||||||
return AlternativeRule(seq(*args), Nothing)
|
return AlternativeRule(seq(*args), Nothing)
|
||||||
|
|
||||||
|
|
||||||
def mark(rule: Rule, **kwargs) -> Rule:
|
def mark(rule: Rule, **kwargs) -> Rule:
|
||||||
|
"""Mark the specified rules with metadata."""
|
||||||
return MetadataRule(rule, kwargs)
|
return MetadataRule(rule, kwargs)
|
||||||
|
|
||||||
|
|
||||||
def one_or_more(r: Rule) -> Rule:
|
def one_or_more(*args: Rule) -> Rule:
|
||||||
|
"""Generate a rule that matches a repetition of one or more of the specified
|
||||||
|
rule.
|
||||||
|
|
||||||
|
The resulting list is transparent, i.e., in the parse tree all of the members
|
||||||
|
of the list will be in-line with the parent. If you want to name the list
|
||||||
|
create a named nonterminal to contain it.
|
||||||
|
"""
|
||||||
global _CURRENT_DEFINITION
|
global _CURRENT_DEFINITION
|
||||||
global _CURRENT_GEN_INDEX
|
global _CURRENT_GEN_INDEX
|
||||||
|
|
||||||
|
|
@ -1822,7 +1831,7 @@ def one_or_more(r: Rule) -> Rule:
|
||||||
def impl() -> Rule:
|
def impl() -> Rule:
|
||||||
nonlocal tail
|
nonlocal tail
|
||||||
assert(tail is not None)
|
assert(tail is not None)
|
||||||
return opt(tail) + r
|
return opt(tail) + seq(*args)
|
||||||
|
|
||||||
tail = NonTerminal(
|
tail = NonTerminal(
|
||||||
fn=impl,
|
fn=impl,
|
||||||
|
|
@ -1833,8 +1842,15 @@ def one_or_more(r: Rule) -> Rule:
|
||||||
|
|
||||||
return tail
|
return tail
|
||||||
|
|
||||||
def zero_or_more(r:Rule) -> Rule:
|
def zero_or_more(*args: Rule) -> Rule:
|
||||||
return opt(one_or_more(r))
|
"""Generate a rule that matches a repetition of zero or more of the specified
|
||||||
|
rule.
|
||||||
|
|
||||||
|
The resulting list is transparent, i.e., in the parse tree all of the members
|
||||||
|
of the list will be in-line with the parent. If you want to name the list
|
||||||
|
create a named nonterminal to contain it.
|
||||||
|
"""
|
||||||
|
return opt(one_or_more(*args))
|
||||||
|
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def rule(f: typing.Callable, /) -> NonTerminal: ...
|
def rule(f: typing.Callable, /) -> NonTerminal: ...
|
||||||
|
|
@ -2155,11 +2171,25 @@ class Re:
|
||||||
def question(self) -> "Re":
|
def question(self) -> "Re":
|
||||||
return ReQuestion(self)
|
return ReQuestion(self)
|
||||||
|
|
||||||
def __or__(self, value: "Re", /) -> "Re":
|
def __or__(self, value: "Re | Terminal", /) -> "Re":
|
||||||
return ReAlt(self, value)
|
if isinstance(value, Re):
|
||||||
|
other = value
|
||||||
|
elif isinstance(value.pattern, Re):
|
||||||
|
other = value.pattern
|
||||||
|
else:
|
||||||
|
other = Re.literal(value.pattern)
|
||||||
|
|
||||||
def __add__(self, value: "Re") -> "Re":
|
return ReAlt(self, other)
|
||||||
return ReSeq(self, value)
|
|
||||||
|
def __add__(self, value: "Re | Terminal") -> "Re":
|
||||||
|
if isinstance(value, Re):
|
||||||
|
other = value
|
||||||
|
elif isinstance(value.pattern, Re):
|
||||||
|
other = value.pattern
|
||||||
|
else:
|
||||||
|
other = Re.literal(value.pattern)
|
||||||
|
|
||||||
|
return ReSeq(self, other)
|
||||||
|
|
||||||
|
|
||||||
UNICODE_MAX_CP = 1114112
|
UNICODE_MAX_CP = 1114112
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue