Shofel2_T124_python/venv/lib/python3.10/site-packages/antlr4/atn/SemanticContext.py

320 lines
10 KiB
Python
Raw Normal View History

2024-05-25 16:45:07 +00:00
#
# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
# Use of this file is governed by the BSD 3-clause license that
# can be found in the LICENSE.txt file in the project root.
#
# A tree structure used to record the semantic context in which
# an ATN configuration is valid. It's either a single predicate,
# a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}.
#
# <p>I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of
# {@link SemanticContext} within the scope of this outer class.</p>
#
from antlr4.Recognizer import Recognizer
from antlr4.RuleContext import RuleContext
from io import StringIO
class SemanticContext(object):
#
# The default {@link SemanticContext}, which is semantically equivalent to
# a predicate of the form {@code {true}?}.
#
NONE = None
#
# For context independent predicates, we evaluate them without a local
# context (i.e., null context). That way, we can evaluate them without
# having to create proper rule-specific context during prediction (as
# opposed to the parser, which creates them naturally). In a practical
# sense, this avoids a cast exception from RuleContext to myruleContext.
#
# <p>For context dependent predicates, we must pass in a local context so that
# references such as $arg evaluate properly as _localctx.arg. We only
# capture context dependent predicates in the context in which we begin
# prediction, so we passed in the outer context here in case of context
# dependent predicate evaluation.</p>
#
def eval(self, parser:Recognizer , outerContext:RuleContext ):
pass
#
# Evaluate the precedence predicates for the context and reduce the result.
#
# @param parser The parser instance.
# @param outerContext The current parser context object.
# @return The simplified semantic context after precedence predicates are
# evaluated, which will be one of the following values.
# <ul>
# <li>{@link #NONE}: if the predicate simplifies to {@code true} after
# precedence predicates are evaluated.</li>
# <li>{@code null}: if the predicate simplifies to {@code false} after
# precedence predicates are evaluated.</li>
# <li>{@code this}: if the semantic context is not changed as a result of
# precedence predicate evaluation.</li>
# <li>A non-{@code null} {@link SemanticContext}: the new simplified
# semantic context after precedence predicates are evaluated.</li>
# </ul>
#
def evalPrecedence(self, parser:Recognizer, outerContext:RuleContext):
return self
# need forward declaration
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
# need forward declaration
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):
def __init__(self, ruleIndex:int=-1, predIndex:int=-1, isCtxDependent:bool=False):
self.ruleIndex = ruleIndex
self.predIndex = predIndex
self.isCtxDependent = isCtxDependent # e.g., $i ref in pred
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
# A semantic context which is true whenever none of the contained contexts
# is false.
del AND
class AND(SemanticContext):
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:
# interested in the transition with the lowest precedence
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"))
#
# {@inheritDoc}
#
# <p>
# The evaluation of predicates by this context is short-circuiting, but
# unordered.</p>
#
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:
# The AND context is false if any element is false
return None
elif evaluated is not SemanticContext.NONE:
# Reduce the result by skipping true elements
operands.append(evaluated)
if not differs:
return self
if len(operands)==0:
# all elements were true, so the AND context is true
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()
#
# A semantic context which is true whenever at least one of the contained
# contexts is true.
del OR
class OR (SemanticContext):
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:
# interested in the transition with the highest precedence
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"))
# <p>
# The evaluation of predicates by this context is short-circuiting, but
# unordered.</p>
#
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:
# The OR context is true if any element is true
return SemanticContext.NONE
elif evaluated is not None:
# Reduce the result by skipping false elements
operands.append(evaluated)
if not differs:
return self
if len(operands)==0:
# all elements were false, so the OR context is false
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()