Package kodkod.ast.visitor

Source Code of kodkod.ast.visitor.AbstractReplacer

/*
* Kodkod -- Copyright (c) 2005-2007, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.ast.visitor;

import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;

import kodkod.ast.BinaryExpression;
import kodkod.ast.BinaryFormula;
import kodkod.ast.BinaryIntExpression;
import kodkod.ast.ComparisonFormula;
import kodkod.ast.Comprehension;
import kodkod.ast.ConstantExpression;
import kodkod.ast.ConstantFormula;
import kodkod.ast.Decl;
import kodkod.ast.Decls;
import kodkod.ast.ExprToIntCast;
import kodkod.ast.Expression;
import kodkod.ast.Formula;
import kodkod.ast.IfExpression;
import kodkod.ast.IfIntExpression;
import kodkod.ast.IntComparisonFormula;
import kodkod.ast.IntConstant;
import kodkod.ast.IntExpression;
import kodkod.ast.IntToExprCast;
import kodkod.ast.MultiplicityFormula;
import kodkod.ast.NaryExpression;
import kodkod.ast.NaryFormula;
import kodkod.ast.NaryIntExpression;
import kodkod.ast.Node;
import kodkod.ast.NotFormula;
import kodkod.ast.ProjectExpression;
import kodkod.ast.QuantifiedFormula;
import kodkod.ast.Relation;
import kodkod.ast.RelationPredicate;
import kodkod.ast.SumExpression;
import kodkod.ast.UnaryExpression;
import kodkod.ast.UnaryIntExpression;
import kodkod.ast.Variable;
import kodkod.ast.operator.Multiplicity;

/**
* A depth first replacer.  The default implementation
* returns the tree to which it is applied.  Reference
* equality is used to determine if two nodes are the same.
*
* @specfield cached: set Node // result of visiting these nodes will be cached
* @specfield cache: Node ->lone Node
* @invariant cached in cache.Node
* @author Emina Torlak
*/
public abstract class AbstractReplacer implements ReturnVisitor<Expression, Formula, Decls, IntExpression> {
  protected final Map<Node,Node> cache;
  protected final Set<Node> cached;
 
  /**
   * Constructs a depth-first replaces which will cache
   * the results of visiting the given nodes and re-use them
   * on subsequent visits.
   * @effects this.cached' = cached && no this.cache'
   */
  protected AbstractReplacer(Set<Node> cached) {
    this.cached = cached;
    this.cache = new IdentityHashMap<Node,Node>(cached.size());
  }
 
  /**
   * Constructs a depth-first replacer which will cache
   * the results of visiting the given nodes in the given map,
   * and re-use them on subsequent visits.
   * @effects this.cached' = cached && this.cache' = cache
   */
  protected AbstractReplacer(Set<Node> cached, Map<Node,Node> cache) {
    this.cached = cached;
    this.cache = cache;
  }

 
  /**
   * If the given node has already been visited and its replacement
   * cached, the cached value is returned.  Otherwise, null is returned.
   * @return this.cache[node]
   */
  @SuppressWarnings("unchecked")
  protected <N extends Node> N lookup(N node) {
    return (N) cache.get(node);
  }
 
  /**
   * Caches the given replacement for the specified node, if this is
   * a caching visitor.  Otherwise does nothing.  The method returns
   * the replacement node. 
   * @effects node in this.cached => this.cache' = this.cache ++ node->replacement,
   *           this.cache' = this.cache
   * @return replacement
   */
  protected <N extends Node> N cache(N node, N replacement) {
    if (cached.contains(node)) {
      cache.put(node, replacement);
    }
    return replacement;
  }
 
  /**
   * Calls lookup(decls) and returns the cached value, if any. 
   * If a replacement has not been cached, visits each of the children's
   * variable and expression.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement Decls object is cached and returned.
   * @return { d: Decls | d.size = decls.size &&
   *                      all i: [0..d.size) | d.declarations[i] = decls.declarations[i].accept(this) }
   */
  public Decls visit(Decls decls) {
    Decls ret = lookup(decls);
    if (ret!=null) return ret;
   
    Decls visitedDecls = null;
    boolean allSame = true;
    for(Decl decl : decls) {
      Decls newDecl = visit(decl);
      if (newDecl != decl)
        allSame = false;
      visitedDecls = (visitedDecls==null) ? newDecl : visitedDecls.and(newDecl);
    }
    ret = allSame ? decls : visitedDecls;
    return cache(decls, ret);
  }
 
  /**
   * Calls lookup(decl) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the declaration's
   * variable and expression.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement Decl object is cached and returned.
   * @return { d: Declaration |  d.variable = declaration.variable.accept(this) &&
   *                             d.multiplicity = decl.multiplicity &&
   *                             d.expression = declaration.expression.accept(this)
   */
  public Decl visit(Decl decl) {
    Decl ret = lookup(decl);
    if (ret!=null) return ret;
   
    final Variable variable = (Variable) decl.variable().accept(this);
    final Expression expression = decl.expression().accept(this);
    ret = (variable==decl.variable() && expression==decl.expression()) ?
        decl : variable.declare(decl.multiplicity(), expression);
    return cache(decl,ret);
  }
 
  /**
   * Calls lookup(relation) and returns the cached value, if any. 
   * If a replacement has not been cached, the relation is cached and
   * returned.
   * @return relation
   */
  public Expression visit(Relation relation) {
    final Expression ret = lookup(relation);
    return ret==null ? cache(relation,relation) : ret;
  }
 
  /**
   * Calls lookup(variable) and returns the cached value, if any. 
   * If a replacement has not been cached, the variable is cached and
   * returned.
   * @return variable
   */
  public Expression visit(Variable variable) {
    final Expression ret = lookup(variable);
    return ret==null ? cache(variable,variable) : variable;
  }
 
  /**
   * Calls lookup(constExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, the constExpr is cached and
   * returned.
   * @return constExpr
   */
  public Expression visit(ConstantExpression constExpr) {
    final Expression ret = lookup(constExpr);
    return ret==null ? cache(constExpr,constExpr) : constExpr;
  }
 
  /**
   * Calls lookup(expr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expr's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expr is cached and returned.
   * @return { e: Expression | e.op = expr.op && #e.children = #expr.children && all i: [0..expr.children) | e.child(i) = expr.child(i).accept(this) }
   */
  public Expression visit(NaryExpression expr) {
    Expression ret = lookup(expr);
    if (ret!=null) return ret;
   
    final Expression[] visited = new Expression[expr.size()];
    boolean allSame = true;
    for(int i = 0 ; i < visited.length; i++) {
      final Expression child = expr.child(i);
      visited[i] = child.accept(this);
      allSame = allSame && visited[i]==child;
    }
   
    ret = allSame ? expr : Expression.compose(expr.op(), visited);
    return cache(expr,ret);
  }
 
  /**
   * Calls lookup(binExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { b: BinaryExpression | b.left = binExpr.left.accept(this) &&
   *                                 b.right = binExpr.right.accept(this) && b.op = binExpr.op }
   */
  public Expression visit(BinaryExpression binExpr) {
    Expression ret = lookup(binExpr);
    if (ret!=null) return ret;
   
    final Expression left  = binExpr.left().accept(this);
    final Expression right = binExpr.right().accept(this);
    ret = (left==binExpr.left() && right==binExpr.right()) ?
        binExpr : left.compose(binExpr.op(), right);
    return cache(binExpr,ret);
  }
 
  /**
   * Calls lookup(unaryExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * child.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { u: UnaryExpression | u.left = unaryExpr.expression.accept(this) && u.op = unaryExpr.op }
   */
  public Expression visit(UnaryExpression unaryExpr) {
    Expression ret = lookup(unaryExpr);
    if (ret!=null) return ret;

    final Expression child = unaryExpr.expression().accept(this);
    ret = (child==unaryExpr.expression()) ?
        unaryExpr : child.apply(unaryExpr.op());
    return cache(unaryExpr,ret);
  }
 
  /**
   * Calls lookup(comprehension) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { c: Comprehension | c.declarations = comprehension.declarations.accept(this) &&
   *                              c.formula = comprehension.formula.accept(this) }
   */
  public Expression visit(Comprehension comprehension) {
    Expression ret = lookup(comprehension);
    if (ret!=null) return ret;
   
    final Decls decls = (Decls)comprehension.decls().accept(this);
    final Formula formula = comprehension.formula().accept(this);
    ret = (decls==comprehension.decls() && formula==comprehension.formula()) ?
        comprehension : formula.comprehension(decls);
    return cache(comprehension,ret);
  }
 
 
  /**
   * Calls lookup(ifExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { i: IfExpression | i.condition = ifExpr.condition.accept(this) &&
   *                             i.thenExpr = ifExpr.thenExpr.accept(this) &&
   *                             i.elseExpr = ifExpr.elseExpr.accept(this) }
   */
  public Expression visit(IfExpression ifExpr) {
    Expression ret = lookup(ifExpr);
    if (ret!=null) return ret;

    final Formula condition = ifExpr.condition().accept(this);
    final Expression thenExpr = ifExpr.thenExpr().accept(this);
    final Expression elseExpr = ifExpr.elseExpr().accept(this);
    ret = (condition==ifExpr.condition() && thenExpr==ifExpr.thenExpr() &&
         elseExpr==ifExpr.elseExpr()) ?
          ifExpr : condition.thenElse(thenExpr, elseExpr);
    return cache(ifExpr,ret);
  }
   
  /**
   * Calls lookup(decls) and returns the cached value, if any. 
   * If a replacement has not been cached, visits each of the children's
   * variable and expression.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement Decls object is cached and returned.
   * @return { d: Decls | d.size = decls.size &&
   *                      all i: [0..d.size) | d.declarations[i] = decls.declarations[i].accept(this) }
   */
  public Expression visit(ProjectExpression project) {
    Expression ret = lookup(project);
    if (ret!=null) return ret;

    final Expression expr = project.expression().accept(this);
    final IntExpression[] cols = new IntExpression[project.arity()];
    boolean allSame = expr==project.expression();
    for(int i = 0, arity = project.arity(); i < arity; i++) {
      cols[i] = project.column(i).accept(this);
      allSame = allSame && (cols[i]==project.column(i));
    }
    ret = allSame ? project : expr.project(cols);
    return cache(project, ret);
  }
  /**
   * Calls lookup(castExpr) and returns the cached value, if any.  If a replacement
   * has not been cached, visits the expression's child.  If nothing changes, the argument
   * is cached and returned, otherwise a replacement expression is cached and returned.
   * @return { e: Expression | e = castExpr.intExpr.accept(this).toExpression() }
   */
  public Expression visit(IntToExprCast castExpr) {
    Expression ret = lookup(castExpr);
    if (ret!=null) return ret;

    final IntExpression intExpr = castExpr.intExpr().accept(this);
    ret = (intExpr==castExpr.intExpr()) ? castExpr : intExpr.cast(castExpr.op());
    return cache(castExpr, ret);
  }
 
    /**
   * Calls lookup(intconst) and returns the cached value, if any. 
   * If a replacement has not been cached, the constant is cached and returned.
   * @return intconst
   */
    public IntExpression visit(IntConstant intconst) {
    IntExpression ret = lookup(intconst);
    return ret==null ? cache(intconst, intconst) : intconst;
    }
   
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { i: IfIntExpression | i.condition = intExpr.condition.accept(this) &&
   *                             i.thenExpr = intExpr.thenExpr.accept(this) &&
   *                             i.elseExpr = intExpr.elseExpr.accept(this) }
   */
  public IntExpression visit(IfIntExpression intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;

    final Formula condition = intExpr.condition().accept(this);
    final IntExpression thenExpr = intExpr.thenExpr().accept(this);
    final IntExpression elseExpr = intExpr.elseExpr().accept(this);
    ret = (condition==intExpr.condition() && thenExpr==intExpr.thenExpr() &&
         elseExpr==intExpr.elseExpr()) ?
          intExpr : condition.thenElse(thenExpr, elseExpr);
    return cache(intExpr,ret);
  }
   
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * child.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { i: ExprToIntCast | i.expression = intExpr.expression.accept(this) && i.op = intExpr.op}
   */
    public IntExpression visit(ExprToIntCast intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;
 
    final Expression expr = intExpr.expression().accept(this);
    ret = expr==intExpr.expression() ? intExpr : expr.apply(intExpr.op());
    return cache(intExpr, ret);
    }
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the intExpr's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement intExpr is cached and returned.
   * @return { e: IntExpression | e.op = intExpr.op && #e.children = #intExpr.children && all i: [0..intExpr.children) | e.child(i) = intExpr.child(i).accept(this) }
   */
    public IntExpression visit(NaryIntExpression intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;
 
    final IntExpression[] visited = new IntExpression[intExpr.size()];
    boolean allSame = true;
    for(int i = 0 ; i < visited.length; i++) {
      final IntExpression child = intExpr.child(i);
      visited[i] = child.accept(this);
      allSame = allSame && visited[i]==child;
    }
   
    ret = allSame ? intExpr : IntExpression.compose(intExpr.op(), visited);
    return cache(intExpr,ret);
    }
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { c: IntExpression | [[c]] = intExpr.left.accept(this) op intExpr.right.accept(this) }
   */
    public IntExpression visit(BinaryIntExpression intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;
 
    final IntExpression left  = intExpr.left().accept(this);
    final IntExpression right = intExpr.right().accept(this);
    ret =  (left==intExpr.left() && right==intExpr.right()) ?
        intExpr : left.compose(intExpr.op(), right);
    return cache(intExpr,ret);
    }
   
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * child.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { u: UnaryIntExpression | u.expression = intExpr.expression.accept(this) && u.op = intExpr.op }
   */
  public IntExpression visit(UnaryIntExpression intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;

    final IntExpression child = intExpr.intExpr().accept(this);
    ret = (child==intExpr.intExpr()) ?  intExpr : child.apply(intExpr.op());
    return cache(intExpr,ret);
  }
 
    /**
   * Calls lookup(intExpr) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the expression's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement expression is cached and returned.
   * @return { c: IntExpression | [[c]] = sum intExpr.decls.accept(this) | intExpr.intExpr.accept(this) }
   */
    public IntExpression visit(SumExpression intExpr) {
    IntExpression ret = lookup(intExpr);
    if (ret!=null) return ret;
 
    final Decls decls  = intExpr.decls().accept(this);
    final IntExpression expr = intExpr.intExpr().accept(this);
    ret =  (decls==intExpr.decls() && expr==intExpr.intExpr()) ?
        intExpr : expr.sum(decls);
    return cache(intExpr,ret);
    }
   
    /**
   * Calls lookup(intComp) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { c: Formula | [[c]] = intComp.left.accept(this) op intComp.right.accept(this) }
   */
    public Formula visit(IntComparisonFormula intComp) {
    Formula ret = lookup(intComp);
    if (ret!=null) return ret;

    final IntExpression left  = intComp.left().accept(this);
    final IntExpression right = intComp.right().accept(this);
    ret =  (left==intComp.left() && right==intComp.right()) ?
        intComp : left.compare(intComp.op(), right);
    return cache(intComp,ret);
    }
 
    /**
   * Calls lookup(constant) and returns the cached value, if any. 
   * If a replacement has not been cached, the constant is cached and
   * returned.
   * @return constant
   */
  public Formula visit(ConstantFormula constant) {
    final Formula ret = lookup(constant);
    return ret==null ? cache(constant,constant) : constant;
  }

  /**
   * Calls lookup(quantFormula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { q: QuantifiedFormula | q.declarations = quantFormula.declarations.accept(this) &&
   *                                  q.formula = quantFormula.formula.accept(this) }
   */
  public Formula visit(QuantifiedFormula quantFormula) {
    Formula ret = lookup(quantFormula);
    if (ret!=null) return ret;
   
    final Decls decls = (Decls)quantFormula.decls().accept(this);
    final Formula formula = quantFormula.formula().accept(this);
    ret = (decls==quantFormula.decls() && formula==quantFormula.formula()) ?
        quantFormula : formula.quantify(quantFormula.quantifier(), decls);
    return cache(quantFormula,ret);
  }
 
  /**
   * Calls lookup(formula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { e: Expression | e.op = formula.op && #e.children = #formula.children && all i: [0..formula.children) | e.child(i) = formula.child(i).accept(this) }
   */
  public Formula visit(NaryFormula formula) {
    Formula ret = lookup(formula);
    if (ret!=null) return ret;
   
    final Formula[] visited = new Formula[formula.size()];
    boolean allSame = true;
    for(int i = 0 ; i < visited.length; i++) {
      final Formula child = formula.child(i);
      visited[i] = child.accept(this);
      allSame = allSame && visited[i]==child;
    }
   
    ret = allSame ? formula : Formula.compose(formula.op(), visited);
    return cache(formula,ret);
  }
 
  /**
   * Calls lookup(binFormula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { b: BinaryFormula | b.left = binExpr.left.accept(this) &&
   *                              b.right = binExpr.right.accept(this) && b.op = binExpr.op }
   */
  public Formula visit(BinaryFormula binFormula) {
    Formula ret = lookup(binFormula);
    if (ret!=null) return ret;
   
    final Formula left  = binFormula.left().accept(this);
    final Formula right = binFormula.right().accept(this);
    ret = (left==binFormula.left() && right==binFormula.right()) ?
        binFormula : left.compose(binFormula.op(), right);    
    return cache(binFormula,ret);
  }
 
  /**
   * Calls lookup(binFormula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * child.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { n: NotFormula | n.child = not.child.accept(this) }
   */
  public Formula visit(NotFormula not) {
    Formula ret = lookup(not);
    if (ret!=null) return ret;

    final Formula child = not.formula().accept(this);
    ret = (child==not.formula()) ? not : child.not();
    return cache(not,ret);
  }
 
  /**
   * Calls lookup(compFormula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { c: ComparisonFormula | c.left = compFormula.left.accept(this) &&
   *                                  c.right = compFormula.right.accept(this) &&
   *                                  c.op = compFormula.op }
   */
  public Formula visit(ComparisonFormula compFormula) {
    Formula ret = lookup(compFormula);
    if (ret!=null) return ret;
     
    final Expression left  = compFormula.left().accept(this);
    final Expression right = compFormula.right().accept(this);
    ret =  (left==compFormula.left() && right==compFormula.right()) ?
         compFormula : left.compare(compFormula.op(), right)
    return cache(compFormula,ret);
  }
 
  /**
   * Calls lookup(multFormula) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { m: MultiplicityFormula | m.multiplicity = multFormula.multiplicity &&
   *                                    m.expression = multFormula.expression.accept(this) }
   */
  public Formula visit(MultiplicityFormula multFormula) {
    Formula ret = lookup(multFormula);
    if (ret!=null) return ret;
   
    final Expression expression = multFormula.expression().accept(this);
    ret = (expression==multFormula.expression()) ?
        multFormula : expression.apply(multFormula.multiplicity());
    return cache(multFormula,ret);
  }
 
  /**
   * Calls lookup(pred) and returns the cached value, if any. 
   * If a replacement has not been cached, visits the formula's
   * children.  If nothing changes, the argument is cached and
   * returned, otherwise a replacement formula is cached and returned.
   * @return { p: RelationPredicate | p.name = pred.name && p.relation = pred.relation.accept(this) &&
   *                                  p.name = FUNCTION => p.targetMult = pred.targetMult &&
   *                                                       p.domain = pred.domain.accept(this) &&
   *                                                       p.range = pred.range.accept(this),
   *                                  p.name = TOTAL_ORDERING => p.ordered = pred.ordered.accept(this) &&
   *                                                             p.first = pred.first.accept(this) &&
   *                                                             p.last = pred.last.accept(this) }
   */
  public Formula visit(RelationPredicate pred) {
    Formula ret = lookup(pred);
    if (ret!=null) return ret;
 
    final Relation r = (Relation)pred.relation().accept(this);
    switch(pred.name()) {
    case ACYCLIC : 
      ret = (r==pred.relation()) ? pred : r.acyclic();
      break;
    case FUNCTION :
      final RelationPredicate.Function fp = (RelationPredicate.Function) pred;
      final Expression domain = fp.domain().accept(this);
      final Expression range = fp.range().accept(this);
      ret = (r==fp.relation() && domain==fp.domain() && range==fp.range()) ?
          fp :
          (fp.targetMult()==Multiplicity.ONE ? r.function(domain, range) : r.partialFunction(domain,range));
      break;
    case TOTAL_ORDERING :
      final RelationPredicate.TotalOrdering tp = (RelationPredicate.TotalOrdering) pred;
      final Relation ordered = (Relation) tp.ordered().accept(this);
      final Relation first = (Relation)tp.first().accept(this);
      final Relation last = (Relation)tp.last().accept(this);
      ret = (r==tp.relation() && ordered==tp.ordered() && first==tp.first() && last==tp.last()) ?
          tp : r.totalOrder(ordered, first, last);
      break;
    default :
      throw new IllegalArgumentException("unknown relation predicate: " + pred.name());
    }
    return cache(pred,ret);
  }
 
}
TOP

Related Classes of kodkod.ast.visitor.AbstractReplacer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.