/* * Copyright (C) 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.smtinterpol.smtlib2; import java.math.BigInteger; import de.uni_freiburg.informatik.ultimate.logic.AnnotatedTerm; import de.uni_freiburg.informatik.ultimate.logic.Annotation; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.NonRecursive; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermTransformer; /** * This class can be used to replace the symbols @/0, @div0, and @mod0 from * terms and replace them by their meaning (/ ... 0), (div ... 0), and * (mod ... 0). * * This transformer also tries to transform annotations to remove these terms. * This is needed to fix the proof trees returned from SMTInterpol. Note that * in these proof terms annotations might be Object[] that contain further terms * or Term[]s. * @author Juergen Christ */ public class Div0Remover extends TermTransformer { private static class BuildAnnotationTerm implements Walker { private final AnnotatedTerm mTerm; public BuildAnnotationTerm(AnnotatedTerm term) { mTerm = term; } @Override public void walk(NonRecursive engine) { final Div0Remover remover = (Div0Remover) engine; final Annotation[] newAnnots = remover.collectAnnotations(mTerm.getAnnotations()); final Term sub = remover.getConverted(); if (newAnnots == mTerm.getAnnotations() && sub == mTerm.getSubterm()) { remover.setResult(mTerm); } else { remover.setResult( mTerm.getTheory().annotatedTerm(newAnnots, sub)); } } } private void pushTermsFromArray(Object[] arr) { for (int i = arr.length - 1; i >= 0; --i) { final Object val = arr[i]; if (val instanceof Term) { pushTerm((Term) val); } else if (val instanceof Term[]) { pushTerms((Term[]) val); } else if (val instanceof Object[]) { /* Recursion should be okay here since nesting should not be too * big. */ pushTermsFromArray((Object[]) val); } } } void pushTermsFromAnnotations(Annotation[] annots) { for (int i = annots.length - 1; i >= 0; --i) { final Object val = annots[i].getValue(); if (val instanceof Term) { pushTerm((Term) val); } else if (val instanceof Term[]) { pushTerms((Term[]) val); } else if (val instanceof Object[]) { pushTermsFromArray((Object[]) val); } } } private Object[] getFromArray(Object[] oldVal) { Object[] newVal = oldVal; for (int i = oldVal.length - 1; i >= 0; --i) { final Object val = oldVal[i]; Object newValue; if (val instanceof Term) { newValue = getConverted(); } else if (val instanceof Term[]) { newValue = getConverted((Term[]) val); } else if (val instanceof Object[]) { /* Recursion should be okay here since nesting should not be too * big. */ newValue = getFromArray((Object[]) val); } else { newValue = val; } if (newValue != val) { if (newVal == oldVal) { newVal = oldVal.clone(); } newVal[i] = newValue; } } return newVal; } Annotation[] collectAnnotations(Annotation[] oldAnnots) { Annotation[] newAnnots = oldAnnots; for (int i = oldAnnots.length - 1; i >= 0; i--) { final Object value = oldAnnots[i].getValue(); Object newValue; if (value instanceof Term) { newValue = getConverted(); } else if (value instanceof Term[]) { newValue = getConverted((Term[]) value); } else if (value instanceof Object[]) { newValue = getFromArray((Object[]) value); } else { newValue = value; } if (newValue != value) { if (oldAnnots == newAnnots) { newAnnots = oldAnnots.clone(); } newAnnots[i] = new Annotation(oldAnnots[i].getKey(), newValue); } } return newAnnots; } @Override protected void convert(Term term) { if (term instanceof AnnotatedTerm) { /* We cannot use postConvertAnnotation here since TermTransformer * does not descend into Object[] which is needed for proof tree * transformations. */ final AnnotatedTerm annot = (AnnotatedTerm) term; enqueueWalker(new BuildAnnotationTerm(annot)); pushTermsFromAnnotations(annot.getAnnotations()); pushTerm(annot.getSubterm()); return; } super.convert(term); } @Override public void convertApplicationTerm(ApplicationTerm appTerm, Term[] newArgs) { final FunctionSymbol sym = appTerm.getFunction(); String name = sym.getName(); if (name.charAt(0) == '@' && name.endsWith("0")) { name = name.substring(1, name.length() - 1); final Term[] args = new Term[2]; args[0] = newArgs[0]; args[1] = appTerm.getTheory().constant( BigInteger.ZERO, newArgs[0].getSort()); setResult(appTerm.getTheory().term(name, args)); } else { super.convertApplicationTerm(appTerm, newArgs); } } }