/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang * * 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 edu.mit.csail.sdg.alloy4compiler.translator; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.Map; import java.io.PrintWriter; import java.io.StringWriter; 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.IfExpression; import kodkod.ast.IfIntExpression; import kodkod.ast.IntComparisonFormula; import kodkod.ast.IntConstant; import kodkod.ast.IntExpression; import kodkod.ast.IntToExprCast; import kodkod.ast.NaryExpression; import kodkod.ast.NaryFormula; import kodkod.ast.NaryIntExpression; import kodkod.ast.Node; import kodkod.ast.ProjectExpression; import kodkod.ast.MultiplicityFormula; import kodkod.ast.NotFormula; import kodkod.ast.QuantifiedFormula; import kodkod.ast.Relation; import kodkod.ast.RelationPredicate; import kodkod.ast.UnaryExpression; import kodkod.ast.SumExpression; import kodkod.ast.UnaryIntExpression; import kodkod.ast.Variable; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.RelationPredicate.Function; import kodkod.ast.visitor.ReturnVisitor; import kodkod.ast.visitor.VoidVisitor; import kodkod.instance.Bounds; import kodkod.instance.TupleSet; import kodkod.instance.Tuple; import kodkod.util.ints.IndexedEntry; import kodkod.util.nodes.PrettyPrinter; /** Translate a Kodkod formula node to an equivalent Java program that solves the formula. * * <p> Requirements: atoms must be String objects (since we cannot possibly * output a Java source code that can re-generate arbitrary Java objects). */ public final class TranslateKodkodToJava implements VoidVisitor { /** Count the height of the given Kodkod AST tree. */ public static int countHeight(Node node) { ReturnVisitor<Integer,Integer,Integer,Integer> vis = new ReturnVisitor<Integer,Integer,Integer,Integer>() { private int max(int a, int b) { return (a>=b) ? a : b; } private int max(int a, int b, int c) { return (a>=b) ? (a>=c ? a : c) : (b>=c ? b: c); } public Integer visit(Relation x) { return 1; } public Integer visit(IntConstant x) { return 1; } public Integer visit(ConstantFormula x) { return 1; } public Integer visit(Variable x) { return 1; } public Integer visit(ConstantExpression x) { return 1; } public Integer visit(NotFormula x) { return 1 + x.formula().accept(this); } public Integer visit(IntToExprCast x) { return 1 + x.intExpr().accept(this); } public Integer visit(Decl x) { return 1 + x.expression().accept(this); } public Integer visit(ExprToIntCast x) { return 1 + x.expression().accept(this); } public Integer visit(UnaryExpression x) { return 1 + x.expression().accept(this); } public Integer visit(UnaryIntExpression x) { return 1 + x.intExpr().accept(this); } public Integer visit(MultiplicityFormula x) { return 1 + x.expression().accept(this); } public Integer visit(BinaryExpression x) { return 1 + max(x.left().accept(this), x.right().accept(this)); } public Integer visit(ComparisonFormula x) { return 1 + max(x.left().accept(this), x.right().accept(this)); } public Integer visit(BinaryFormula x) { return 1 + max(x.left().accept(this), x.right().accept(this)); } public Integer visit(BinaryIntExpression x) { return 1 + max(x.left().accept(this), x.right().accept(this)); } public Integer visit(IntComparisonFormula x) { return 1 + max(x.left().accept(this), x.right().accept(this)); } public Integer visit(IfExpression x) { return 1 + max(x.condition().accept(this), x.thenExpr().accept(this), x.elseExpr().accept(this)); } public Integer visit(IfIntExpression x) { return 1 + max(x.condition().accept(this), x.thenExpr().accept(this), x.elseExpr().accept(this)); } public Integer visit(SumExpression x) { return 1 + max(x.decls().accept(this), x.intExpr().accept(this)); } public Integer visit(QuantifiedFormula x) { return 1 + max(x.decls().accept(this), x.formula().accept(this)); } public Integer visit(Comprehension x) { return 1 + max(x.decls().accept(this), x.formula().accept(this)); } public Integer visit(Decls x) { int max = 0, n = x.size(); for(int i=0; i<n; i++) max = max(max, x.get(i).accept(this)); return max; } public Integer visit(ProjectExpression x) { int max = x.expression().accept(this); for(Iterator<IntExpression> t = x.columns(); t.hasNext();) { max = max(max, t.next().accept(this)); } return max; } public Integer visit(RelationPredicate x) { if (x instanceof Function) { Function f = ((Function)x); return max(f.domain().accept(this), f.range().accept(this)); } return 1; } public Integer visit(NaryExpression x) { int max = 0; for(int m=0, n=x.size(), i=0; i<n; i++) { m=x.child(i).accept(this); if (i==0 || max<m) max=m; } return max + 1; } public Integer visit(NaryIntExpression x) { int max = 0; for(int m=0, n=x.size(), i=0; i<n; i++) { m=x.child(i).accept(this); if (i==0 || max<m) max=m; } return max + 1; } public Integer visit(NaryFormula x) { int max = 0; for(int m=0, n=x.size(), i=0; i<n; i++) { m=x.child(i).accept(this); if (i==0 || max<m) max=m; } return max + 1; } }; Object ans = node.accept(vis); if (ans instanceof Integer) return ((Integer)ans).intValue(); else return 0; } /** Given a Kodkod formula node, return a Java program that (when compiled and executed) would solve that formula. * * <p> Requirement: atoms must be String objects (since we cannot possibly * output a Java source code that can re-generate arbitrary Java objects). * * @param formula - the formula to convert * @param bitwidth - the integer bitwidth * @param atoms - an iterator over the set of all atoms * @param bounds - the Kodkod bounds object to use * @param atomMap - if nonnull, it is used to map the atom name before printing */ public static String convert (Formula formula, int bitwidth, Iterable<String> atoms, Bounds bounds, Map<Object,String> atomMap) { StringWriter string=new StringWriter(); PrintWriter file=new PrintWriter(string); new TranslateKodkodToJava(file, formula, bitwidth, atoms, bounds, atomMap); if (file.checkError()) { return ""; // shouldn't happen } else { return string.toString(); } } /** The PrintWriter that is receiving the text. */ private final PrintWriter file; /** This caches nodes that we have already generated. */ private final IdentityHashMap<Node,String> map=new IdentityHashMap<Node,String>(); /** Given a node, return its name (if no name has been chosen, then make a new name) */ private String makename(Node obj) { if (map.containsKey(obj)) return null; String name="x"+(map.size()); map.put(obj, name); return name; } /** Given a node, call the visitor to dump its text out, then return its name. */ private String make(Node x) { x.accept(this); return map.get(x); } /** Constructor is private, so that the only way to access this class is via the static convert() method. */ private TranslateKodkodToJava (PrintWriter pw, Formula x, int bitwidth, Iterable<String> atoms, Bounds bounds, Map<Object,String> atomMap) { file=pw; file.printf("import java.util.Arrays;%n"); file.printf("import java.util.List;%n"); file.printf("import kodkod.ast.*;%n"); file.printf("import kodkod.ast.operator.*;%n"); file.printf("import kodkod.instance.*;%n"); file.printf("import kodkod.engine.*;%n"); file.printf("import kodkod.engine.satlab.SATFactory;%n"); file.printf("import kodkod.engine.config.Options;%n%n"); file.printf("/* %n"); file.printf(" ==================================================%n"); file.printf(" kodkod formula: %n"); file.printf(" ==================================================%n"); file.print(PrettyPrinter.print(x, 4) + "\n"); file.printf(" ==================================================%n"); file.printf("*/%n"); file.printf("public final class Test {%n%n"); file.printf("public static void main(String[] args) throws Exception {%n%n"); ArrayList<String> atomlist=new ArrayList<String>(); for(Object a:atoms) { String b = atomMap==null ? null : atomMap.get(a); atomlist.add(b==null ? a.toString() : b); } Collections.sort(atomlist); for(Relation r:bounds.relations()) { String name=makename(r); int a=r.arity(); if (a==1) file.printf("Relation %s = Relation.unary(\"%s\");%n", name, r.name()); else file.printf("Relation %s = Relation.nary(\"%s\", %d);%n", name, r.name(), a); } file.printf("%nList<String> atomlist = Arrays.asList(%n"); int j=(-1); for(String a:atomlist) { if (j!=(-1)) file.printf(","); else j=0; if (j==5) {file.printf("%n "); j=0;} else {file.printf(" "); j++;} file.printf("\"%s\"", a); } file.printf("%n);%n%n"); file.printf("Universe universe = new Universe(atomlist);%n"); file.printf("TupleFactory factory = universe.factory();%n"); file.printf("Bounds bounds = new Bounds(universe);%n%n"); for(Relation r:bounds.relations()) { String n=map.get(r); TupleSet upper=bounds.upperBound(r); TupleSet lower=bounds.lowerBound(r); printTupleset(n+"_upper", upper, atomMap); if (upper.equals(lower)) { file.printf("bounds.boundExactly(%s, %s_upper);%n%n",n,n); } else if (lower.size()==0) { file.printf("bounds.bound(%s, %s_upper);%n%n",n,n); } else { printTupleset(n+"_lower", lower, atomMap); file.printf("bounds.bound(%s, %s_lower, %s_upper);%n%n",n,n,n); } } for(IndexedEntry<TupleSet> i:bounds.intBounds()) { for(Tuple t:i.value()) { Object a = t.atom(0); String b = (atomMap!=null ? atomMap.get(a) : null); String c = (b!=null? b : a.toString()); file.printf("bounds.boundExactly(%d,factory.range(" +"factory.tuple(\"%s\"),factory.tuple(\"%s\")));%n", i.index(), c, c); } } file.printf("%n"); String result=make(x); file.printf("%nSolver solver = new Solver();"); file.printf("%nsolver.options().setSolver(SATFactory.DefaultSAT4J);"); file.printf("%nsolver.options().setBitwidth(%d);",bitwidth != 0 ? bitwidth : 1); file.printf("%nsolver.options().setFlatten(false);"); file.printf("%nsolver.options().setIntEncoding(Options.IntEncoding.TWOSCOMPLEMENT);"); file.printf("%nsolver.options().setSymmetryBreaking(20);"); file.printf("%nsolver.options().setSkolemDepth(0);"); file.printf("%nSystem.out.println(\"Solving...\");"); file.printf("%nSystem.out.flush();"); file.printf("%nSolution sol = solver.solve(%s,bounds);", result); file.printf("%nSystem.out.println(sol.toString());"); file.printf("%n}}%n"); file.close(); } /** Print the tupleset using the name n. */ private void printTupleset(String n, TupleSet ts, Map<Object,String> atomMap) { file.printf("TupleSet %s = factory.noneOf(%d);%n", n, ts.arity()); for(Tuple t:ts) { file.printf("%s.add(",n); for(int i=0; i<ts.arity(); i++) { if (i!=0) file.printf(".product("); Object a=t.atom(i); String b=atomMap==null ? null : atomMap.get(a); file.printf("factory.tuple(\"%s\")" , (b==null ? a.toString() : b) ); if (i!=0) file.printf(")"); } file.printf(");%n"); } } /** {@inheritDoc} */ public void visit(Relation x) { if (!map.containsKey(x)) throw new RuntimeException("Unknown kodkod relation \""+x.name()+"\" encountered"); } /** {@inheritDoc} */ public void visit(BinaryExpression x) { String newname=makename(x); if (newname==null) return; String left=make(x.left()); String right=make(x.right()); switch(x.op()) { case DIFFERENCE: file.printf("Expression %s=%s.difference(%s);%n", newname, left, right); break; case INTERSECTION: file.printf("Expression %s=%s.intersection(%s);%n", newname, left, right); break; case JOIN: file.printf("Expression %s=%s.join(%s);%n", newname, left, right); break; case OVERRIDE: file.printf("Expression %s=%s.override(%s);%n", newname, left, right); break; case PRODUCT: file.printf("Expression %s=%s.product(%s);%n", newname, left, right); break; case UNION: file.printf("Expression %s=%s.union(%s);%n", newname, left, right); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(ComparisonFormula x) { String newname=makename(x); if (newname==null) return; String left=make(x.left()); String right=make(x.right()); switch(x.op()) { case EQUALS: file.printf("Formula %s=%s.eq(%s);%n", newname, left, right); break; case SUBSET: file.printf("Formula %s=%s.in(%s);%n", newname, left, right); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(ProjectExpression x) { String newname=makename(x); if (newname==null) return; String expr=make(x.expression()); List<String> names=new ArrayList<String>(); for(Iterator<IntExpression> i = x.columns(); i.hasNext(); ) { names.add(make(i.next())); } for(int i=0; i<names.size(); i++) { if (i==0) file.printf("Expression %s=%s.over(", newname, expr); else file.printf(","); file.printf("%s", names.get(i)); } file.printf(");%n"); } /** {@inheritDoc} */ public void visit(IntComparisonFormula x) { String newname=makename(x); if (newname==null) return; String left=make(x.left()); String right=make(x.right()); switch(x.op()) { case NEQ: file.printf("Formula %s=%s.neq(%s);%n", newname, left, right); break; case EQ: file.printf("Formula %s=%s.eq(%s);%n", newname, left, right); break; case GT: file.printf("Formula %s=%s.gt(%s);%n", newname, left, right); break; case GTE: file.printf("Formula %s=%s.gte(%s);%n", newname, left, right); break; case LT: file.printf("Formula %s=%s.lt(%s);%n", newname, left, right); break; case LTE: file.printf("Formula %s=%s.lte(%s);%n", newname, left, right); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(BinaryFormula x) { String newname=makename(x); if (newname==null) return; String left=make(x.left()); String right=make(x.right()); switch(x.op()) { case AND: file.printf("Formula %s=%s.and(%s);%n", newname, left, right); break; case OR: file.printf("Formula %s=%s.or(%s);%n", newname, left, right); break; case IMPLIES: file.printf("Formula %s=%s.implies(%s);%n", newname, left, right); break; case IFF: file.printf("Formula %s=%s.iff(%s);%n", newname, left, right); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(BinaryIntExpression x) { String newname=makename(x); if (newname==null) return; String left=make(x.left()); String right=make(x.right()); switch(x.op()) { case PLUS: file.printf("IntExpression %s=%s.plus(%s);%n", newname, left, right); break; case MINUS: file.printf("IntExpression %s=%s.minus(%s);%n", newname, left, right); break; case MULTIPLY: file.printf("IntExpression %s=%s.multiply(%s);%n", newname, left, right); break; case DIVIDE: file.printf("IntExpression %s=%s.divide(%s);%n", newname, left, right); break; case MODULO: file.printf("IntExpression %s=%s.modulo(%s);%n", newname, left, right); break; case AND: file.printf("IntExpression %s=%s.and(%s);%n", newname, left, right); break; case OR: file.printf("IntExpression %s=%s.or(%s);%n", newname, left, right); break; case XOR: file.printf("IntExpression %s=%s.xor(%s);%n", newname, left, right); break; case SHA: file.printf("IntExpression %s=%s.sha(%s);%n", newname, left, right); break; case SHL: file.printf("IntExpression %s=%s.shl(%s);%n", newname, left, right); break; case SHR: file.printf("IntExpression %s=%s.shr(%s);%n", newname, left, right); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(UnaryIntExpression x) { String newname=makename(x); if (newname==null) return; String sub=make(x.intExpr()); switch(x.op()) { case MINUS: file.printf("IntExpression %s=%s.negate();%n", newname, sub); break; case NOT: file.printf("IntExpression %s=%s.not();%n", newname, sub); break; case ABS: file.printf("IntExpression %s=%s.abs();%n", newname, sub); break; case SGN: file.printf("IntExpression %s=%s.signum();%n", newname, sub); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(UnaryExpression x) { String newname=makename(x); if (newname==null) return; String sub=make(x.expression()); switch(x.op()) { case CLOSURE: file.printf("Expression %s=%s.closure();%n", newname, sub); break; case REFLEXIVE_CLOSURE: file.printf("Expression %s=%s.reflexiveClosure();%n", newname, sub); break; case TRANSPOSE: file.printf("Expression %s=%s.transpose();%n", newname, sub); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(IfExpression x) { String newname=makename(x); if (newname==null) return; String a=make(x.condition()); String b=make(x.thenExpr()); String c=make(x.elseExpr()); file.printf("Expression %s=%s.thenElse(%s,%s);%n", newname, a, b, c); } /** {@inheritDoc} */ public void visit(IfIntExpression x) { String newname=makename(x); if (newname==null) return; String a=make(x.condition()); String b=make(x.thenExpr()); String c=make(x.elseExpr()); file.printf("IntExpression %s=%s.thenElse(%s,%s);%n", newname, a, b, c); } /** {@inheritDoc} */ public void visit(NotFormula x) { String newname=makename(x); if (newname==null) return; String sub=make(x.formula()); file.printf("Formula %s=%s.not();%n", newname, sub); } /** {@inheritDoc} */ public void visit(IntToExprCast x) { String newname=makename(x); if (newname==null) return; String sub=make(x.intExpr()); switch(x.op()) { case INTCAST: file.printf("Expression %s=%s.toExpression();%n", newname, sub); break; case BITSETCAST: file.printf("Expression %s=%s.toBitset();%n", newname, sub); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(ExprToIntCast x) { String newname=makename(x); if (newname==null) return; String sub=make(x.expression()); switch(x.op()) { case CARDINALITY: file.printf("IntExpression %s=%s.count();%n", newname, sub); break; case SUM: file.printf("IntExpression %s=%s.sum();%n", newname, sub); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(IntConstant x) { String newname=makename(x); if (newname==null) return; file.printf("IntExpression %s=IntConstant.constant(%d);%n", newname, x.value()); } /** {@inheritDoc} */ public void visit(ConstantFormula x) { if (map.containsKey(x)) return; String newname=(x.booleanValue() ? "Formula.TRUE" : "Formula.FALSE"); map.put(x,newname); } /** {@inheritDoc} */ public void visit(ConstantExpression x) { if (map.containsKey(x)) return; String newname=null; if (x==Expression.NONE) newname="Expression.NONE"; else if (x==Expression.UNIV) newname="Expression.UNIV"; else if (x==Expression.IDEN) newname="Expression.IDEN"; else if (x==Expression.INTS) newname="Expression.INTS"; else throw new RuntimeException("Unknown kodkod ConstantExpression \""+x+"\" encountered"); map.put(x,newname); } /** {@inheritDoc} */ public void visit(Variable x) { String newname=makename(x); if (newname==null) return; int a=x.arity(); if (a==1) file.printf("Variable %s=Variable.unary(\"%s\");%n", newname, x.name()); else file.printf("Variable %s=Variable.nary(\"%s\",%d);%n", newname, x.name(), a); } /** {@inheritDoc} */ public void visit(Comprehension x) { String newname=makename(x); if (newname==null) return; String d=make(x.decls()); String f=make(x.formula()); file.printf("Expression %s=%s.comprehension(%s);%n",newname,f,d); } /** {@inheritDoc} */ public void visit(QuantifiedFormula x) { String newname=makename(x); if (newname==null) return; String d=make(x.decls()); String f=make(x.formula()); switch(x.quantifier()) { case ALL: file.printf("Formula %s=%s.forAll(%s);%n",newname,f,d); break; case SOME: file.printf("Formula %s=%s.forSome(%s);%n",newname,f,d); break; default: throw new RuntimeException("Unknown kodkod quantifier \""+x.quantifier()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(SumExpression x) { String newname=makename(x); if (newname==null) return; String d=make(x.decls()); String f=make(x.intExpr()); file.printf("IntExpression %s=%s.sum(%s);%n",newname,f,d); } /** {@inheritDoc} */ public void visit(MultiplicityFormula x) { String newname=makename(x); if (newname==null) return; String sub=make(x.expression()); switch(x.multiplicity()) { case LONE: file.printf("Formula %s=%s.lone();%n",newname,sub); break; case ONE: file.printf("Formula %s=%s.one();%n",newname,sub); break; case SOME: file.printf("Formula %s=%s.some();%n",newname,sub); break; case NO: file.printf("Formula %s=%s.no();%n",newname,sub); break; default: throw new RuntimeException("Unknown kodkod multiplicity \""+x.multiplicity()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(Decl x) { String newname=makename(x); if (newname==null) return; String v=make(x.variable()); String e=make(x.expression()); switch(x.multiplicity()) { case LONE: file.printf("Decls %s=%s.loneOf(%s);%n",newname,v,e); break; case ONE: file.printf("Decls %s=%s.oneOf(%s);%n",newname,v,e); break; case SOME: file.printf("Decls %s=%s.someOf(%s);%n",newname,v,e); break; case SET: file.printf("Decls %s=%s.setOf(%s);%n",newname,v,e); break; default: throw new RuntimeException("Unknown kodkod multiplicity \""+x.multiplicity()+"\" encountered"); } } /** {@inheritDoc} */ public void visit(Decls x) { String newname=makename(x); if (newname==null) return; for (Decl y:x) { y.accept(this); } boolean first=true; file.printf("Decls %s=",newname); for(Decl y:x) { String z=map.get(y); if (first) {file.printf("%s",z); first=false;} else file.printf(".and(%s)",z); } file.printf(";%n"); } /** {@inheritDoc} */ public void visit(RelationPredicate x) { String newname=makename(x); if (newname==null) return; String rel=make(x.relation()); switch(x.name()) { case TOTAL_ORDERING: { final RelationPredicate.TotalOrdering tp = (RelationPredicate.TotalOrdering) x; String o=make(tp.ordered()); String f=make(tp.first()); String l=make(tp.last()); file.printf("Formula %s=%s.totalOrder(%s,%s,%s);%n",newname,rel,o,f,l); return; } case FUNCTION: { final RelationPredicate.Function tp = (RelationPredicate.Function) x; String domain=make(tp.domain()); String range=make(tp.range()); switch(((RelationPredicate.Function)x).targetMult()) { case ONE: file.printf("Formula %s=%s.function(%s,%s);%n",newname,rel,domain,range); return; case LONE: file.printf("Formula %s=%s.partialFunction(%s,%s);%n",newname,rel,domain,range); return; default: throw new RuntimeException("Illegal multiplicity encountered in RelationPredicate.Function"); } } case ACYCLIC: { file.printf("Formula %s=%s.acyclic();%n",newname,rel); return; } } throw new RuntimeException("Unknown RelationPredicate \""+x+"\" encountered"); } /** {@inheritDoc} */ public void visit(NaryExpression x) { String newname = makename(x); if (newname==null) return; String[] list = new String[x.size()]; for(int i=0; i<list.length; i++) list[i] = make(x.child(i)); file.printf("Expression %s=Expression.compose(ExprOperator.", newname); switch(x.op()) { case INTERSECTION: file.print("INTERSECTION"); break; case OVERRIDE: file.print("OVERRIDE"); break; case PRODUCT: file.print("PRODUCT"); break; case UNION: file.print("UNION"); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } for(int i=0; i<list.length; i++) file.printf(", %s", list[i]); file.printf(");%n"); } /** {@inheritDoc} */ public void visit(NaryIntExpression x) { String newname = makename(x); if (newname==null) return; String[] list = new String[x.size()]; for(int i=0; i<list.length; i++) list[i] = make(x.child(i)); file.printf("IntExpression %s=IntExpression.compose(IntOperator.", newname); switch(x.op()) { case PLUS: file.print("PLUS"); break; case MULTIPLY: file.print("MULTIPLY"); break; case AND: file.print("AND"); break; case OR: file.print("OR"); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } for(int i=0; i<list.length; i++) file.printf(", %s", list[i]); file.printf(");%n"); } /** {@inheritDoc} */ public void visit(NaryFormula x) { String newname = makename(x); if (newname==null) return; String[] list = new String[x.size()]; for(int i=0; i<list.length; i++) list[i] = make(x.child(i)); file.printf("Formula %s=Formula.compose(FormulaOperator.", newname); switch(x.op()) { case AND: file.print("AND"); break; case OR: file.print("OR"); break; default: throw new RuntimeException("Unknown kodkod operator \""+x.op()+"\" encountered"); } for(int i=0; i<list.length; i++) file.printf(", %s", list[i]); file.printf(");%n"); } }