![JAR search and dependency download from the Maven repository](/logo.png)
com.sri.ai.grinder.parser.antlr.ExpressionVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aic-expresso Show documentation
Show all versions of aic-expresso Show documentation
SRI International's AIC Symbolic Manipulation and Evaluation Library (for Java 1.8+)
The newest version!
/*
* Copyright (c) 2013, SRI International
* All rights reserved.
* Licensed under the The BSD 3-Clause License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://opensource.org/licenses/BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the aic-expresso nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sri.ai.grinder.parser.antlr;
import static com.sri.ai.expresso.helper.Expressions.apply;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.INTEGER_INTERVAL;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.NOT;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.antlr.v4.runtime.Token;
import com.google.common.annotations.Beta;
import com.sri.ai.expresso.api.Expression;
import com.sri.ai.expresso.api.IntensionalSet;
import com.sri.ai.expresso.core.DefaultCountingFormula;
import com.sri.ai.expresso.core.DefaultLambdaExpression;
import com.sri.ai.expresso.core.ExtensionalIndexExpressionsSet;
import com.sri.ai.expresso.helper.Expressions;
import com.sri.ai.grinder.helper.FunctionSignature;
import com.sri.ai.grinder.sgdpllt.library.FunctorConstants;
import com.sri.ai.grinder.sgdpllt.library.boole.And;
import com.sri.ai.grinder.sgdpllt.library.boole.ForAll;
import com.sri.ai.grinder.sgdpllt.library.boole.Or;
import com.sri.ai.grinder.sgdpllt.library.boole.ThereExists;
import com.sri.ai.grinder.sgdpllt.library.set.extensional.ExtensionalSets;
import com.sri.ai.util.Util;
@Beta
public class ExpressionVisitor extends AntlrGrinderBaseVisitor {
private Collection randomPredicatesSignatures;
// Note track bracketed expressions based on identity to ensure no accidental replacement by value.
private Map parenthesizedExpressions = new IdentityHashMap();
public ExpressionVisitor(Collection randomPredicatesSignatures) {
super();
this.randomPredicatesSignatures = randomPredicatesSignatures;
}
// parenthesis, e.g.:(1+2)
// '(' expr ')' #parenthesesAroundExpression
@Override
public Expression visitParenthesesAroundExpression(
AntlrGrinderParser.ParenthesesAroundExpressionContext ctx) {
Expression result = visit(ctx.expr());
// Keep track of explicitly bracketed expressions
// so that the are not flattened as part of the
// possiblyFlatten()
// call for some expressions, e.g.: 1 + 2 + 3.
parenthesizedExpressions.put(result, result);
return result;
}
// an expression symbol, e.g.:
// '<' expr '>' #expressionSymbol
@Override
public Expression visitExpressionSymbol(
AntlrGrinderParser.ExpressionSymbolContext ctx) {
Expression expr = visit(ctx.expr());
Expression result = Expressions.makeSymbol(expr);
return result;
}
// function application, e.g.: f(X)
// functor=expr '(' ( args+=expr (',' args+=expr)* )? ')' # functionApplication
@Override
public Expression visitFunctionApplication(
AntlrGrinderParser.FunctionApplicationContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTreesWithRandomPredicatesSignatures(randomPredicatesSignatures, visit(ctx.functor), expressions(ctx.args));
return result;
}
@Override
public Expression visitTupleType(AntlrGrinderParser.TupleTypeContext ctx) {
Object[] arguments = new Object[1+ctx.additionalargs.size()];
arguments[0] = visit(ctx.firstarg);
for (int i = 0; i < ctx.additionalargs.size(); i++) {
arguments[i+1] = visit(ctx.additionalargs.get(i));
}
Expression result = Expressions.apply(FunctorConstants.TUPLE_TYPE, arguments);
return result;
}
@Override
public Expression visitFunctionType(AntlrGrinderParser.FunctionTypeContext ctx) {
Object[] arguments = new Object[2];
if (ctx.domaintypes.size() == 1) {
Expression domain = visit(ctx.domaintypes.get(0));
arguments[0] = domain;
}
else {
Object[] domainArgs = new Object[ctx.domaintypes.size()];
for (int i = 0; i < ctx.domaintypes.size(); i++) {
domainArgs[i] = visit(ctx.domaintypes.get(i));
}
Expression tupleType = Expressions.apply(FunctorConstants.TUPLE_TYPE, domainArgs);
arguments[0] = tupleType;
}
arguments[1] = visit(ctx.rangetype);
Expression result = Expressions.apply(FunctorConstants.FUNCTION_TYPE, arguments);
return result;
}
// tuple, e.g.: (A, B, C)
// '(' expr ',' expr (',' expr)* ')' #tuple
@Override
public Expression visitTuple(AntlrGrinderParser.TupleContext ctx) {
Expression result = Expressions.makeTuple(expressions(ctx.expr()));
return result;
}
// counting formula, e.g.: | X in 1..10 : X < 5 |
// '|' ( indexes+=expr (',' indexes+=expr)* )? ':' body=expr '|' #countingFormula
@Override
public Expression visitCountingFormula(AntlrGrinderParser.CountingFormulaContext ctx) {
Expression result = new DefaultCountingFormula(expressionsList(ctx.indexes), visit(ctx.body));
return result;
}
// cardinality, e.g.: | X |
// '|' expr '|' #cardinality
@Override
public Expression visitCardinality(AntlrGrinderParser.CardinalityContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.CARDINALITY, visit(ctx.expr()));
return result;
}
// intensional uniset, e.g.: { (on X) f(X) | X != a }
// '{' ('{' ON ( scopeargs+=expr (',' scopeargs+=expr)* )? ')')? head=expr ('|' condition=expr)? '}' #intensionalUniset
@Override
public Expression visitIntensionalUniset(AntlrGrinderParser.IntensionalUnisetContext ctx) {
Expression result = makeIntensionalSet(IntensionalSet.UNI_SET_LABEL, ctx.scope, ctx.scopeargs, ctx.head, ctx.condition);
return result;
}
// intensional multiset, e.g.: {{ (on X) f(X) | X != a }}
// '{{' ('(' ON ( scopeargs+=expr (',' scopeargs+=expr)* )? ')')? head=expr ('|' condition=expr)? '}}' #intensionalMultiset
@Override
public Expression visitIntensionalMultiset(
AntlrGrinderParser.IntensionalMultisetContext ctx) {
Expression result = makeIntensionalSet(IntensionalSet.MULTI_SET_LABEL, ctx.scope, ctx.scopeargs, ctx.head, ctx.condition);
return result;
}
// extensional uniset, e.g.: { A, B, C, C, D }
// '{' ( expr (',' expr)* )? '}' #extensionalUniset
@Override
public Expression visitExtensionalUniset(
AntlrGrinderParser.ExtensionalUnisetContext ctx) {
Expression result = ExtensionalSets.makeUniSet(expressionsList(ctx.expr()));
return result;
}
// extensional multiset, e.g.: {{ A, B, C, C, D }}
// '{{' ( expr (',' expr)* )? '}}' #extensionalMultiset
@Override
public Expression visitExtensionalMultiset(AntlrGrinderParser.ExtensionalMultisetContext ctx) {
Expression result = ExtensionalSets.makeMultiSet(expressionsList(ctx.expr()));
return result;
}
// bracketed expression, for parfactors and random variables, e.g. [if p(X) then 1 else 2]
// '[' expr ']' #bracketedExpression
@Override
public Expression visitBracketedExpression(
AntlrGrinderParser.BracketedExpressionContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTreesWithRandomPredicatesSignatures(randomPredicatesSignatures, FunctorConstants.LEFT_DOT_RIGHT, visit(ctx.expr()));
return result;
}
// not, e.g.: not A and B -> (not(A)) and B
// NOT expr #not
@Override
public Expression visitNot(AntlrGrinderParser.NotContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(NOT, visit(ctx.expr()));
return result;
}
// negative, e.g.: 2 * -1 -> 2 * (-1)
// '-' expr #negative
@Override
public Expression visitNegative(AntlrGrinderParser.NegativeContext ctx) {
Expression argument = visit(ctx.expr());
Expression result;
if (argument.getValue() instanceof Number) {
result = Expressions.makeSymbol(argument.rationalValue().negate());
}
else {
result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.MINUS, argument);
}
return result;
}
// exponentiation, e.g. 2^3^4 -> 2^(3^4)
// base=expr '^' exponent=expr #Exponentiation
@Override
public Expression visitExponentiation(AntlrGrinderParser.ExponentiationContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.EXPONENTIATION, visit(ctx.base), visit(ctx.exponent));
return result;
}
// multiplication or division or integer interval, e.g.: 2*3/2 -> 2*(3/2)
// numerator=expr op=('*' | '/' | '..') denominator=expr #multiplicationOrDivisionOrIntegerInterval
@Override
public Expression visitMultiplicationOrDivisionOrIntegerInterval(AntlrGrinderParser.MultiplicationOrDivisionOrIntegerIntervalContext ctx) {
Expression result;
if (ctx.op.getText().equals("..")) {
result = apply(INTEGER_INTERVAL, visit(ctx.leftop), visit(ctx.rightop));
// result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.INTEGER_INTERVAL, visit(ctx.leftop), visit(ctx.rightop));
// using the above line places extra quotes around '..', not sure why.
}
else {
result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(ctx.op.getText(), visit(ctx.leftop), visit(ctx.rightop));
}
result = possiblyFlatten(result);
return result;
}
// addition or subtraction, e.g.: 1-2+3 -> (1-2)+3
// leftop=expr op=('+' | '-') rightop=expr #additionOrSubtraction
@Override
public Expression visitAdditionOrSubtraction(AntlrGrinderParser.AdditionOrSubtractionContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(ctx.op.getText(), visit(ctx.leftop), visit(ctx.rightop));
result = possiblyFlatten(result);
return result;
}
@Override
public Expression visitRealInterval(AntlrGrinderParser.RealIntervalContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(ctx.leftBracket.getText()+" . ; . "+ctx.rightBracket.getText(), visit(ctx.lower), visit(ctx.upper));
return result;
}
// set intersection, e.g.: {a, b, c} intersection {b}
// leftop=expr INTERSECTION rightop=expr #intersection
@Override
public Expression visitIntersection(
AntlrGrinderParser.IntersectionContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.INTERSECTION, visit(ctx.leftop), visit(ctx.rightop));
result = possiblyFlatten(result);
return result;
}
// set union, {a, b, c} union {b, d}
// leftop=expr UNION rightop=expr #union
@Override
public Expression visitUnion(AntlrGrinderParser.UnionContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.UNION, visit(ctx.leftop), visit(ctx.rightop));
result = possiblyFlatten(result);
return result;
}
// set membership, x in {x, y, z}
// leftop=expr IN rightop=expr #in
@Override
public Expression visitIn(AntlrGrinderParser.InContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.IN, visit(ctx.leftop), visit(ctx.rightop));
return result;
}
// comparison operators, e.g.: X = Y, 2 < 3
// leftop=expr op=('<' | '<=' | '=' | '!=' | '>=' | '>') rightop=expr #comparison
@Override
public Expression visitComparison(AntlrGrinderParser.ComparisonContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(ctx.op.getText(), visit(ctx.leftop), visit(ctx.rightop));
result = possiblyFlatten(result);
return result;
}
// conjunction, e.g.: A or B and C -> A or (B and C)
// leftconj=expr AND rightconj=expr #and
@Override
public Expression visitAnd(AntlrGrinderParser.AndContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(And.FUNCTOR, visit(ctx.leftconj), visit(ctx.rightconj));
result = possiblyFlatten(result);
return result;
}
// disjunction, e.g.: A => B or C -> A => (B or C)
// leftdisj=expr OR rightdisj=expr #or
@Override
public Expression visitOr(AntlrGrinderParser.OrContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(Or.FUNCTOR, visit(ctx.leftdisj), visit(ctx.rightdisj));
result = possiblyFlatten(result);
return result;
}
// implication, e.g.: A = B => C = D
// antecedent=expr IMPLICATION consequent=expr #implication
@Override
public Expression visitImplication(AntlrGrinderParser.ImplicationContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.IMPLICATION, visit(ctx.antecedent), visit(ctx.consequent));
return result;
}
// biconditional, e.g.: A = B <=> C = D
// leftop=expr BICONDITIONAL rightop=expr #biconditional
@Override
public Expression visitBiconditional(
AntlrGrinderParser.BiconditionalContext ctx) {
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.EQUIVALENCE, visit(ctx.leftop), visit(ctx.rightop));
return result;
}
// conditional, e.g.: if X = Y then 1 else 2
// IF condition=expr THEN thenbranch=expr ELSE elsebranch=expr #ifThenElse
@Override
public Expression visitIfThenElse(AntlrGrinderParser.IfThenElseContext ctx) {
Expression condition = visit(ctx.condition);
Expression thenBranch = visit(ctx.thenbranch);
Expression elseBranch = visit(ctx.elsebranch);
Expression result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(FunctorConstants.IF_THEN_ELSE, condition, thenBranch, elseBranch);
return result;
}
// lambda, e.g.: lambda f(X) : 2 + f(X)
// LAMBDA ( parameters+=expr (',' parameters+=expr)* )? ':' body=expr #lamda
@Override
public Expression visitLamda(
AntlrGrinderParser.LamdaContext ctx) {
Expression result = new DefaultLambdaExpression(expressionsList(ctx.parameters), visit(ctx.body));
return result;
}
// universal quantification, e.g.: for all X : X != a
// FOR ALL index=expr ':' body=expr #forAll
@Override
public Expression visitForAll(AntlrGrinderParser.ForAllContext ctx) {
Expression result = ForAll.make(visit(ctx.index), visit(ctx.body));
return result;
}
// existential quantification, e.g.: there exists X : X = a
// THERE EXISTS index=expr ':' body=expr #thereExists
@Override
public Expression visitThereExists(AntlrGrinderParser.ThereExistsContext ctx) {
Expression result = ThereExists.make(visit(ctx.index), visit(ctx.body));
return result;
}
@Override
public Expression visitSymbol(AntlrGrinderParser.SymbolContext ctx) {
Expression result = newSymbol(ctx.getText());
return result;
}
//
// PROTECTED
//
protected Expression newSymbol(String text) {
Expression result = Expressions.parseTextAndMakeSymbolOrStringLiteral(text);
return result;
}
protected Expression makeIntensionalSet(Object label, Token scope, List scopeargs,
AntlrGrinderParser.ExprContext head, AntlrGrinderParser.ExprContext condition) {
List indexExpressionsList = Util.list();
if (scope != null) {
indexExpressionsList = expressionsList(scopeargs);
}
Expression headExpression = visit(head);
Expression conditionExpression = null;
if (condition != null) {
conditionExpression = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(IntensionalSet.CONDITION_LABEL, visit(condition));
}
Expression result = null;
if (scope == null && conditionExpression == null) {
// We need to construct an extensional set in this case
if (label.equals(IntensionalSet.UNI_SET_LABEL)) {
result = ExtensionalSets.makeUniSet(headExpression);
}
else {
result = ExtensionalSets.makeMultiSet(Arrays.asList(headExpression));
}
}
else {
conditionExpression = conditionExpression == null? Expressions.TRUE : conditionExpression.get(0); // contains the "|";
result = IntensionalSet.make(label, new ExtensionalIndexExpressionsSet(indexExpressionsList), headExpression, conditionExpression);
}
return result;
}
protected Expression[] expressions(List exprContexts) {
List result = new ArrayList();
for (AntlrGrinderParser.ExprContext exprContext : exprContexts) {
result.add(visit(exprContext));
}
return result.toArray(new Expression[result.size()]);
}
protected List expressionsList(List exprContexts) {
List indexExpressionsList = new ArrayList();
for (AntlrGrinderParser.ExprContext exprContext : exprContexts) {
indexExpressionsList.add(visit(exprContext));
}
return indexExpressionsList;
}
protected Expression possiblyFlatten(Expression expression) {
Expression result = expression;
Object functor = expression.getFunctor();
if (functor != null) {
if (functor.equals(FunctorConstants.TIMES) ||
functor.equals(FunctorConstants.PLUS) ||
functor.equals(FunctorConstants.INTERSECTION) ||
functor.equals(FunctorConstants.UNION) ||
functor.equals(FunctorConstants.EQUAL) ||
functor.equals(FunctorConstants.AND) ||
functor.equals(FunctorConstants.OR)) {
List args = new ArrayList();
for (Expression arg : expression.getArguments()) {
if (arg.getFunctor() != null && functor.equals(arg.getFunctor()) && !parenthesizedExpressions.containsKey(arg)) {
args.addAll(arg.getArguments());
}
else {
args.add(arg);
}
}
result = Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(functor, args.toArray());
}
}
// Clear in order manage memory
parenthesizedExpressions.clear();
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy