Add lookup expressions

This commit is contained in:
James Westman 2022-01-29 21:21:04 -06:00
parent c094743e84
commit 4fefa0bd73
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
8 changed files with 177 additions and 5 deletions

View file

@ -98,6 +98,7 @@ class ParseContext:
def __init__(self, tokens, index=0):
self.tokens = list(tokens)
self.binding_power = 0
self.index = index
self.start = index
self.group = None
@ -118,6 +119,7 @@ class ParseContext:
ctx = ParseContext(self.tokens, self.index)
ctx.errors = self.errors
ctx.warnings = self.warnings
ctx.binding_power = self.binding_power
return ctx
def apply_child(self, other):
@ -544,6 +546,64 @@ class Keyword(ParseNode):
return str(token) == self.kw
class Prefix(ParseNode):
def __init__(self, child):
self.child = to_parse_node(child)
def _parse(self, ctx: ParseContext):
return self.child.parse(ctx).succeeded()
class Infix(ParseNode):
def __init__(self, binding_power: int, child):
self.binding_power = binding_power
self.child = to_parse_node(child)
def _parse(self, ctx: ParseContext):
ctx.binding_power = self.binding_power
return self.child.parse(ctx).succeeded()
def __lt__(self, other):
return self.binding_power < other.binding_power
def __eq__(self, other):
return self.binding_power == other.binding_power
class Pratt(ParseNode):
""" Basic Pratt parser implementation. """
def __init__(self, *children):
self.children = children
@property
def children(self):
return self._children
@children.setter
def children(self, children):
self._children = children
self.prefixes = [child for child in children if isinstance(child, Prefix)]
self.infixes = sorted([child for child in children if isinstance(child, Infix)], reverse=True)
def _parse(self, ctx: ParseContext) -> bool:
for prefix in self.prefixes:
if prefix.parse(ctx).succeeded():
break
else:
# none of the prefixes could be parsed
return False
while True:
succeeded = False
for infix in self.infixes:
if infix.binding_power <= ctx.binding_power:
break
if infix.parse(ctx).succeeded():
succeeded = True
break
if not succeeded:
return True
def to_parse_node(value) -> ParseNode:
if isinstance(value, str):
return Match(value)