|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from antlr4.Recognizer import Recognizer |
|
from antlr4.RuleContext import RuleContext |
|
from io import StringIO |
|
|
|
|
|
class SemanticContext(object): |
|
|
|
|
|
|
|
|
|
NONE = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eval(self, parser:Recognizer , outerContext:RuleContext ): |
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): |
|
return self |
|
|
|
|
|
AND = None |
|
|
|
def andContext(a:SemanticContext, b:SemanticContext): |
|
if a is None or a is SemanticContext.NONE: |
|
return b |
|
if b is None or b is SemanticContext.NONE: |
|
return a |
|
result = AND(a, b) |
|
if len(result.opnds) == 1: |
|
return result.opnds[0] |
|
else: |
|
return result |
|
|
|
|
|
OR = None |
|
|
|
def orContext(a:SemanticContext, b:SemanticContext): |
|
if a is None: |
|
return b |
|
if b is None: |
|
return a |
|
if a is SemanticContext.NONE or b is SemanticContext.NONE: |
|
return SemanticContext.NONE |
|
result = OR(a, b) |
|
if len(result.opnds) == 1: |
|
return result.opnds[0] |
|
else: |
|
return result |
|
|
|
def filterPrecedencePredicates(collection:set): |
|
return [context for context in collection if isinstance(context, PrecedencePredicate)] |
|
|
|
|
|
class Predicate(SemanticContext): |
|
__slots__ = ('ruleIndex', 'predIndex', 'isCtxDependent') |
|
|
|
def __init__(self, ruleIndex:int=-1, predIndex:int=-1, isCtxDependent:bool=False): |
|
self.ruleIndex = ruleIndex |
|
self.predIndex = predIndex |
|
self.isCtxDependent = isCtxDependent |
|
|
|
def eval(self, parser:Recognizer , outerContext:RuleContext ): |
|
localctx = outerContext if self.isCtxDependent else None |
|
return parser.sempred(localctx, self.ruleIndex, self.predIndex) |
|
|
|
def __hash__(self): |
|
return hash((self.ruleIndex, self.predIndex, self.isCtxDependent)) |
|
|
|
def __eq__(self, other): |
|
if self is other: |
|
return True |
|
elif not isinstance(other, Predicate): |
|
return False |
|
return self.ruleIndex == other.ruleIndex and \ |
|
self.predIndex == other.predIndex and \ |
|
self.isCtxDependent == other.isCtxDependent |
|
|
|
def __str__(self): |
|
return "{" + str(self.ruleIndex) + ":" + str(self.predIndex) + "}?" |
|
|
|
|
|
class PrecedencePredicate(SemanticContext): |
|
|
|
def __init__(self, precedence:int=0): |
|
self.precedence = precedence |
|
|
|
def eval(self, parser:Recognizer , outerContext:RuleContext ): |
|
return parser.precpred(outerContext, self.precedence) |
|
|
|
def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): |
|
if parser.precpred(outerContext, self.precedence): |
|
return SemanticContext.NONE |
|
else: |
|
return None |
|
|
|
def __lt__(self, other): |
|
return self.precedence < other.precedence |
|
|
|
def __hash__(self): |
|
return 31 |
|
|
|
def __eq__(self, other): |
|
if self is other: |
|
return True |
|
elif not isinstance(other, PrecedencePredicate): |
|
return False |
|
else: |
|
return self.precedence == other.precedence |
|
|
|
|
|
|
|
del AND |
|
class AND(SemanticContext): |
|
__slots__ = 'opnds' |
|
|
|
def __init__(self, a:SemanticContext, b:SemanticContext): |
|
operands = set() |
|
if isinstance( a, AND ): |
|
operands.update(a.opnds) |
|
else: |
|
operands.add(a) |
|
if isinstance( b, AND ): |
|
operands.update(b.opnds) |
|
else: |
|
operands.add(b) |
|
|
|
precedencePredicates = filterPrecedencePredicates(operands) |
|
if len(precedencePredicates)>0: |
|
|
|
reduced = min(precedencePredicates) |
|
operands.add(reduced) |
|
|
|
self.opnds = list(operands) |
|
|
|
def __eq__(self, other): |
|
if self is other: |
|
return True |
|
elif not isinstance(other, AND): |
|
return False |
|
else: |
|
return self.opnds == other.opnds |
|
|
|
def __hash__(self): |
|
h = 0 |
|
for o in self.opnds: |
|
h = hash((h, o)) |
|
return hash((h, "AND")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eval(self, parser:Recognizer, outerContext:RuleContext): |
|
return all(opnd.eval(parser, outerContext) for opnd in self.opnds) |
|
|
|
def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): |
|
differs = False |
|
operands = [] |
|
for context in self.opnds: |
|
evaluated = context.evalPrecedence(parser, outerContext) |
|
differs |= evaluated is not context |
|
if evaluated is None: |
|
|
|
return None |
|
elif evaluated is not SemanticContext.NONE: |
|
|
|
operands.append(evaluated) |
|
|
|
if not differs: |
|
return self |
|
|
|
if len(operands)==0: |
|
|
|
return SemanticContext.NONE |
|
|
|
result = None |
|
for o in operands: |
|
result = o if result is None else andContext(result, o) |
|
|
|
return result |
|
|
|
def __str__(self): |
|
with StringIO() as buf: |
|
first = True |
|
for o in self.opnds: |
|
if not first: |
|
buf.write("&&") |
|
buf.write(str(o)) |
|
first = False |
|
return buf.getvalue() |
|
|
|
|
|
|
|
|
|
del OR |
|
class OR (SemanticContext): |
|
__slots__ = 'opnds' |
|
|
|
def __init__(self, a:SemanticContext, b:SemanticContext): |
|
operands = set() |
|
if isinstance( a, OR ): |
|
operands.update(a.opnds) |
|
else: |
|
operands.add(a) |
|
if isinstance( b, OR ): |
|
operands.update(b.opnds) |
|
else: |
|
operands.add(b) |
|
|
|
precedencePredicates = filterPrecedencePredicates(operands) |
|
if len(precedencePredicates)>0: |
|
|
|
s = sorted(precedencePredicates) |
|
reduced = s[-1] |
|
operands.add(reduced) |
|
|
|
self.opnds = list(operands) |
|
|
|
def __eq__(self, other): |
|
if self is other: |
|
return True |
|
elif not isinstance(other, OR): |
|
return False |
|
else: |
|
return self.opnds == other.opnds |
|
|
|
def __hash__(self): |
|
h = 0 |
|
for o in self.opnds: |
|
h = hash((h, o)) |
|
return hash((h, "OR")) |
|
|
|
|
|
|
|
|
|
|
|
def eval(self, parser:Recognizer, outerContext:RuleContext): |
|
return any(opnd.eval(parser, outerContext) for opnd in self.opnds) |
|
|
|
def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext): |
|
differs = False |
|
operands = [] |
|
for context in self.opnds: |
|
evaluated = context.evalPrecedence(parser, outerContext) |
|
differs |= evaluated is not context |
|
if evaluated is SemanticContext.NONE: |
|
|
|
return SemanticContext.NONE |
|
elif evaluated is not None: |
|
|
|
operands.append(evaluated) |
|
|
|
if not differs: |
|
return self |
|
|
|
if len(operands)==0: |
|
|
|
return None |
|
|
|
result = None |
|
for o in operands: |
|
result = o if result is None else orContext(result, o) |
|
|
|
return result |
|
|
|
def __str__(self): |
|
with StringIO() as buf: |
|
first = True |
|
for o in self.opnds: |
|
if not first: |
|
buf.write("||") |
|
buf.write(str(o)) |
|
first = False |
|
return buf.getvalue() |
|
|
|
|
|
SemanticContext.NONE = Predicate() |
|
|