JSON-Lang/patterns.py

103 lines
2.9 KiB
Python

from emis_funky_funktions import *
from typing import Collection, Mapping, Sequence, Tuple, TypeAlias
import types_
from match_tree import LeafNode, IntNode, MatchTree, StructurePath, FAIL_NODE, EMPTY_STRUCT_PATH
Pattern: TypeAlias = 'NamePattern | IntPattern | SPattern | IgnorePattern'
@dataclass(frozen=True)
class NamePattern:
"""
A pattern which always succeeds to match, and binds a whole expression to a name
"""
name: str
def match_tree(self, location: StructurePath, success_leaf: 'MatchTree[A]') -> 'MatchTree[A]':
return success_leaf
def bindings(self) -> Collection[Tuple[str, StructurePath]]:
return ((self.name, EMPTY_STRUCT_PATH),)
def binds(self, var: str) -> bool:
"""
Test to see if this pattern binds a given variable
"""
return var == self.name
def __repr__(self) -> str:
return self.name
@dataclass(frozen=True)
class IgnorePattern:
"""
A pattern which always succeeds to match, but binds nothing
"""
def match_tree(self, location: StructurePath, success_leaf: 'MatchTree[A]') -> 'MatchTree[A]':
return success_leaf
def bindings(self) -> Collection[Tuple[str, StructurePath]]:
return tuple()
def binds(self, var: str) -> bool:
"""
Test to see if this pattern binds a given variable
For an `IgnorePattern` this is always false
"""
return False
def __repr__(self) -> str:
return '_'
@dataclass(frozen=True)
class IntPattern:
value: int
def match_tree(self, location: StructurePath, success_leaf: 'MatchTree[A]') -> 'MatchTree[A]':
return IntNode(location, {self.value: success_leaf}, LeafNode([]))
def bindings(self) -> Collection[Tuple[str, StructurePath]]:
return tuple()
def binds(self, var: str) -> bool:
"""
Test to see if this pattern binds a given variable
For an `IntPattern` this is always false
"""
return False
def __repr__(self) -> str:
return repr(self.value)
@dataclass(frozen=True)
class SPattern:
pred: Pattern
def match_tree(self, location: StructurePath, success_leaf: 'MatchTree[A]') -> 'MatchTree[A]':
match self.pred.match_tree(StructurePath((*location, 0)), success_leaf):
case IntNode(child_location, trees, fallback) as child:
# If the child check is also an int node on pred of our current location:
# "raise" that node to be at our current level.
if child_location == (*location, 0):
return IntNode(location, dict(((0, FAIL_NODE), *((1 + v, mt) for v, mt in trees.items()))), fallback)
else:
return IntNode(location, {0: FAIL_NODE}, child)
case child:
return IntNode(location, {0: FAIL_NODE}, child)
def bindings(self) -> Collection[Tuple[str, StructurePath]]:
# Prepend each binding path of the child pattern with 0 (i.e. subtract one from an int)
return tuple((name, StructurePath((0, *path))) for (name, path) in self.pred.bindings())
def binds(self, var: str) -> bool:
"""
Test to see if this pattern binds a given variable
"""
return self.pred.binds(var)
def __repr__(self) -> str:
return 'S ' + repr(self.pred)