package org.antlr.analysis;
import org.antlr.codegen.CodeGenerator;
import org.antlr.grammar.v3.ANTLRParser;
import org.antlr.tool.Grammar;
import org.antlr.tool.GrammarAST;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import java.util.*;
public abstract class SemanticContext {
public static final SemanticContext EMPTY_SEMANTIC_CONTEXT = new Predicate(Predicate.INVALID_PRED_VALUE);
public abstract SemanticContext getGatedPredicateContext();
public abstract ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa);
public abstract boolean hasUserSemanticPredicate();
public abstract boolean isSyntacticPredicate();
public void trackUseOfSyntacticPredicates(Grammar g) {
}
public static class Predicate extends SemanticContext {
public GrammarAST predicateAST;
protected boolean gated = false;
protected boolean synpred = false;
public static final int INVALID_PRED_VALUE = -2;
public static final int FALSE_PRED = 0;
public static final int TRUE_PRED = ~0;
protected int constantValue = INVALID_PRED_VALUE;
public Predicate(int constantValue) {
predicateAST = new GrammarAST();
this.constantValue=constantValue;
}
public Predicate(GrammarAST predicate) {
this.predicateAST = predicate;
this.gated =
predicate.getType()==ANTLRParser.GATED_SEMPRED ||
predicate.getType()==ANTLRParser.SYN_SEMPRED ;
this.synpred =
predicate.getType()==ANTLRParser.SYN_SEMPRED ||
predicate.getType()==ANTLRParser.BACKTRACK_SEMPRED;
}
public Predicate(Predicate p) {
this.predicateAST = p.predicateAST;
this.gated = p.gated;
this.synpred = p.synpred;
this.constantValue = p.constantValue;
}
@Override
public boolean equals(Object o) {
if ( !(o instanceof Predicate) ) {
return false;
}
Predicate other = (Predicate)o;
if (this.constantValue != other.constantValue){
return false;
}
if (this.constantValue != INVALID_PRED_VALUE){
return true;
}
return predicateAST.getText().equals(other.predicateAST.getText());
}
@Override
public int hashCode() {
if (constantValue != INVALID_PRED_VALUE){
return constantValue;
}
if ( predicateAST ==null ) {
return 0;
}
return predicateAST.getText().hashCode();
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
ST eST;
if ( templates!=null ) {
if ( synpred ) {
eST = templates.getInstanceOf("evalSynPredicate");
}
else {
eST = templates.getInstanceOf("evalPredicate");
generator.grammar.decisionsWhoseDFAsUsesSemPreds.add(dfa);
}
String predEnclosingRuleName = predicateAST.enclosingRuleName;
if ( generator!=null ) {
eST.add("pred",
generator.translateAction(predEnclosingRuleName,predicateAST));
}
}
else {
eST = new ST("<pred>");
eST.add("pred", this.toString());
return eST;
}
if ( generator!=null ) {
String description =
generator.target.getTargetStringLiteralFromString(this.toString());
eST.add("description", description);
}
return eST;
}
@Override
public SemanticContext getGatedPredicateContext() {
if ( gated ) {
return this;
}
return null;
}
@Override
public boolean hasUserSemanticPredicate() {
return predicateAST !=null &&
( predicateAST.getType()==ANTLRParser.GATED_SEMPRED ||
predicateAST.getType()==ANTLRParser.SEMPRED );
}
@Override
public boolean isSyntacticPredicate() {
return predicateAST !=null &&
( predicateAST.getType()==ANTLRParser.SYN_SEMPRED ||
predicateAST.getType()==ANTLRParser.BACKTRACK_SEMPRED );
}
@Override
public void trackUseOfSyntacticPredicates(Grammar g) {
if ( synpred ) {
g.synPredNamesUsedInDFA.add(predicateAST.getText());
}
}
@Override
public String toString() {
if ( predicateAST ==null ) {
return "<nopred>";
}
return predicateAST.getText();
}
}
public static class TruePredicate extends Predicate {
public TruePredicate() {
super(TRUE_PRED);
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
if ( templates!=null ) {
return templates.getInstanceOf("true_value");
}
return new ST("true");
}
@Override
public boolean hasUserSemanticPredicate() {
return false;
}
@Override
public String toString() {
return "true";
}
}
public static class FalsePredicate extends Predicate {
public FalsePredicate() {
super(FALSE_PRED);
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
if ( templates!=null ) {
return templates.getInstanceOf("false");
}
return new ST("false");
}
@Override
public boolean hasUserSemanticPredicate() {
return false;
}
@Override
public String toString() {
return "false";
}
}
public static abstract class CommutativePredicate extends SemanticContext {
protected final Set<SemanticContext> operands = new HashSet<SemanticContext>();
protected int hashcode;
public CommutativePredicate(SemanticContext a, SemanticContext b) {
if (a.getClass() == this.getClass()){
CommutativePredicate predicate = (CommutativePredicate)a;
operands.addAll(predicate.operands);
} else {
operands.add(a);
}
if (b.getClass() == this.getClass()){
CommutativePredicate predicate = (CommutativePredicate)b;
operands.addAll(predicate.operands);
} else {
operands.add(b);
}
hashcode = calculateHashCode();
}
public CommutativePredicate(HashSet<SemanticContext> contexts){
for (SemanticContext context : contexts){
if (context.getClass() == this.getClass()){
CommutativePredicate predicate = (CommutativePredicate)context;
operands.addAll(predicate.operands);
} else {
operands.add(context);
}
}
hashcode = calculateHashCode();
}
@Override
public SemanticContext getGatedPredicateContext() {
SemanticContext result = null;
for (SemanticContext semctx : operands) {
SemanticContext gatedPred = semctx.getGatedPredicateContext();
if ( gatedPred!=null ) {
result = combinePredicates(result, gatedPred);
}
}
return result;
}
@Override
public boolean hasUserSemanticPredicate() {
for (SemanticContext semctx : operands) {
if ( semctx.hasUserSemanticPredicate() ) {
return true;
}
}
return false;
}
@Override
public boolean isSyntacticPredicate() {
for (SemanticContext semctx : operands) {
if ( semctx.isSyntacticPredicate() ) {
return true;
}
}
return false;
}
@Override
public void trackUseOfSyntacticPredicates(Grammar g) {
for (SemanticContext semctx : operands) {
semctx.trackUseOfSyntacticPredicates(g);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj.getClass() == this.getClass()) {
CommutativePredicate commutative = (CommutativePredicate)obj;
Set<SemanticContext> otherOperands = commutative.operands;
if (operands.size() != otherOperands.size())
return false;
return operands.containsAll(otherOperands);
}
if (obj instanceof NOT)
{
NOT not = (NOT)obj;
if (not.ctx instanceof CommutativePredicate && not.ctx.getClass() != this.getClass()) {
Set<SemanticContext> otherOperands = ((CommutativePredicate)not.ctx).operands;
if (operands.size() != otherOperands.size())
return false;
ArrayList<SemanticContext> temp = new ArrayList<SemanticContext>(operands.size());
for (SemanticContext context : otherOperands) {
temp.add(not(context));
}
return operands.containsAll(temp);
}
}
return false;
}
@Override
public int hashCode(){
return hashcode;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("(");
int i = 0;
for (SemanticContext semctx : operands) {
if ( i>0 ) {
buf.append(getOperandString());
}
buf.append(semctx.toString());
i++;
}
buf.append(")");
return buf.toString();
}
public abstract String getOperandString();
public abstract SemanticContext combinePredicates(SemanticContext left, SemanticContext right);
public abstract int calculateHashCode();
}
public static class AND extends CommutativePredicate {
public AND(SemanticContext a, SemanticContext b) {
super(a,b);
}
public AND(HashSet<SemanticContext> contexts) {
super(contexts);
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
ST result = null;
for (SemanticContext operand : operands) {
if (result == null) {
result = operand.genExpr(generator, templates, dfa);
continue;
}
ST eST;
if ( templates!=null ) {
eST = templates.getInstanceOf("andPredicates");
}
else {
eST = new ST("(<left>&&<right>)");
}
eST.add("left", result);
eST.add("right", operand.genExpr(generator,templates,dfa));
result = eST;
}
return result;
}
@Override
public String getOperandString() {
return "&&";
}
@Override
public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
return SemanticContext.and(left, right);
}
@Override
public int calculateHashCode() {
int hashcode = 0;
for (SemanticContext context : operands) {
hashcode = hashcode ^ context.hashCode();
}
return hashcode;
}
}
public static class OR extends CommutativePredicate {
public OR(SemanticContext a, SemanticContext b) {
super(a,b);
}
public OR(HashSet<SemanticContext> contexts) {
super(contexts);
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
ST eST;
if ( templates!=null ) {
eST = templates.getInstanceOf("orPredicates");
}
else {
eST = new ST("(<operands; separator=\"||\">)");
}
for (SemanticContext semctx : operands) {
eST.add("operands", semctx.genExpr(generator,templates,dfa));
}
return eST;
}
@Override
public String getOperandString() {
return "||";
}
@Override
public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
return SemanticContext.or(left, right);
}
@Override
public int calculateHashCode() {
int hashcode = 0;
for (SemanticContext context : operands) {
hashcode = ~hashcode ^ context.hashCode();
}
return hashcode;
}
}
public static class NOT extends SemanticContext {
protected SemanticContext ctx;
public NOT(SemanticContext ctx) {
this.ctx = ctx;
}
@Override
public ST genExpr(CodeGenerator generator,
STGroup templates,
DFA dfa)
{
ST eST;
if ( templates!=null ) {
eST = templates.getInstanceOf("notPredicate");
}
else {
eST = new ST("!(<pred>)");
}
eST.add("pred", ctx.genExpr(generator,templates,dfa));
return eST;
}
@Override
public SemanticContext getGatedPredicateContext() {
SemanticContext p = ctx.getGatedPredicateContext();
if ( p==null ) {
return null;
}
return new NOT(p);
}
@Override
public boolean hasUserSemanticPredicate() {
return ctx.hasUserSemanticPredicate();
}
@Override
public boolean isSyntacticPredicate() {
return ctx.isSyntacticPredicate();
}
@Override
public void trackUseOfSyntacticPredicates(Grammar g) {
ctx.trackUseOfSyntacticPredicates(g);
}
@Override
public boolean equals(Object object) {
if ( !(object instanceof NOT) ) {
return false;
}
return this.ctx.equals(((NOT)object).ctx);
}
@Override
public int hashCode() {
return ~ctx.hashCode();
}
@Override
public String toString() {
return "!("+ctx+")";
}
}
public static SemanticContext and(SemanticContext a, SemanticContext b) {
if (a instanceof FalsePredicate || b instanceof FalsePredicate)
return new FalsePredicate();
SemanticContext[] terms = factorOr(a, b);
SemanticContext commonTerms = terms[0];
a = terms[1];
b = terms[2];
boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof TruePredicate);
if (factored) {
return or(commonTerms, and(a, b));
}
if (a instanceof FalsePredicate || b instanceof FalsePredicate)
return new FalsePredicate();
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null ) {
return b;
}
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null ) {
return a;
}
if (a instanceof TruePredicate)
return b;
if (b instanceof TruePredicate)
return a;
AND result = new AND(a,b);
if (result.operands.size() == 1) {
return result.operands.iterator().next();
}
return result;
}
public static SemanticContext or(SemanticContext a, SemanticContext b) {
if (a instanceof TruePredicate || b instanceof TruePredicate)
return new TruePredicate();
SemanticContext[] terms = factorAnd(a, b);
SemanticContext commonTerms = terms[0];
a = terms[1];
b = terms[2];
boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof FalsePredicate);
if (factored) {
return and(commonTerms, or(a, b));
}
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null || a instanceof FalsePredicate ) {
return b;
}
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null || b instanceof FalsePredicate ) {
return a;
}
if ( a instanceof TruePredicate || b instanceof TruePredicate || commonTerms instanceof TruePredicate ) {
return new TruePredicate();
}
if ( a instanceof NOT ) {
NOT n = (NOT)a;
if ( n.ctx.equals(b) ) {
return new TruePredicate();
}
}
else if ( b instanceof NOT ) {
NOT n = (NOT)b;
if ( n.ctx.equals(a) ) {
return new TruePredicate();
}
}
OR result = new OR(a,b);
if (result.operands.size() == 1)
return result.operands.iterator().next();
return result;
}
public static SemanticContext not(SemanticContext a) {
if (a instanceof NOT) {
return ((NOT)a).ctx;
}
if (a instanceof TruePredicate)
return new FalsePredicate();
else if (a instanceof FalsePredicate)
return new TruePredicate();
return new NOT(a);
}
public static SemanticContext[] factorAnd(SemanticContext a, SemanticContext b)
{
if (a == EMPTY_SEMANTIC_CONTEXT || a == null || a instanceof FalsePredicate)
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
if (b == EMPTY_SEMANTIC_CONTEXT || b == null || b instanceof FalsePredicate)
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
if (a instanceof TruePredicate || b instanceof TruePredicate)
{
return new SemanticContext[] { new TruePredicate(), EMPTY_SEMANTIC_CONTEXT, EMPTY_SEMANTIC_CONTEXT };
}
HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getAndOperands(a));
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getAndOperands(b));
HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
result.retainAll(opsB);
if (result.isEmpty())
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
opsA.removeAll(result);
if (opsA.isEmpty())
a = new TruePredicate();
else if (opsA.size() == 1)
a = opsA.iterator().next();
else
a = new AND(opsA);
opsB.removeAll(result);
if (opsB.isEmpty())
b = new TruePredicate();
else if (opsB.size() == 1)
b = opsB.iterator().next();
else
b = new AND(opsB);
if (result.size() == 1)
return new SemanticContext[] { result.iterator().next(), a, b };
return new SemanticContext[] { new AND(result), a, b };
}
public static SemanticContext[] factorOr(SemanticContext a, SemanticContext b)
{
HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getOrOperands(a));
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getOrOperands(b));
HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
result.retainAll(opsB);
if (result.isEmpty())
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
opsA.removeAll(result);
if (opsA.isEmpty())
a = new FalsePredicate();
else if (opsA.size() == 1)
a = opsA.iterator().next();
else
a = new OR(opsA);
opsB.removeAll(result);
if (opsB.isEmpty())
b = new FalsePredicate();
else if (opsB.size() == 1)
b = opsB.iterator().next();
else
b = new OR(opsB);
if (result.size() == 1)
return new SemanticContext[] { result.iterator().next(), a, b };
return new SemanticContext[] { new OR(result), a, b };
}
public static Collection<SemanticContext> getAndOperands(SemanticContext context)
{
if (context instanceof AND)
return ((AND)context).operands;
if (context instanceof NOT) {
Collection<SemanticContext> operands = getOrOperands(((NOT)context).ctx);
List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size());
for (SemanticContext operand : operands) {
result.add(not(operand));
}
return result;
}
ArrayList<SemanticContext> result = new ArrayList<SemanticContext>();
result.add(context);
return result;
}
public static Collection<SemanticContext> getOrOperands(SemanticContext context)
{
if (context instanceof OR)
return ((OR)context).operands;
if (context instanceof NOT) {
Collection<SemanticContext> operands = getAndOperands(((NOT)context).ctx);
List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size());
for (SemanticContext operand : operands) {
result.add(not(operand));
}
return result;
}
ArrayList<SemanticContext> result = new ArrayList<SemanticContext>();
result.add(context);
return result;
}
}