import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Map; import java.util.Set; import freeboogie.ast.*; // TODO: Some nonnullness assertions need to be added // NOTE A bunch of provers are supposed to reuse the same builder. // NOTE Sort constructors (such as * -> *) should be necessary only if // the prover is higher-order. That is not supported. // NOTE I don't want to distinguish axioms from assumptions. // NOTE The prover does not know about the `background predicate'; // that is the responsability of the VCgen class TermType { private Class cls; private Sort[] argSorts; private Sort naryArgSort; private Sort retSort; public Class cls() { return cls; } public Sort[] argSorts() { return argSorts; } public Sort naryArgSort() { return naryArgSort; } public Sort retSort() { return retSort; } public TermType(Sort[] argSorts, Sort retSort) { this.argSorts = argSorts; this.retSort = retSort; } public TermType(Sort naryArgSort, Sort retSort) { this.naryArgSort = retSort; this.retSort = retSort; } public TermType(Class cls, Sort retSort) { this.cls = cls; this.retSort = retSort; } } // NOTE Sorts don't vary too much from prover to prover. enum Sort { ANY(null), PRED(ANY), VALUE(ANY), INT(VALUE), BOOL(VALUE), REAL(VALUE), REF(VALUE); public final Sort superSort; Sort(Sort superSort) { this.superSort = superSort; } public boolean isSubSortOf(Sort other) { if (this == other) return true; if (superSort == null) return false; return superSort.isSubSortOf(other); } public Sort superSort() { return superSort; } } class Term { private Sort sort; public Term(Sort sort) { this.sort = sort; } public Sort sort() { return sort; } } // A standard utility, not really related to the prover backend. class StackedHashMap<K, V> implements Map<K, V> { private LinkedList<LinkedHashMap<K, V>> data = new LinkedList<LinkedHashMap<K, V>>(); // The extra methods public void push() { data.addFirst(new LinkedHashMap<K, V>()); } public void pop() { data.removeFirst(); } // The Map<K, V> interface implementation public void clear() { data.clear(); } public boolean containsKey(Object key) { return get(key) != null; } public boolean containsValue(Object value) { for (LinkedHashMap<K, V> h : data) if (h.containsValue(value)) return true; return false; } public Set<Map.Entry<K, V>> entrySet() { Set<Map.Entry<K, V>> r = new LinkedHashSet<Map.Entry<K, V>>(); for (LinkedHashMap<K, V> h : data) r.addAll(h.entrySet()); return r; } public boolean equals(Object other) { return false; // todo } public V get(Object key) { return null; // todo } public int hashCode() { return 0; // todo } public boolean isEmpty() { return size() == 0; } public Set<K> keySet() { return null; // todo } public V put(K key, V value) { return null; // todo } public void putAll(Map<? extends K, ? extends V> m) { // todo } public V remove(Object key) { return null; // todo } public int size() { return 0; // todo } public Collection<V> values() { return null; // todo } } public abstract class Builder { private StackedHashMap<String, TermType> termTypes = new StackedHashMap<String, TermType>(); public void reg(String name, Sort[] argSorts, Sort retSort) { assert termTypes.get(name) == null; // attempted to register `name' twice termTypes.put(name, new TermType(argSorts, retSort)); } public void reg(String name, Sort naryArgSort, Sort retSort) { assert termTypes.get(name) == null; // attempted to register `name' twice termTypes.put(name, new TermType(naryArgSort, retSort)); } public void reg(String name, Class cls, Sort retSort) { assert termTypes.get(name) == null; // attempted to register `name' twice termTypes.put(name, new TermType(cls, retSort)); } public void unreg(String name) { termTypes.remove(name); } public void pushReg() { termTypes.push(); } public void popReg() { termTypes.pop(); } public TermType getTermType(String name) { TermType r = termTypes.get(name); assert r != null; // attempted to use an unregistered name return r; } public final Term mk(String termId, Object a) { TermType type = getTermType(termId); assert type.cls() != null; assert type.cls().isInstance(a); Term r = reallyMk(termId, a); assert r.sort().isSubSortOf(type.retSort()); return r; } public final Term mk(String termId, Term a) { return mk(termId, new Term[] {a}); } public final Term mk(String termId, Term a, Term b) { return mk(termId, new Term[] {a, b}); } public final Term mk(String termId, Term[] a) { TermType type = getTermType(termId); if (type.naryArgSort() != null) { for (int i = 0; i < a.length; ++i) assert a[i].sort().isSubSortOf(type.naryArgSort()); Term r = reallyMkNary(termId, a); assert r.sort().isSubSortOf(type.retSort()); return r; } if (type.argSorts() != null) { assert type.argSorts().length == a.length; for (int i = 0; i < a.length; ++i) assert a[i].sort().isSubSortOf(type.argSorts()[i]); Term r = reallyMk(termId, a); assert r.sort().isSubSortOf(type.retSort()); return r; } assert false; return null; } protected abstract Term reallyMk(String termId, Object a); protected abstract Term reallyMk(String termId, Term[] a); protected abstract Term reallyMkNary(String termId, Term[] a); } interface ProverAnswer {} class ProverException extends Exception { private ProverAnswer answer; public ProverException(String reason) { this(reason, null); } public ProverException(ProverAnswer answer) { this("", answer); } public ProverException(String reason, ProverAnswer answer) { super(reason); this.answer = answer; } } // NOTE Prover handles things like introducing definitions, // exploiting stuff like bg_push and bg_pop, and so on. interface Prover { public Builder getBuilder(); // TODO Check that t is a predicate here? public void makeAssumption(Term t) throws ProverException; public void retractAssumption() throws ProverException; public boolean isSat(Term t) throws ProverException; public ProverAnswer getDetailedAnswer(); // also, resend all the previous assumptions public void restartProver() throws ProverException; } class ConcreteBuilder extends Builder { public ConcreteBuilder() { // built-in operators reg("and", Sort.BOOL, Sort.BOOL); // built-in functions? // constants reg("const_int", Integer.class, Sort.INT); reg("const_bool", Boolean.class, Sort.BOOL); // to-be-bound variables reg("var_int", String.class, Sort.INT); reg("var_bool", String.class, Sort.BOOL); // quantifiers reg("any_int", new Sort[]{Sort.INT, Sort.PRED}, Sort.PRED); reg("exists_int", new Sort[]{Sort.INT, Sort.PRED}, Sort.PRED); // (idea: a bunch of provers reuse the same builder) } protected Term reallyMk(String termId, Object a) { return new Term(null); } protected Term reallyMk(String termId, Term[] a) { return new Term(null); } protected Term reallyMkNary(String termId, Term[] a) { return new Term(null); } } class ConcreteProver implements Prover { public ConcreteBuilder getBuilder() { return new ConcreteBuilder(); } public void makeAssumption(Term t) { assert t.sort() == Sort.PRED; // todo } public void retractAssumption() { // todo } public boolean isSat(Term t) { return false; // todo } public ProverAnswer getDetailedAnswer() { return null; // todo } public void restartProver() throws ProverException { // todo } } // NOTE The VCgen is responsible for high-level decisions such as // whether an axiomatization of integerAdd is necessary or the // built in `+' is used. class VcGen { private Prover p; private Builder b; public VcGen(Prover p) { this.p = p; b = p.getBuilder(); } public Term visitBinaryOp(BinaryOp bo, BinaryOp.Op op, Expr left, Expr right) { return b.mk("and", visitExpr(left), visitExpr(right)); } public Term visitExpr(Expr expr) { return b.mk("var_int", "x"); // an integer named "x" } }