#!/usr/bin/env python3
from lark import Lark
from fosf.config import FOSF_GRAMMAR
from fosf.parsers.base import BaseOSFParser, _BaseOSFTransformer
from fosf.parsers.taxonomy import _TaxonomyTransformer
from fosf.syntax.base import Tag
from fosf.syntax.constraints import (
Clause,
EqualityConstraint,
FeatureConstraint,
RootedClause,
RootedSolvedClause,
SolvedClause,
SortConstraint,
)
class _OsfConstraintTransformer(_BaseOSFTransformer):
def __init__(self):
super().__init__()
self.osf_clause = Clause()
self.root = None
def clause(self, _):
return self.osf_clause
def sort_constraint(self, tree):
X = Tag(tree[0].value)
s = tree[1]
return self.osf_clause.add(SortConstraint(X, s))
def feature_constraint(self, tree):
X = Tag(tree[0].value)
f = tree[1]
Y = Tag(tree[2].value)
return self.osf_clause.add(FeatureConstraint(X, f, Y))
def equality_constraint(self, tree):
X = Tag(tree[0].value)
Y = Tag(tree[1].value)
return self.osf_clause.add(EqualityConstraint(X, Y))
def prefixed_clause(self, tree):
return tree[-1]
def transform(self, parse_tree, create_using=None, root=None):
if create_using is None:
if root is None:
self.osf_clause = Clause()
else:
self.osf_clause = RootedClause(root)
elif root is None:
if create_using in {RootedClause, RootedSolvedClause}:
msg = f"A root must be specified for a clause of type {create_using}"
raise TypeError(msg)
self.osf_clause = create_using()
else:
if create_using in {Clause, SolvedClause}:
msg = f"Clauses of type {create_using} do not require a root"
raise TypeError(msg)
if isinstance(root, str):
root = Tag(root)
self.osf_clause = create_using(root)
return super().transform(parse_tree)
[docs]
class OsfConstraintParser(BaseOSFParser):
def __init__(self):
self.parser = Lark.open_from_package(
"fosf", FOSF_GRAMMAR, start="prefixed_clause"
)
self.transformer = _OsfConstraintTransformer()
[docs]
def parse(self, expression: str, create_using=None, root=None) -> Clause:
parse_tree = self.parser.parse(expression)
return self.transformer.transform(parse_tree, create_using, root)
class _QueryClauseTransformer(_OsfConstraintTransformer):
def q_tag(self, tree):
tag = Tag(tree[-1].value)
if len(tree) == 2:
self._query_tags.add(tag)
return tag
def query_clause(self, _):
return self.osf_clause
def sort_constraint(self, tree):
X = tree[0]
s = tree[1]
return self.osf_clause.add(SortConstraint(X, s))
def feature_constraint(self, tree):
X = tree[0]
f = tree[1]
Y = tree[2]
return self.osf_clause.add(FeatureConstraint(X, f, Y))
def equality_constraint(self, tree):
X = tree[0]
Y = tree[1]
return self.osf_clause.add(EqualityConstraint(X, Y))
def prefixed_query_clause(self, tree):
return tree[-1]
def transform(self, parse_tree, create_using=None, root=None):
self._query_tags = set()
clause = super().transform(parse_tree, create_using, root)
return self._query_tags, clause
[docs]
class QueryClauseParser(BaseOSFParser):
def __init__(self):
self.parser = Lark.open_from_package("fosf", FOSF_GRAMMAR, start="prefixed_query_clause")
self.transformer = _QueryClauseTransformer()
[docs]
def parse(self, expression: str, create_using=None, root=None) -> Clause:
parse_tree = self.parser.parse(expression)
return self.transformer.transform(parse_tree, create_using, root)
class _NormalizationTransformer(_TaxonomyTransformer, _OsfConstraintTransformer):
def norm_program(self, tree):
taxonomy = tree[0]
clause = tree[1]
return taxonomy, clause
[docs]
class NormalizationParser(BaseOSFParser):
def __init__(self):
self.parser = Lark.open_from_package("fosf", FOSF_GRAMMAR, start="norm_program")
self.transformer = _NormalizationTransformer()