/*
* Copyright (C) 2009-2012 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.logic;
/**
* A walker according to the visitor pattern. This walker is recursive. Since
* this is dangerous for big terms, it should not be used anymore. Consider
* {@link NonRecursive} or {@link TermTransformer} instead.
* @author Juergen Christ
*/
@Deprecated
public class FormulaWalker {
public interface SymbolVisitor {
/**
* Returns the new term corresponding to <code>input</code>.
* @param input Input term.
* @return OutputTerm or <code>null</code> iff walker should descend
* into subterms (only for ApplicationTerms with arguments and
* ITETerms).
*/
public Term term(Term input);
/**
* Finished descending into arguments of a term.
* @param input Term recently processed.
*/
public void done(Term input);
/**
* Whether flet formulae should be removed or not.
* @return <code>true</code> iff flets should be removed
*/
public boolean unflet();
/**
* Should let formulae be removed or not. Note that the visitor is
* responsible for substituting TermVariables.
* @return <code>true</code> iff let formulae should be removed.
*/
public boolean unlet();
/**
* Notification for a discovered let formula.
* @param tv TermVariable bound by this let formula.
* @param mval Modified value of <code>tv</code>.
*/
public void let(TermVariable[] tv,Term[] mval);
/**
* Begin of a quantifier scope.
* @param tvs Variables bound by this quantifier.
*/
public void quantifier(TermVariable[] tvs);
/**
* End scopes of multiple variables.
* @param tv All variables whose scope ends.
*/
public void endscope(TermVariable[] tv);
}
private final SymbolVisitor mVisitor;
private final Script mScript;
public FormulaWalker(SymbolVisitor visitor, Script script) {
mVisitor = visitor;
mScript = script;
}
public Term process(Term term) throws SMTLIBException {
return recursivewalk(term);
}
private Term recursivewalk(Term term) throws SMTLIBException {
final Term res = mVisitor.term(term);
if (res != null) {
return res;
}
if (term instanceof LetTerm) {
final LetTerm let = (LetTerm) term;
final Term[] values = let.getValues();
Term[] newvalues = new Term[values.length];
boolean changed = false;
for (int i = 0; i < values.length; i++) {
newvalues[i] = recursivewalk(values[i]);
if (newvalues[i] != values[i]) {
changed = true;
}
}
if (!changed) {
newvalues = values;
}
mVisitor.let(let.getVariables(), newvalues);
try {
final Term newsub = recursivewalk(let.getSubTerm());
return mVisitor.unlet() ? newsub
: newvalues == values && newsub == let.getSubTerm() ? let
: mScript.let(let.getVariables(), newvalues, newsub);
} finally {
mVisitor.endscope(let.getVariables());
}
} else if (term instanceof QuantifiedFormula) {
final QuantifiedFormula qf = (QuantifiedFormula)term;
final int quantifier = qf.getQuantifier();
final TermVariable[] vars = qf.getVariables();
mVisitor.quantifier(vars);
try {
final Term msub = recursivewalk(qf.getSubformula());
final boolean changed = msub != qf.getSubformula();
return changed ? qf : mScript.quantifier(
quantifier, vars, msub);
} finally {
mVisitor.endscope(vars);
}
} else if (term instanceof AnnotatedTerm) {
final AnnotatedTerm annterm = (AnnotatedTerm) term;
final Term sub = recursivewalk(annterm.getSubterm());
final Annotation[] annots = annterm.getAnnotations();
Annotation[] newAnnots = annots;
for (int i = 0; i < annots.length; i++) {
final Object value = annots[i].getValue();
Object newValue;
if (value instanceof Term) {
newValue = recursivewalk((Term) value);
} else if (value instanceof Term[]) {
newValue = recursivewalk((Term[]) value);
} else {
newValue = value;
}
if (newValue != value) {
if (annots == newAnnots) {
newAnnots = annots.clone();
}
newAnnots[i] = new Annotation(annots[i].getKey(), newValue);
}
}
if (sub == annterm.getSubterm() && newAnnots == annots) {
return term;
}
return mScript.annotate(sub, newAnnots);
} else if (term instanceof ApplicationTerm) {
final ApplicationTerm at = (ApplicationTerm) term;
final Term[] args = at.getParameters();
final Term[] nargs = recursivewalk(args);
mVisitor.done(term);
return args == nargs ? term : mScript.term(
at.getFunction().getName(),nargs);
}
throw new RuntimeException(
"SymbolVisitor returned null-value for basic term!");
}
private Term[] recursivewalk(Term[] args) throws SMTLIBException {
final Term[] nargs = new Term[args.length];
boolean changed = false;
for (int i = 0; i < args.length; ++i) {
nargs[i] = recursivewalk(args[i]);
if (nargs[i] != args[i]) {
changed = true;
}
}
return changed ? nargs : args;
}
}