diff --git a/src/main/java/de/tla2b/analysis/PredicateVsExpression.java b/src/main/java/de/tla2b/analysis/PredicateVsExpression.java new file mode 100644 index 0000000000000000000000000000000000000000..a66c5774fe30f5f346496eb2ef2840fbc2882630 --- /dev/null +++ b/src/main/java/de/tla2b/analysis/PredicateVsExpression.java @@ -0,0 +1,122 @@ +package de.tla2b.analysis; + +import java.util.HashMap; + +import de.tla2b.global.BBuildIns; +import de.tla2b.global.BBuiltInOPs; +import de.tla2b.global.TranslationGlobals; +import tla2sany.semantic.ASTConstants; +import tla2sany.semantic.LetInNode; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tlc2.tool.BuiltInOPs; + +public class PredicateVsExpression extends BuiltInOPs implements ASTConstants, + BBuildIns, TranslationGlobals { + + private final HashMap<OpDefNode, DefinitionType> definitionsTypeMap; + + public enum DefinitionType { + PREDICATE, EXPRESSION + } + + public DefinitionType getDefinitionType(OpDefNode def) { + return definitionsTypeMap.get(def); + } + + public PredicateVsExpression(ModuleNode moduleNode) { + this.definitionsTypeMap = new HashMap<OpDefNode, PredicateVsExpression.DefinitionType>(); + OpDefNode[] defs = moduleNode.getOpDefs(); + + for (int i = 0; i < defs.length; i++) { + OpDefNode def = defs[i]; + DefinitionType type = visitSemanticNode(defs[i].getBody()); + definitionsTypeMap.put(def, type); + } + + } + + private DefinitionType visitSemanticNode(SemanticNode s) { + switch (s.getKind()) { + case OpApplKind: { + return visitOppApplNode((OpApplNode) s); + } + + case LetInKind: { + LetInNode letInNode = (LetInNode) s; + return visitSemanticNode(letInNode.getBody()); + } + + } + + return DefinitionType.EXPRESSION; + } + + private DefinitionType visitOppApplNode(OpApplNode s) { + OpApplNode opApplNode = (OpApplNode) s; + int kind = opApplNode.getOperator().getKind(); + + if (kind == BuiltInKind) { + switch (getOpCode(opApplNode.getOperator().getName())) { + case OPCODE_eq: // = + case OPCODE_noteq: // /= + case OPCODE_cl: // $ConjList + case OPCODE_land: // \land + case OPCODE_dl: // $DisjList + case OPCODE_lor: // \/ + case OPCODE_equiv: // \equiv + case OPCODE_implies: // => + case OPCODE_lnot: // \lnot + case OPCODE_be: // \E x \in S : P + case OPCODE_bf: // \A x \in S : P + case OPCODE_in: // \in + case OPCODE_subseteq: // \subseteq {1,2} <: {1,2,3} + case OPCODE_unchanged: { + return DefinitionType.PREDICATE; + } + + case OPCODE_ite: // IF THEN ELSE + { + return visitSemanticNode(opApplNode.getArgs()[1]); + } + + case OPCODE_case: // CASE p1 -> e1 [] p2 -> e2 + { + OpApplNode pair = (OpApplNode) opApplNode.getArgs()[0]; + return visitSemanticNode(pair.getArgs()[1]); + } + + default: { + return DefinitionType.EXPRESSION; + } + } + } else if (kind == UserDefinedOpKind) { + return visitUserdefinedOp(s); + } + return DefinitionType.EXPRESSION; + } + + private DefinitionType visitUserdefinedOp(OpApplNode s) { + OpDefNode def = (OpDefNode) s.getOperator(); + if (BBuiltInOPs.contains(def.getName()) + && STANDARD_MODULES.contains(def.getSource() + .getOriginallyDefinedInModuleNode().getName() + .toString())) { + + switch (BBuiltInOPs.getOpcode(def.getName())) { + case B_OPCODE_lt: // < + case B_OPCODE_gt: // > + case B_OPCODE_leq: // <= + case B_OPCODE_geq: // >= + case B_OPCODE_finite: + return DefinitionType.PREDICATE; + default: + return DefinitionType.EXPRESSION; + } + + } + return getDefinitionType(def); + } +} diff --git a/src/main/java/de/tla2b/analysis/RecursiveDefinition.java b/src/main/java/de/tla2b/analysis/RecursiveDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..09b5d7a270664808036d270024beb186bc8bf68e --- /dev/null +++ b/src/main/java/de/tla2b/analysis/RecursiveDefinition.java @@ -0,0 +1,42 @@ +package de.tla2b.analysis; + +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDefNode; +import tlc2.tool.BuiltInOPs; +import de.tla2b.exceptions.NotImplementedException; + +public class RecursiveDefinition extends BuiltInOPs{ + + private OpDefNode def; + private OpApplNode ifThenElse; + + public RecursiveDefinition(OpDefNode def) throws NotImplementedException{ + this.def = def; + evalRecursiveDefinition(); + } + + private void evalRecursiveDefinition() throws NotImplementedException { + if (def.getBody() instanceof OpApplNode) { + OpApplNode o = (OpApplNode) def.getBody(); + switch (getOpCode(o.getOperator().getName())) { + case OPCODE_ite: { // IF THEN ELSE + ifThenElse = o; + return; + } + } + throw new NotImplementedException( + "Only IF/THEN/ELSE or CASE constructs are supported at the body of a recursive function."); + } else { + throw new NotImplementedException( + "Only IF/THEN/ELSE or CASE constructs are supported at the body of a recursive function."); + } + } + + public OpDefNode getOpDefNode() { + return def; + } + + public OpApplNode getIfThenElse() { + return ifThenElse; + } +} diff --git a/src/main/java/de/tla2b/analysis/RecursiveFunktion.java b/src/main/java/de/tla2b/analysis/RecursiveFunktion.java index cfae0ae2d934da527e6a165463f70628fcc6cc6f..42975537d586c6924418028496a012068cf74115 100644 --- a/src/main/java/de/tla2b/analysis/RecursiveFunktion.java +++ b/src/main/java/de/tla2b/analysis/RecursiveFunktion.java @@ -10,30 +10,31 @@ import tla2sany.semantic.OpApplNode; import tla2sany.semantic.OpDefNode; import tlc2.tool.BuiltInOPs; -public class RecursiveFunktion extends BuiltInOPs{ +public class RecursiveFunktion extends BuiltInOPs { private OpDefNode def; private OpApplNode rfs; private OpApplNode ifThenElse; - public RecursiveFunktion(OpDefNode n, OpApplNode rfs) throws NotImplementedException { + public RecursiveFunktion(OpDefNode n, OpApplNode rfs) + throws NotImplementedException { def = n; this.rfs = rfs; evalDef(); } + /** * @throws NotImplementedException * */ private void evalDef() throws NotImplementedException { ExprOrOpArgNode e = rfs.getArgs()[0]; - + System.out.println(rfs.toString(5)); if (e instanceof OpApplNode) { OpApplNode o = (OpApplNode) e; - switch (getOpCode(o.getOperator().getName())) - { - case OPCODE_ite:{ // IF THEN ELSE + switch (getOpCode(o.getOperator().getName())) { + case OPCODE_ite: { // IF THEN ELSE ifThenElse = o; return; } @@ -45,16 +46,16 @@ public class RecursiveFunktion extends BuiltInOPs{ "Only IF/THEN/ELSE or CASE constructs are supported at the body of a recursive function."); } } - - public OpDefNode getOpDefNode(){ + + public OpDefNode getOpDefNode() { return def; } - - public OpApplNode getRF(){ + + public OpApplNode getRF() { return rfs; } - - public OpApplNode getIfThenElse(){ + + public OpApplNode getIfThenElse() { return ifThenElse; } } diff --git a/src/main/java/de/tla2b/analysis/SpecAnalyser.java b/src/main/java/de/tla2b/analysis/SpecAnalyser.java index 2b19348f581a46f4779f3b2f3697789c07185e61..7ca3fb7d4e7ce61f310cda29b0d99d256b7cdf59 100644 --- a/src/main/java/de/tla2b/analysis/SpecAnalyser.java +++ b/src/main/java/de/tla2b/analysis/SpecAnalyser.java @@ -20,9 +20,6 @@ import de.tla2b.global.TranslationGlobals; import de.tla2b.types.IType; import de.tla2b.types.TLAType; - - - import tla2sany.semantic.ASTConstants; import tla2sany.semantic.AssumeNode; import tla2sany.semantic.ExprNode; @@ -74,9 +71,11 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, private ArrayList<String> definitionMacros = new ArrayList<String>(); private ArrayList<RecursiveFunktion> recursiveFunctions = new ArrayList<RecursiveFunktion>(); - + + private ArrayList<RecursiveDefinition> recursiveDefinitions = new ArrayList<RecursiveDefinition>(); + private ConfigfileEvaluator conEval; - + /** * @param m * @param conEval @@ -368,23 +367,35 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, */ private void findDefinitions() throws ConfigFileErrorException { - if(conEval != null){ + if (conEval != null) { bDefinitionsSet.addAll(conEval.getConstantOverrideTable().values()); } - + AssumeNode[] assumes = moduleNode.getAssumptions(); for (int i = 0; i < assumes.length; i++) { - visitExprNode(assumes[i].getAssume(), null); + findDefintionInExprNode(assumes[i].getAssume(), null); } if (inits != null) { for (int i = 0; i < inits.size(); i++) { - visitExprNode(inits.get(i), null); + findDefintionInExprNode(inits.get(i), null); } } + if (bOperations != null) { for (int i = 0; i < bOperations.size(); i++) { - visitExprNode(bOperations.get(i).getNode(), null); + ExprNode node = bOperations.get(i).getNode(); + + if (node instanceof OpApplNode) { + OpApplNode opApplNode = (OpApplNode) node; + if (opApplNode.getOperator().getKind() == UserDefinedOpKind + && !BBuiltInOPs.contains(opApplNode.getOperator() + .getName())) { + OpDefNode def = (OpDefNode) opApplNode.getOperator(); + node = def.getBody(); + } + } + findDefintionInExprNode(node, null); } } @@ -392,35 +403,41 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, for (int i = 0; i < invariants.size(); i++) { OpDefNode def = invariants.get(i); bDefinitionsSet.add(def); - visitExprNode(def.getBody(), null); + findDefintionInExprNode(def.getBody(), null); } } for (int i = 0; i < globalLets.size(); i++) { LetInNode letInNode = globalLets.get(i); for (int j = 0; j < letInNode.getLets().length; j++) { - visitExprNode(letInNode.getLets()[j].getBody(), null); + findDefintionInExprNode(letInNode.getLets()[j].getBody(), null); } } + HashSet<OpDefNode> defSet = new HashSet<OpDefNode>(bDefinitionsSet); + for (OpDefNode def : defSet) { + findDefintionInExprNode(def.getBody(), null); + } + } /** * @param exprOrOpArgNode */ - private void visitExprOrOpArgNode(ExprOrOpArgNode n, + private void findDefintionInExprOrOpArgNode(ExprOrOpArgNode n, FormalParamNode[] parameters) { if (n instanceof ExprNode) { - visitExprNode((ExprNode) n, parameters); + findDefintionInExprNode((ExprNode) n, parameters); } else if (n instanceof OpArgNode) { } } - private void visitExprNode(ExprNode node, FormalParamNode[] parameters) { + private void findDefintionInExprNode(ExprNode node, + FormalParamNode[] parameters) { switch (node.getKind()) { case OpApplKind: { - visitOpApplNode((OpApplNode) node, parameters); + findDefinitionInOpApplNode((OpApplNode) node, parameters); return; } case LetInKind: { @@ -431,9 +448,9 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, if (parameters != null) letParams.put(letDef, parameters); - visitExprNode(letDef.getBody(), letDef.getParams()); + findDefintionInExprNode(letDef.getBody(), letDef.getParams()); } - visitExprNode(l.getBody(), parameters); + findDefintionInExprNode(l.getBody(), parameters); return; } @@ -444,49 +461,53 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, * @param node * @throws ConfigFileErrorException */ - private void visitOpApplNode(OpApplNode node, FormalParamNode[] parameters) { + private void findDefinitionInOpApplNode(OpApplNode node, + FormalParamNode[] parameters) { switch (node.getOperator().getKind()) { case ConstantDeclKind: { for (int i = 0; i < node.getArgs().length; i++) { - visitExprOrOpArgNode(node.getArgs()[i], parameters); + findDefintionInExprOrOpArgNode(node.getArgs()[i], parameters); } return; } case VariableDeclKind: { for (int i = 0; i < node.getArgs().length; i++) { - visitExprOrOpArgNode(node.getArgs()[i], parameters); + findDefintionInExprOrOpArgNode(node.getArgs()[i], parameters); } return; } case BuiltInKind: { - visitBuiltInKind(node, parameters); + findDefinitionInBuiltInKind(node, parameters); return; } case UserDefinedOpKind: { OpDefNode def = (OpDefNode) node.getOperator(); - //TODO - ModuleNode moduleNode = def.getSource().getOriginallyDefinedInModuleNode(); - if(moduleNode.getName().toString().equals("TLA2B")){ + // TODO + ModuleNode moduleNode = def.getSource() + .getOriginallyDefinedInModuleNode(); + if (moduleNode.getName().toString().equals("TLA2B")) { return; } if (BBuiltInOPs.contains(def.getName()) && STANDARD_MODULES.contains(def.getSource() .getOriginallyDefinedInModuleNode().getName() .toString())) { - + for (int i = 0; i < node.getArgs().length; i++) { - visitExprOrOpArgNode(node.getArgs()[i], parameters); + findDefintionInExprOrOpArgNode(node.getArgs()[i], + parameters); } return; } - bDefinitionsSet.add(def); - visitExprNode(def.getBody(), def.getParams()); + if (bDefinitionsSet.add(def)) { + findDefintionInExprNode(def.getBody(), def.getParams()); + } for (int i = 0; i < node.getArgs().length; i++) { - visitExprOrOpArgNode(node.getArgs()[i], parameters); + findDefintionInExprOrOpArgNode(node.getArgs()[i], parameters); } return; } @@ -498,7 +519,8 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, /** * @param node */ - private void visitBuiltInKind(OpApplNode node, FormalParamNode[] parameters) { + private void findDefinitionInBuiltInKind(OpApplNode node, + FormalParamNode[] parameters) { switch (BuiltInOPs.getOpCode(node.getOperator().getName())) { case OPCODE_be: @@ -509,7 +531,7 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, case OPCODE_fc: { ExprNode[] in = node.getBdedQuantBounds(); for (int i = 0; i < in.length; i++) { - visitExprNode(in[i], parameters); + findDefintionInExprNode(in[i], parameters); } break; } @@ -532,7 +554,7 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, } } for (int i = 0; i < node.getArgs().length; i++) { - visitExprOrOpArgNode(node.getArgs()[i], parameters); + findDefintionInExprOrOpArgNode(node.getArgs()[i], parameters); } } @@ -541,8 +563,16 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, * */ private void evalRecursiveFunctions() throws NotImplementedException { - - for (OpDefNode def : bDefinitionsSet) { + Set<OpDefNode> set = new HashSet<OpDefNode>(bDefinitionsSet); + for (OpDefNode def : set) { + if (def.getInRecursive()) { + bDefinitionsSet.remove(def); + // System.out.println(def.toString(7)); + RecursiveDefinition rd = new RecursiveDefinition(def); + recursiveDefinitions.add(rd); + } else + + // System.out.println(def.toString(4)); if (def.getBody() instanceof OpApplNode) { OpApplNode o = (OpApplNode) def.getBody(); switch (getOpCode(o.getOperator().getName())) { @@ -605,4 +635,9 @@ public class SpecAnalyser extends BuiltInOPs implements ASTConstants, public ArrayList<RecursiveFunktion> getRecursiveFunctions() { return recursiveFunctions; } + + public ArrayList<RecursiveDefinition> getRecursiveDefinitions(){ + return recursiveDefinitions; + } + } diff --git a/src/main/java/de/tla2b/analysis/TypeChecker.java b/src/main/java/de/tla2b/analysis/TypeChecker.java index 08b9d0b670c0d66e7c54ac6e0935adfa364288a0..b468d57ba7ca3e6705c7eeaa1015522ee58c9339 100644 --- a/src/main/java/de/tla2b/analysis/TypeChecker.java +++ b/src/main/java/de/tla2b/analysis/TypeChecker.java @@ -468,7 +468,7 @@ public class TypeChecker extends BuiltInOPs implements IType, ASTConstants, p.setToolObject(TEMP_TYPE_ID, pType); } - if (found.isUntyped() || untyped) { + if (found.isUntyped() || untyped|| def.getInRecursive() == false) { // evaluate the body of the definition again paramId = TEMP_TYPE_ID; found = visitExprNode(def.getBody(), found); @@ -1000,6 +1000,26 @@ public class TypeChecker extends BuiltInOPs implements IType, ASTConstants, } + case OPCODE_uc:{ + TLAType found = new Untyped(); + FormalParamNode x = n.getUnbdedQuantSymbols()[0]; + x.setToolObject(TYPE_ID, found); + if (found instanceof AbstractHasFollowers) { + ((AbstractHasFollowers) found).addFollower(x); + } + visitExprOrOpArgNode(n.getArgs()[0], BoolType.getInstance()); + + found = (TLAType) x.getToolObject(TYPE_ID); + try { + found = found.unify(expected); + } catch (UnificationException e) { + throw new TypeErrorException(String.format( + "Expected %s, found %s at 'CHOOSE',\n%s", expected, + found, n.getLocation())); + } + return found; + } + case OPCODE_bc: { // CHOOSE x \in S: P if (n.isBdedQuantATuple()[0]) { throw new TypeErrorException( @@ -1026,7 +1046,7 @@ public class TypeChecker extends BuiltInOPs implements IType, ASTConstants, visitExprOrOpArgNode(n.getArgs()[0], BoolType.getInstance()); return found; } - + case OPCODE_unchanged: { return BoolType.getInstance().unify(expected); } diff --git a/src/main/java/de/tla2b/analysis/UsedExternalFunctions.java b/src/main/java/de/tla2b/analysis/UsedExternalFunctions.java new file mode 100644 index 0000000000000000000000000000000000000000..c73b870bb6438b4cc2f2dfa43a3b00535188d8ee --- /dev/null +++ b/src/main/java/de/tla2b/analysis/UsedExternalFunctions.java @@ -0,0 +1,97 @@ +package de.tla2b.analysis; + +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + +import tla2sany.semantic.ASTConstants; +import tla2sany.semantic.AssumeNode; +import tla2sany.semantic.ExprNode; +import tla2sany.semantic.ExprOrOpArgNode; +import tla2sany.semantic.LetInNode; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpApplNode; +import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tlc2.tool.BuiltInOPs; + +public class UsedExternalFunctions extends BuiltInOPs implements ASTConstants { + + public enum EXTERNAL_FUNCTIONS { + CHOOSE + } + + private final Set<EXTERNAL_FUNCTIONS> usedExternalFunctions; + + public Set<EXTERNAL_FUNCTIONS> getUsedExternalFunctions() { + return usedExternalFunctions; + } + + public UsedExternalFunctions(ModuleNode moduleNode, + SpecAnalyser specAnalyser) { + usedExternalFunctions = new HashSet<UsedExternalFunctions.EXTERNAL_FUNCTIONS>(); + + AssumeNode[] assumes = moduleNode.getAssumptions(); + for (int i = 0; i < assumes.length; i++) { + AssumeNode assume = assumes[i]; + visitSemanticNode(assume.getAssume()); + } + + for (OpDefNode def : specAnalyser.getUsedDefinitions()) { + visitSemanticNode(def.getBody()); + } + + } + + private void findExternalFunctions(Hashtable<Integer, SemanticNode> table) { + for (SemanticNode sNode : table.values()) { + if (sNode instanceof OpApplNode) { + OpApplNode opApplNode = (OpApplNode) sNode; + int kind = opApplNode.getOperator().getKind(); + if (kind == BuiltInKind) { + switch (getOpCode(opApplNode.getOperator().getName())) { + case OPCODE_case: { + usedExternalFunctions.add(EXTERNAL_FUNCTIONS.CHOOSE); + } + case OPCODE_bc: { + usedExternalFunctions.add(EXTERNAL_FUNCTIONS.CHOOSE); + } + } + + } + } + } + } + + private void visitSemanticNode(SemanticNode s) { + if (s == null) + return; + if (s instanceof OpApplNode) { + OpApplNode opApplNode = (OpApplNode) s; + int kind = opApplNode.getOperator().getKind(); + if (kind == BuiltInKind) { + switch (getOpCode(opApplNode.getOperator().getName())) { + case OPCODE_case: + case OPCODE_bc: + case OPCODE_uc: { + usedExternalFunctions.add(EXTERNAL_FUNCTIONS.CHOOSE); + break; + } + } + + } + for (SemanticNode arg : opApplNode.getArgs()) { + visitSemanticNode(arg); + } + + } + + SemanticNode[] children = s.getChildren(); + if (children != null) { + for (SemanticNode semanticNode : children) { + visitSemanticNode(semanticNode); + } + } + } + +} diff --git a/src/main/java/de/tla2b/pprint/ASTPrettyPrinter.java b/src/main/java/de/tla2b/pprint/ASTPrettyPrinter.java index 16c4ca33929995d6bca34c91d0d6e8c5566d4152..27f86b256370a5341313673e44d72444e0b235f3 100644 --- a/src/main/java/de/tla2b/pprint/ASTPrettyPrinter.java +++ b/src/main/java/de/tla2b/pprint/ASTPrettyPrinter.java @@ -11,6 +11,7 @@ import de.be4.classicalb.core.parser.node.AAnySubstitution; import de.be4.classicalb.core.parser.node.ABecomesSuchSubstitution; import de.be4.classicalb.core.parser.node.ADefinitionExpression; import de.be4.classicalb.core.parser.node.ADefinitionPredicate; +import de.be4.classicalb.core.parser.node.AEmptySequenceExpression; import de.be4.classicalb.core.parser.node.AExpressionDefinitionDefinition; import de.be4.classicalb.core.parser.node.ALambdaExpression; import de.be4.classicalb.core.parser.node.AOperation; @@ -178,6 +179,7 @@ public class ASTPrettyPrinter extends ExtendedDFAdapter { putPreEnd("ACardExpression", "card(", ")"); putPreEnd("AFirstExpression", "first(", ")"); putPreEnd("ATailExpression", "tail(", ")"); + putPreEnd("AEmptySequenceExpression", "[", "]"); put("ASetExtensionExpression", null, "{", ", ", "}", null, null); put("AStructExpression", "struct", "(", ", ", ")", null, null); diff --git a/src/main/java/de/tla2b/pprint/AbstractExpressionPrinter.java b/src/main/java/de/tla2b/pprint/AbstractExpressionPrinter.java index c00c494b16388995f1a71fb5c6517f4bc5be71fa..1504c6b1edc25e18e87d5e14c82eac64d38465b9 100644 --- a/src/main/java/de/tla2b/pprint/AbstractExpressionPrinter.java +++ b/src/main/java/de/tla2b/pprint/AbstractExpressionPrinter.java @@ -781,6 +781,18 @@ public abstract class AbstractExpressionPrinter extends BuiltInOPs implements return new ExprReturn(out); } + case OPCODE_uc: { // CHOOSE x : P + out.append("CHOOSE({"); + FormalParamNode x = n.getUnbdedQuantSymbols()[0]; + out.append(getPrintName(x)); + out.append("|"); + out.append(getPrintName(x)); + out.append(visitExprOrOpArgNode(n.getArgs()[0], d, PREDICATE).out); + out.append("})"); + return new ExprReturn(out); + + } + case OPCODE_bc: { // CHOOSE x \in S: P out.append("CHOOSE({"); FormalParamNode x = n.getBdedQuantSymbolLists()[0][0]; diff --git a/src/main/java/de/tla2b/types/EnumType.java b/src/main/java/de/tla2b/types/EnumType.java index c75dc52fbeee1a7e67629892edf3ef41c78538a1..3cbe1fb2fc1230ea959a09c1543e9cfd462ca84b 100644 --- a/src/main/java/de/tla2b/types/EnumType.java +++ b/src/main/java/de/tla2b/types/EnumType.java @@ -9,7 +9,7 @@ import java.util.LinkedHashSet; import de.be4.classicalb.core.parser.node.PExpression; import de.tla2b.exceptions.UnificationException; -import de.tla2b.pprint.BAstCreator; +import de.tla2bAst.BAstCreator; diff --git a/src/main/java/de/tla2b/types/StructType.java b/src/main/java/de/tla2b/types/StructType.java index 34e52e01bfe27a9e01a97b8ad23aaf16d5f1841d..96e6cbefb3017c714c47382d5a1c4ebceb21e610 100644 --- a/src/main/java/de/tla2b/types/StructType.java +++ b/src/main/java/de/tla2b/types/StructType.java @@ -12,7 +12,7 @@ import de.be4.classicalb.core.parser.node.AStructExpression; import de.be4.classicalb.core.parser.node.PExpression; import de.be4.classicalb.core.parser.node.PRecEntry; import de.tla2b.exceptions.UnificationException; -import de.tla2b.pprint.BAstCreator; +import de.tla2bAst.BAstCreator; diff --git a/src/main/java/de/tla2b/pprint/BAstCreator.java b/src/main/java/de/tla2bAst/BAstCreator.java similarity index 76% rename from src/main/java/de/tla2b/pprint/BAstCreator.java rename to src/main/java/de/tla2bAst/BAstCreator.java index ce21166589c99f54267724e9d22a2b16c81344a7..5197cbb1fd4bd66d02468933d7776baacb716da0 100644 --- a/src/main/java/de/tla2b/pprint/BAstCreator.java +++ b/src/main/java/de/tla2bAst/BAstCreator.java @@ -1,12 +1,14 @@ -package de.tla2b.pprint; +package de.tla2bAst; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; +import java.util.Set; import tla2sany.semantic.ASTConstants; import tla2sany.semantic.AssumeNode; @@ -14,6 +16,7 @@ import tla2sany.semantic.AtNode; import tla2sany.semantic.ExprNode; import tla2sany.semantic.ExprOrOpArgNode; import tla2sany.semantic.FormalParamNode; +import tla2sany.semantic.LetInNode; import tla2sany.semantic.ModuleNode; import tla2sany.semantic.NumeralNode; import tla2sany.semantic.OpApplNode; @@ -22,6 +25,8 @@ import tla2sany.semantic.OpDefNode; import tla2sany.semantic.StringNode; import tlc2.tool.BuiltInOPs; import tlc2.value.SetEnumValue; +import tlc2.value.Value; +import tlc2.value.ValueConstants; import de.be4.classicalb.core.parser.Definitions; import de.be4.classicalb.core.parser.node.AAbstractConstantsMachineClause; import de.be4.classicalb.core.parser.node.AAbstractMachineParseUnit; @@ -44,6 +49,7 @@ import de.be4.classicalb.core.parser.node.ADefinitionsMachineClause; import de.be4.classicalb.core.parser.node.ADisjunctPredicate; import de.be4.classicalb.core.parser.node.ADivExpression; import de.be4.classicalb.core.parser.node.ADomainExpression; +import de.be4.classicalb.core.parser.node.AEmptySequenceExpression; import de.be4.classicalb.core.parser.node.AEmptySetExpression; import de.be4.classicalb.core.parser.node.AEnumeratedSetSet; import de.be4.classicalb.core.parser.node.AEqualPredicate; @@ -118,14 +124,18 @@ import de.be4.classicalb.core.parser.node.TIdentifierLiteral; import de.be4.classicalb.core.parser.node.TIntegerLiteral; import de.be4.classicalb.core.parser.node.TStringLiteral; import de.tla2b.analysis.BOperation; +import de.tla2b.analysis.PredicateVsExpression; +import de.tla2b.analysis.RecursiveDefinition; import de.tla2b.analysis.SpecAnalyser; +import de.tla2b.analysis.UsedExternalFunctions; +import de.tla2b.analysis.PredicateVsExpression.DefinitionType; +import de.tla2b.analysis.UsedExternalFunctions.EXTERNAL_FUNCTIONS; import de.tla2b.config.ConfigfileEvaluator; import de.tla2b.config.ValueObj; import de.tla2b.global.BBuildIns; import de.tla2b.global.BBuiltInOPs; import de.tla2b.global.Priorities; import de.tla2b.global.TranslationGlobals; -import de.tla2b.types.BoolType; import de.tla2b.types.EnumType; import de.tla2b.types.FunctionType; import de.tla2b.types.IType; @@ -135,15 +145,21 @@ import de.tla2b.types.TLAType; import de.tla2b.types.TupleType; public class BAstCreator extends BuiltInOPs implements TranslationGlobals, - ASTConstants, IType, BBuildIns, Priorities { + ASTConstants, IType, BBuildIns, Priorities, ValueConstants { Start start; List<PMachineClause> machineClauseList; ConfigfileEvaluator conEval; SpecAnalyser specAnalyser; + private final PredicateVsExpression predicateVsExpression; + final int SUBSTITUTE_PARAM = 29; + + final HashSet<OpDefNode> allTLADefinitions; List<OpDeclNode> bConstants; private ModuleNode moduleNode; + private final UsedExternalFunctions usedExternalFunctions; + private Definitions bDefinitions = new Definitions(); public Start getStartNode() { @@ -156,10 +172,16 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, } public BAstCreator(ModuleNode moduleNode, ConfigfileEvaluator conEval, - SpecAnalyser specAnalyser) { + SpecAnalyser specAnalyser, + UsedExternalFunctions usedExternalFunctions, + PredicateVsExpression predicateVsExpression) { + this.predicateVsExpression = predicateVsExpression; this.conEval = conEval; this.moduleNode = moduleNode; this.specAnalyser = specAnalyser; + this.usedExternalFunctions = usedExternalFunctions; + this.allTLADefinitions = new HashSet<OpDefNode>( + Arrays.asList(moduleNode.getOpDefs())); if (conEval != null) { this.bConstants = conEval.getbConstantList(); @@ -249,24 +271,31 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, } } + Set<EXTERNAL_FUNCTIONS> set = usedExternalFunctions + .getUsedExternalFunctions(); - if (bDefs.size() == 0) { + if (bDefs.size() == 0 && set.size() == 0) { return; } ADefinitionsMachineClause defClause = new ADefinitionsMachineClause(); List<PDefinition> defs = new ArrayList<PDefinition>(); + + defs.addAll(createDefinitionsForExternalFunctions(set)); + for (OpDefNode opDefNode : bDefs) { - TLAType type = (TLAType) opDefNode.getToolObject(TYPE_ID); - if (opDefNode.level == 2 || type instanceof BoolType) { + List<PExpression> list = new ArrayList<PExpression>(); + for (int i = 0; i < opDefNode.getParams().length; i++) { + FormalParamNode p = opDefNode.getParams()[i]; + list.add(createIdentifierNode(p.getName().toString())); + } + + // TLAType type = (TLAType) opDefNode.getToolObject(TYPE_ID); + // if (opDefNode.level == 2 || type instanceof BoolType) { + if (predicateVsExpression.getDefinitionType(opDefNode) == DefinitionType.PREDICATE) { APredicateDefinitionDefinition d = new APredicateDefinitionDefinition(); d.setName(new TDefLiteralPredicate(opDefNode.getName() - .toString() + "_def")); - List<PExpression> list = new ArrayList<PExpression>(); - for (int i = 0; i < opDefNode.getParams().length; i++) { - FormalParamNode p = opDefNode.getParams()[i]; - list.add(createIdentifierNode(p.getName().toString())); - } + .toString())); d.setParameters(list); d.setRhs(visitExprNodePredicate(opDefNode.getBody())); defs.add(d); @@ -274,11 +303,7 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, } else { AExpressionDefinitionDefinition d = new AExpressionDefinitionDefinition(); d.setName(new TIdentifierLiteral(opDefNode.getName().toString())); - List<PExpression> list = new ArrayList<PExpression>(); - for (int i = 0; i < opDefNode.getParams().length; i++) { - FormalParamNode p = opDefNode.getParams()[i]; - list.add(createIdentifierNode(p.getName().toString())); - } + d.setParameters(list); d.setRhs(visitExprNodeExpression(opDefNode.getBody())); defs.add(d); @@ -290,6 +315,29 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, machineClauseList.add(defClause); } + private ArrayList<PDefinition> createDefinitionsForExternalFunctions( + Set<EXTERNAL_FUNCTIONS> set) { + ArrayList<PDefinition> list = new ArrayList<PDefinition>(); + + if (set.contains(UsedExternalFunctions.EXTERNAL_FUNCTIONS.CHOOSE)) { + AExpressionDefinitionDefinition def1 = new AExpressionDefinitionDefinition(); + def1.setName(new TIdentifierLiteral("CHOOSE")); + def1.setParameters(createIdentifierList("X")); + def1.setRhs(new AStringExpression(new TStringLiteral( + "a member of X"))); + list.add(def1); + AExpressionDefinitionDefinition def2 = new AExpressionDefinitionDefinition(); + def2.setName(new TIdentifierLiteral("EXTERNAL_FUNCTION_CHOOSE")); + def2.setParameters(createIdentifierList("T")); + ATotalFunctionExpression total = new ATotalFunctionExpression(); + total.setLeft(new APowSubsetExpression(createIdentifierNode("T"))); + total.setRight(createIdentifierNode("T")); + def2.setRhs(total); + list.add(def2); + } + return list; + } + private void createOperationsClause() { ArrayList<BOperation> bOperations = specAnalyser.getBOperations(); if (bOperations == null || bOperations.size() == 0) { @@ -309,7 +357,7 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, OpApplNode o = op.getExistQuans().get(j); whereList.add(visitBounded(o)); } - + AOperation operation = new AOperation(); operation.setOpName(createTIdentifierLiteral(defName)); operation.setParameters(paramList); @@ -333,7 +381,27 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, } any.setIdentifiers(anyParams); - whereList.add(visitExprOrOpArgNodePredicate(op.getNode())); + PPredicate body = null; + if (op.getNode() instanceof OpApplNode) { + OpApplNode opApplNode = (OpApplNode) op.getNode(); + if (opApplNode.getOperator().getKind() == UserDefinedOpKind + && !BBuiltInOPs.contains(opApplNode.getOperator() + .getName())) { + OpDefNode def = (OpDefNode) opApplNode.getOperator(); + System.out.println(def.getName()); + FormalParamNode[] params = def.getParams(); + for (int j = 0; j < params.length; j++) { + FormalParamNode param = params[j]; + param.setToolObject(SUBSTITUTE_PARAM, + opApplNode.getArgs()[j]); + } + body = visitExprNodePredicate(def.getBody()); + } + } + if (body == null) { + body = visitExprOrOpArgNodePredicate(op.getNode()); + } + whereList.add(body); any.setWhere(createConjunction(whereList)); List<PExpression> varList = new ArrayList<PExpression>(); @@ -403,22 +471,71 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, bConstants = Arrays.asList(moduleNode.getConstantDecls()); } - if (bConstants.size() > 0) { - List<PExpression> list = new ArrayList<PExpression>(); - for (OpDeclNode opDeclNode : bConstants) { - AIdentifierExpression id = new AIdentifierExpression( - createTIdentifierLiteral(opDeclNode.getName() - .toString())); - list.add(id); - } + List<PExpression> constantsList = new ArrayList<PExpression>(); + for (OpDeclNode opDeclNode : bConstants) { + AIdentifierExpression id = new AIdentifierExpression( + createTIdentifierLiteral(opDeclNode.getName().toString())); + constantsList.add(id); + } + + for (RecursiveDefinition recDef : specAnalyser + .getRecursiveDefinitions()) { + + AIdentifierExpression id = new AIdentifierExpression( + createTIdentifierLiteral(recDef.getOpDefNode().getName() + .toString())); + constantsList.add(id); + } + + if (constantsList.size() > 0) { AAbstractConstantsMachineClause abstractConstantsClause = new AAbstractConstantsMachineClause( - list); + constantsList); machineClauseList.add(abstractConstantsClause); } + } private void createPropertyClause() { - List<PPredicate> list = new ArrayList<PPredicate>(); + List<PPredicate> propertiesList = new ArrayList<PPredicate>(); + + for (RecursiveDefinition recDef : specAnalyser + .getRecursiveDefinitions()) { + OpDefNode def = recDef.getOpDefNode(); + TLAType t = (TLAType) def.getToolObject(TYPE_ID); + // OpApplNode ifThenElse = recDef.getIfThenElse(); + FormalParamNode[] params = def.getParams(); + ArrayList<PExpression> paramList1 = new ArrayList<PExpression>(); + ArrayList<PPredicate> typeList = new ArrayList<PPredicate>(); + // ArrayList<PExpression> paramList2 = new ArrayList<PExpression>(); + for (FormalParamNode p : params) { + paramList1.add(createIdentifierNode(p.getName().toString())); + // paramList2.add(createIdentifierNode(p.getName().toString())); + TLAType paramType = (TLAType) p.getToolObject(TYPE_ID); + System.out.println(paramType); + AEqualPredicate equal = new AEqualPredicate( + createIdentifierNode(p.getName().toString()), + paramType.getBNode()); + typeList.add(equal); + } + ALambdaExpression lambda1 = new ALambdaExpression(); + lambda1.setIdentifiers(paramList1); + lambda1.setPredicate(createConjunction(typeList)); + lambda1.setExpression(visitExprNodeExpression(def.getBody())); + // lambda1.setPredicate(visitExprOrOpArgNodePredicate(ifThenElse.getArgs()[0])); + // lambda1.setExpression(visitExprOrOpArgNodeExpression(ifThenElse.getArgs()[1])); + + // ALambdaExpression lambda2 = new ALambdaExpression(); + // lambda2.setIdentifiers(paramList2); + // ANegationPredicate not = new + // ANegationPredicate(visitExprOrOpArgNodePredicate(ifThenElse.getArgs()[0])); + // lambda2.setPredicate(not); + // lambda2.setExpression(visitExprOrOpArgNodeExpression(ifThenElse.getArgs()[2])); + // AUnionExpression union = new AUnionExpression(lambda1, lambda2); + + AEqualPredicate equals = new AEqualPredicate( + createIdentifierNode(def.getName().toString()), lambda1); + propertiesList.add(equals); + } for (OpDeclNode con : bConstants) { if (conEval != null @@ -442,19 +559,20 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, equal.setLeft(createIdentifierNode(con.getName().toString())); equal.setRight(createIdentifierNode(((SetType) t) .getSubType().toString())); - list.add(equal); + propertiesList.add(equal); } else { AEqualPredicate equal = new AEqualPredicate(); equal.setLeft(createIdentifierNode(con.getName().toString())); - equal.setRight(createIdentifierNode(v.getValue().toString())); - list.add(equal); + Value tlcValue = v.getValue(); + equal.setRight(createTLCValue(tlcValue)); + propertiesList.add(equal); } } else { AMemberPredicate member = new AMemberPredicate(); member.setLeft(createIdentifierNode(con.getName().toString())); TLAType t = (TLAType) con.getToolObject(TYPE_ID); member.setRight(t.getBNode()); - list.add(member); + propertiesList.add(member); } } @@ -464,27 +582,49 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, while (iter.hasNext()) { Entry<OpDeclNode, OpDefNode> entry = iter.next(); OpDeclNode con = entry.getKey(); - OpDefNode def = entry.getValue(); + OpDefNode generatedDef = entry.getValue(); + OpDefNode def = null; + try { + OpApplNode opApplNode = (OpApplNode) generatedDef.getBody(); + if (opApplNode.getKind() == UserDefinedOpKind) { + def = (OpDefNode) opApplNode.getOperator(); + } else { + def = generatedDef; + } + } catch (ClassCastException e) { + def = generatedDef; + } AEqualPredicate equal = new AEqualPredicate(); equal.setLeft(createIdentifierNode(con.getName().toString())); equal.setRight(visitExprNodeExpression(def.getBody())); - list.add(equal); + propertiesList.add(equal); } } AssumeNode[] assumes = moduleNode.getAssumptions(); for (AssumeNode assumeNode : assumes) { - list.add(visitAssumeNode(assumeNode)); + propertiesList.add(visitAssumeNode(assumeNode)); } - if (list.size() == 0) - return; + if (propertiesList.size() > 0) { + APropertiesMachineClause propertiesClause = new APropertiesMachineClause(); + propertiesClause.setPredicates(createConjunction(propertiesList)); + + machineClauseList.add(propertiesClause); + } + } - APropertiesMachineClause propertiesClause = new APropertiesMachineClause(); - propertiesClause.setPredicates(createConjunction(list)); + private PExpression createTLCValue(Value tlcValue) { + switch (tlcValue.getKind()) { + case INTVALUE: - machineClauseList.add(propertiesClause); + return new AIntegerExpression(new TIntegerLiteral( + tlcValue.toString())); + + } + + throw new RuntimeException(); } private void createInvariantClause() { @@ -507,7 +647,7 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, for (OpDefNode def : conEval.getInvariants()) { ADefinitionPredicate defPred = new ADefinitionPredicate(); defPred.setDefLiteral(new TDefLiteralPredicate(def.getName() - .toString() + "_def")); + .toString())); predList.add(defPred); } } @@ -526,11 +666,19 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, case OpApplKind: return visitOpApplNodePredicate((OpApplNode) n); + case LetInKind: { + LetInNode letInNode = (LetInNode) n; + return visitExprNodePredicate(letInNode.getBody()); + } + case NumeralKind: { + throw new RuntimeException(); } } + System.out.println(n); + System.out.println(n.getClass()); throw new RuntimeException(); } @@ -551,30 +699,42 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, return new AStringExpression(new TStringLiteral(s.getRep() .toString())); } - + case AtNodeKind: { // @ AtNode at = (AtNode) n; TLAType type = (TLAType) at.getExceptRef().getToolObject(TYPE_ID); - if(type instanceof FunctionType){ - - OpApplNode seq = at.getAtModifier(); - LinkedList<ExprOrOpArgNode> list = new LinkedList<ExprOrOpArgNode>(); - for (int j = 0; j < seq.getArgs().length; j++) { - list.add(seq.getArgs()[j]); - } + OpApplNode seq = at.getAtModifier(); + LinkedList<ExprOrOpArgNode> list = new LinkedList<ExprOrOpArgNode>(); + for (int j = 0; j < seq.getArgs().length; j++) { + list.add(seq.getArgs()[j]); + } + if (type instanceof FunctionType) { + List<PExpression> params = new ArrayList<PExpression>(); params.add(visitExprOrOpArgNodeExpression(list.get(0))); - + AFunctionExpression funCall = new AFunctionExpression(); funCall.setIdentifier(visitExprNodeExpression(at.getAtBase())); funCall.setParameters(params); return funCall; + } else { + ARecordFieldExpression select = new ARecordFieldExpression(); + select.setRecord(visitExprNodeExpression(at.getAtBase())); + StringNode stringNode = (StringNode) list.get(0); + select.setIdentifier(createIdentifierNode(stringNode.getRep() + .toString())); + return select; } - throw new RuntimeException(); } + case LetInKind: { + LetInNode letInNode = (LetInNode) n; + return visitExprNodeExpression(letInNode.getBody()); } + } + + System.out.println(n.getClass()); throw new RuntimeException(); } @@ -611,7 +771,16 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, } case FormalParamKind: { - return createIdentifierNode(n.getOperator().getName().toString()); + FormalParamNode param = (FormalParamNode) n.getOperator(); + ExprOrOpArgNode e = (ExprOrOpArgNode) param + .getToolObject(SUBSTITUTE_PARAM); + if (e == null) { + return createIdentifierNode(n.getOperator().getName() + .toString()); + } else { + return visitExprOrOpArgNodeExpression(e); + } + } case BuiltInKind: @@ -628,23 +797,35 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, private PPredicate visitUserdefinedOpPredicate(OpApplNode n) { OpDefNode def = (OpDefNode) n.getOperator(); - // Operator is a B built-in operator - if (BBuiltInOPs.contains(def.getName()) + + if (BBuiltInOPs.contains(def.getName()) // Operator is a B built-in + // operator && STANDARD_MODULES.contains(def.getSource() .getOriginallyDefinedInModuleNode().getName() .toString())) { return visitBBuitInsPredicate(n); } - ADefinitionPredicate defCall = new ADefinitionPredicate(); - defCall.setDefLiteral(new TDefLiteralPredicate(def.getName().toString() - + "_def")); - List<PExpression> list = new ArrayList<PExpression>(); + List<PExpression> params = new ArrayList<PExpression>(); for (int i = 0; i < n.getArgs().length; i++) { - list.add(visitExprOrOpArgNodeExpression(n.getArgs()[i])); + params.add(visitExprOrOpArgNodeExpression(n.getArgs()[i])); + } + if (predicateVsExpression.getDefinitionType(def) == DefinitionType.EXPRESSION) { + ADefinitionExpression defCall = new ADefinitionExpression(); + defCall.setDefLiteral(new TIdentifierLiteral(def.getName() + .toString())); + ; + defCall.setParameters(params); + return new AEqualPredicate(defCall, new ABooleanTrueExpression()); + + } else { + ADefinitionPredicate defCall = new ADefinitionPredicate(); + defCall.setDefLiteral(new TDefLiteralPredicate(def.getName() + .toString())); + + defCall.setParameters(params); + return defCall; } - defCall.setParameters(list); - return defCall; } private PExpression visitUserdefinedOpExpression(OpApplNode n) { @@ -657,16 +838,50 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, return visitBBuitInsExpression(n); } - // new Definition or what else - ADefinitionExpression defExpr = new ADefinitionExpression(); - defExpr.setDefLiteral(new TIdentifierLiteral(n.getOperator().getName() - .toString())); - List<PExpression> list = new ArrayList<PExpression>(); - for (int i = 0; i < n.getArgs().length; i++) { - list.add(visitExprOrOpArgNodeExpression(n.getArgs()[i])); + if (allTLADefinitions.contains(def)) { + List<PExpression> params = new ArrayList<PExpression>(); + for (int i = 0; i < n.getArgs().length; i++) { + params.add(visitExprOrOpArgNodeExpression(n.getArgs()[i])); + } + + if (conEval != null + && conEval.getConstantOverrideTable().containsValue(def)) { + // used constants name instead of the definition overriding the + // constant + Iterator<Entry<OpDeclNode, OpDefNode>> iter = conEval + .getConstantOverrideTable().entrySet().iterator(); + String name = null; + while (iter.hasNext()) { + Entry<OpDeclNode, OpDefNode> entry = iter.next(); + if (entry.getValue().equals(def)) { + name = entry.getKey().getName().toString(); + } + } + if (params.size() == 0) { + return createIdentifierNode(name); + } else { + AFunctionExpression funcCall = new AFunctionExpression(); + funcCall.setIdentifier(createIdentifierNode(name)); + funcCall.setParameters(params); + return funcCall; + } + } else { + ADefinitionExpression defExpr = new ADefinitionExpression(); + defExpr.setDefLiteral(new TIdentifierLiteral(n.getOperator() + .getName().toString())); + defExpr.setParameters(params); + return defExpr; + } + + } else { + FormalParamNode[] params = def.getParams(); + for (int i = 0; i < params.length; i++) { + FormalParamNode param = params[i]; + param.setToolObject(SUBSTITUTE_PARAM, n.getArgs()[i]); + } + PExpression result = visitExprNodeExpression(def.getBody()); + return result; } - defExpr.setParameters(list); - return defExpr; } @@ -1131,7 +1346,11 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, if (t instanceof TupleType) { return new ACoupleExpression(list); } else { - return new ASequenceExtensionExpression(list); + if (list.size() == 0) { + return new AEmptySequenceExpression(); + } else { + return new ASequenceExtensionExpression(list); + } } } @@ -1246,12 +1465,45 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, return funCall; } + case OPCODE_case: { + return createCaseNode(n); + } + case OPCODE_exc: // Except { TLAType type = (TLAType) n.getToolObject(TYPE_ID); if (type.getKind() == STRUCT) { - System.out.println(n.getOperator().getName()); - throw new RuntimeException(); + Hashtable<String, PExpression> temp = new Hashtable<String, PExpression>(); + for (int i = 1; i < n.getArgs().length; i++) { + OpApplNode pair = (OpApplNode) n.getArgs()[i]; + ExprOrOpArgNode first = pair.getArgs()[0]; + ExprOrOpArgNode second = pair.getArgs()[1]; + OpApplNode seq = (OpApplNode) first; + + PExpression val = visitExprOrOpArgNodeExpression(second); + + StringNode stringNode = (StringNode) seq.getArgs()[0]; + String fieldName = stringNode.getRep().toString(); + temp.put(fieldName, val); + } + + StructType st = (StructType) type; + List<PRecEntry> list = new ArrayList<PRecEntry>(); + for (int i = 0; i < st.getFields().size(); i++) { + ARecEntry entry = new ARecEntry(); + String fieldName = st.getFields().get(i); + entry.setIdentifier(createIdentifierNode(fieldName)); + PExpression value = temp.get(fieldName); + if (value == null) { + value = new ARecordFieldExpression( + visitExprOrOpArgNodeExpression(n.getArgs()[0]), + createIdentifierNode(fieldName)); + } + entry.setValue(value); + list.add(entry); + } + ARecExpression rec = new ARecExpression(list); + return rec; } else { FunctionType func = (FunctionType) type; @@ -1284,12 +1536,89 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, return visitExprOrOpArgNodeExpression(n.getArgs()[0]); } + case OPCODE_uc: { // CHOOSE x : P + return createUnboundedChoose(n); + } + + case OPCODE_bc: { // CHOOSE x \in S: P + return createBoundedChoose(n); + } + } System.out.println(n.getOperator().getName()); throw new RuntimeException(); } + private PExpression createUnboundedChoose(OpApplNode n) { + ADefinitionExpression defCall = new ADefinitionExpression(); + defCall.setDefLiteral(new TIdentifierLiteral("CHOOSE")); + AComprehensionSetExpression comprehension = new AComprehensionSetExpression(); + FormalParamNode x = n.getUnbdedQuantSymbols()[0]; + comprehension.setIdentifiers(createIdentifierList(x.getName() + .toString())); + comprehension + .setPredicates(visitExprOrOpArgNodePredicate(n.getArgs()[0])); + List<PExpression> list = new ArrayList<PExpression>(); + list.add(comprehension); + defCall.setParameters(list); + return defCall; + } + + private PExpression createBoundedChoose(OpApplNode n) { + ADefinitionExpression defCall = new ADefinitionExpression(); + defCall.setDefLiteral(new TIdentifierLiteral("CHOOSE")); + AComprehensionSetExpression comprehension = new AComprehensionSetExpression(); + FormalParamNode x = n.getBdedQuantSymbolLists()[0][0]; + comprehension.setIdentifiers(createIdentifierList(x.getName() + .toString())); + AMemberPredicate member = new AMemberPredicate(); + member.setLeft(createIdentifierNode(x.getName().toString())); + ExprNode in = n.getBdedQuantBounds()[0]; + member.setRight(visitExprNodeExpression(in)); + AConjunctPredicate conj = new AConjunctPredicate(); + conj.setLeft(member); + conj.setRight(visitExprOrOpArgNodePredicate(n.getArgs()[0])); + comprehension.setPredicates(conj); + List<PExpression> list = new ArrayList<PExpression>(); + list.add(comprehension); + defCall.setParameters(list); + return defCall; + } + + private PExpression createCaseNode(OpApplNode n) { + List<PPredicate> conditions = new ArrayList<PPredicate>(); + List<PPredicate> disjunctionList = new ArrayList<PPredicate>(); + for (int i = 0; i < n.getArgs().length; i++) { + OpApplNode pair = (OpApplNode) n.getArgs()[i]; + + AConjunctPredicate conj = new AConjunctPredicate(); + if (pair.getArgs()[0] == null) { + ANegationPredicate neg = new ANegationPredicate(); + neg.setPredicate(createDisjunction(conditions)); + conj.setLeft(neg); + } else { + conditions + .add(visitExprOrOpArgNodePredicate(pair.getArgs()[0])); + conj.setLeft(visitExprOrOpArgNodePredicate(pair.getArgs()[0])); + } + AEqualPredicate equals = new AEqualPredicate(); + equals.setLeft(createIdentifierNode("t_")); + equals.setRight(visitExprOrOpArgNodeExpression(pair.getArgs()[1])); + conj.setRight(equals); + disjunctionList.add(conj); + } + AComprehensionSetExpression comprehension = new AComprehensionSetExpression(); + comprehension.setIdentifiers(createIdentifierList("t_")); + comprehension.setPredicates(createDisjunction(disjunctionList)); + ADefinitionExpression defCall = new ADefinitionExpression(); + defCall.setDefLiteral(new TIdentifierLiteral("CHOOSE")); + List<PExpression> params = new ArrayList<PExpression>(); + params.add(comprehension); + defCall.setParameters(params); + return defCall; + } + private List<PExpression> createIdentifierList(String name) { ArrayList<PExpression> list = new ArrayList<PExpression>(); list.add(createIdentifierNode(name)); @@ -1449,6 +1778,11 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, return new AEqualPredicate(rcdSelect, new ABooleanTrueExpression()); } + case OPCODE_case: { + return new AEqualPredicate(createCaseNode(n), + new ABooleanTrueExpression()); + } + case OPCODE_prime: // prime { OpApplNode node = (OpApplNode) n.getArgs()[0]; @@ -1462,6 +1796,30 @@ public class BAstCreator extends BuiltInOPs implements TranslationGlobals, new ABooleanTrueExpression()); } + case OPCODE_uc: { // CHOOSE x : P + return new AEqualPredicate(createUnboundedChoose(n), + new ABooleanTrueExpression()); + } + + case OPCODE_bc: { // CHOOSE x \in S: P + return new AEqualPredicate(createBoundedChoose(n), + new ABooleanTrueExpression()); + } + + case OPCODE_ite: // IF THEN ELSE + { + AImplicationPredicate impl1 = new AImplicationPredicate(); + impl1.setLeft(visitExprOrOpArgNodePredicate(n.getArgs()[0])); + impl1.setRight(visitExprOrOpArgNodePredicate(n.getArgs()[1])); + + AImplicationPredicate impl2 = new AImplicationPredicate(); + ANegationPredicate neg = new ANegationPredicate( + visitExprOrOpArgNodePredicate(n.getArgs()[0])); + impl2.setLeft(neg); + impl2.setRight(visitExprOrOpArgNodePredicate(n.getArgs()[2])); + return new AConjunctPredicate(impl1, impl2); + } + case 0: return visitBBuitInsPredicate(n); diff --git a/src/main/java/de/tla2bAst/Translator.java b/src/main/java/de/tla2bAst/Translator.java index 38bff13b6a669ad59ce6e5151fdafd8907c3d28c..1ffbcc86cbe02883960b83e5729a2ea324099289 100644 --- a/src/main/java/de/tla2bAst/Translator.java +++ b/src/main/java/de/tla2bAst/Translator.java @@ -7,15 +7,16 @@ import java.io.IOException; import de.be4.classicalb.core.parser.Definitions; import de.be4.classicalb.core.parser.node.Start; import de.tla2b.analysis.InstanceTransformation; +import de.tla2b.analysis.PredicateVsExpression; import de.tla2b.analysis.SpecAnalyser; import de.tla2b.analysis.SymbolRenamer; import de.tla2b.analysis.SymbolSorter; import de.tla2b.analysis.TypeChecker; +import de.tla2b.analysis.UsedExternalFunctions; import de.tla2b.config.ConfigfileEvaluator; import de.tla2b.config.ModuleOverrider; import de.tla2b.exceptions.FrontEndException; import de.tla2b.exceptions.TLA2BException; -import de.tla2b.pprint.BAstCreator; import de.tla2b.pprint.BMachinePrinter; import tla2sany.semantic.ModuleNode; import tlc2.tool.ModelConfig; @@ -25,25 +26,26 @@ import util.ToolIO; public class Translator { private String moduleFileName; private String configFileName; - + private Definitions bDefinitions; - + private String moduleName; private ModuleNode moduleNode; private ModelConfig modelConfig; private String bMachineString; - - public Translator(String moduleFileName, String configFileName) throws FrontEndException { + + public Translator(String moduleFileName, String configFileName) + throws FrontEndException { this.moduleFileName = moduleFileName; - this.configFileName = configFileName; - + this.configFileName = configFileName; + parse(); } - - - //Used for Testing - public Translator(String moduleString, String configString, int i) throws FrontEndException { + + // Used for Testing + public Translator(String moduleString, String configString, int i) + throws FrontEndException { moduleName = "Testing"; File dir = new File("temp/"); dir.mkdirs(); @@ -54,7 +56,7 @@ public class Translator { FileWriter fw = new FileWriter(f); fw.write(moduleString); fw.close(); - //f.deleteOnExit(); + // f.deleteOnExit(); moduleFileName = f.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); @@ -63,7 +65,7 @@ public class Translator { modelConfig = null; if (configString != null) { File f = new File("temp/" + moduleName + ".cfg"); - + try { f.createNewFile(); FileWriter fw = new FileWriter(f); @@ -72,15 +74,15 @@ public class Translator { } catch (IOException e) { e.printStackTrace(); } - //f.deleteOnExit(); + // f.deleteOnExit(); configFileName = f.getAbsolutePath(); } dir.deleteOnExit(); - + parse(); } - - //Used for Testing + + // Used for Testing public Translator(String moduleString) throws FrontEndException { moduleName = "Testing"; File dir = new File("temp/"); @@ -92,7 +94,7 @@ public class Translator { FileWriter fw = new FileWriter(f); fw.write(moduleString); fw.close(); - //f.deleteOnExit(); + // f.deleteOnExit(); moduleFileName = f.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); @@ -100,8 +102,7 @@ public class Translator { parseModule(); } - - + private void parseModule() throws FrontEndException { moduleName = evalFileName(moduleFileName); @@ -109,8 +110,7 @@ public class Translator { moduleNode = tlaParser.parseModule(moduleName); } - - private void parse() throws FrontEndException{ + private void parse() throws FrontEndException { moduleName = evalFileName(moduleFileName); TLAParser tlaParser = new TLAParser(null); @@ -119,18 +119,19 @@ public class Translator { modelConfig = null; if (configFileName != null) { File f = new File(configFileName); - if(f.exists()){ + if (f.exists()) { modelConfig = new ModelConfig(f.getName(), null); modelConfig.parse(); } - }else { + } else { String fileNameWithoutSuffix = moduleFileName; if (fileNameWithoutSuffix.toLowerCase().endsWith(".tla")) { - fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, fileNameWithoutSuffix.length() - 4); + fileNameWithoutSuffix = fileNameWithoutSuffix.substring(0, + fileNameWithoutSuffix.length() - 4); } String configFile = fileNameWithoutSuffix + ".cfg"; File f = new File(configFile); - if(f.exists()){ + if (f.exists()) { modelConfig = new ModelConfig(f.getName(), null); modelConfig.parse(); } @@ -144,6 +145,9 @@ public class Translator { SymbolSorter symbolSorter = new SymbolSorter(moduleNode); symbolSorter.sort(); + PredicateVsExpression predicateVsExpression = new PredicateVsExpression( + moduleNode); + SpecAnalyser specAnalyser; ConfigfileEvaluator conEval = null; @@ -172,11 +176,15 @@ public class Translator { BMachinePrinter p = new BMachinePrinter(moduleNode, conEval, specAnalyser); bMachineString = p.start().toString(); + + UsedExternalFunctions usedExternalFunctions = new UsedExternalFunctions( + moduleNode, specAnalyser); + BAstCreator bAstCreator = new BAstCreator(moduleNode, conEval, - specAnalyser); - + specAnalyser, usedExternalFunctions, predicateVsExpression); + this.bDefinitions = bAstCreator.getBDefinitions(); - + return bAstCreator.getStartNode(); } @@ -188,8 +196,7 @@ public class Translator { if (name.toLowerCase().endsWith(".cfg")) { name = name.substring(0, name.length() - 4); } - - + String sourceModuleName = name.substring(name .lastIndexOf(FileUtil.separator) + 1); @@ -199,13 +206,13 @@ public class Translator { ToolIO.setUserDir(path); return sourceModuleName; } - - public Definitions getBDefinitions(){ + + public Definitions getBDefinitions() { return bDefinitions; } - public String getBMachineString(){ + public String getBMachineString() { return bMachineString; } - + } diff --git a/src/test/java/de/tla2b/examples/ForDistribution.java b/src/test/java/de/tla2b/examples/ForDistribution.java deleted file mode 100644 index 64e927653428edfe4c70d51462cef949b2051b28..0000000000000000000000000000000000000000 --- a/src/test/java/de/tla2b/examples/ForDistribution.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.tla2b.examples; - -import org.junit.Test; -import static de.tla2b.util.TestUtil.runModule; - - -public class ForDistribution { - - - @Test - public void testClub() throws Exception { - String file = "src/test/resources/examples/Club/Club.tla"; - runModule(file); - } - - @Test - public void testSimpleMC() throws Exception { - String file = "src/test/resources/MCTests/simple/MC.tla"; - runModule(file); - } - - @Test - public void testConstantSetupMC() throws Exception { - String file = "src/test/resources/MCTests/constantsetup/MC.tla"; - runModule(file); - } - - @Test - public void testModelValuesMC() throws Exception { - String file = "src/test/resources/MCTests/modelvalues/MC.tla"; - runModule(file); - } - - @Test - public void testDieHardMC() throws Exception { - String file = "src/test/resources/MCTests/DieHard/MC.tla"; - runModule(file); - } - - @Test - public void testSimpleAllocatorMC() throws Exception { - String file = "src/test/resources/MCTests/SimpleAllocator/MC.tla"; - runModule(file); - } - -} diff --git a/src/test/java/de/tla2b/examples/MCTest.java b/src/test/java/de/tla2b/examples/MCTest.java new file mode 100644 index 0000000000000000000000000000000000000000..19d068fdb4842ba123ed187904d6507a2b3a8d5b --- /dev/null +++ b/src/test/java/de/tla2b/examples/MCTest.java @@ -0,0 +1,96 @@ +package de.tla2b.examples; + +import org.junit.Ignore; +import org.junit.Test; + +import static de.tla2b.util.TestUtil.runModule; + +public class MCTest { + + @Test + public void testClub() throws Exception { + String file = "src/test/resources/examples/Club/Club.tla"; + runModule(file); + } + + @Test + public void testSimpleMC() throws Exception { + String file = "src/test/resources/MCTests/simple/MC.tla"; + runModule(file); + } + + @Test + public void testConstantSetupMC() throws Exception { + String file = "src/test/resources/MCTests/constantsetup/MC.tla"; + runModule(file); + } + + @Test + public void testModelValuesMC() throws Exception { + String file = "src/test/resources/MCTests/modelvalues/MC.tla"; + runModule(file); + } + + @Test + public void testDieHardMC() throws Exception { + String file = "src/test/resources/MCTests/DieHard/MC.tla"; + runModule(file); + } + + @Test + public void testSimpleAllocatorMC() throws Exception { + String file = "src/test/resources/MCTests/SimpleAllocator/MC.tla"; + runModule(file); + } + + @Test + public void testMCDieHarder() throws Exception { + String file = "src/test/resources/MCTests/MCDieHarder/MCDieHarder.tla"; + runModule(file); + } + + @Test + public void testDieHarder() throws Exception { + String file = "src/test/resources/MCTests/DieHarder/MC.tla"; + runModule(file); + } + + @Test + public void testChannel() throws Exception { + String file = "src/test/resources/examples/Channel/Channel.tla"; + runModule(file); + } + + @Ignore + @Test + public void testCarTalkPuzzle() throws Exception { + String file = "src/test/resources/MCTests/CarTalkPuzzle/MC.tla"; + runModule(file); + } + + @Ignore + @Test + public void testCarTalkPuzzleModel2() throws Exception { + String file = "src/test/resources/MCTests/CarTalkPuzzle/Model2/MC.tla"; + runModule(file); + } + + @Test + public void testSequences() throws Exception { + String file = "src/test/resources/examples/MySequence/MySequence.tla"; + runModule(file); + } + + @Ignore + @Test + public void testRecursiveFunciton() throws Exception { + String file = "src/test/resources/examples/RecursiveFunction/RecursiveFunction.tla"; + runModule(file); + } + + @Test + public void testQueens() throws Exception { + String file = "src/test/resources/MCTests/Queens/MC.tla"; + runModule(file); + } +} diff --git a/src/test/java/de/tla2b/prettyprintb/DefinitionsTest.java b/src/test/java/de/tla2b/prettyprintb/DefinitionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d120ee40d67fed3b5b8606533911699164480ca3 --- /dev/null +++ b/src/test/java/de/tla2b/prettyprintb/DefinitionsTest.java @@ -0,0 +1,36 @@ +package de.tla2b.prettyprintb; + +import static de.tla2b.util.TestUtil.compare; + +import org.junit.Test; + +public class DefinitionsTest { + + @Test + public void testMakePredicate() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "foo == TRUE \n" + + "ASSUME foo\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS foo == TRUE;" + + "PROPERTIES foo = TRUE\n" + + "END"; + compare(expected, module); + } + + @Test + public void testPredicate() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "foo == TRUE = TRUE \n" + + "ASSUME foo\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS foo == TRUE= TRUE;" + + "PROPERTIES foo\n" + + "END"; + compare(expected, module); + } +} diff --git a/src/test/java/de/tla2b/prettyprintb/ExceptTest.java b/src/test/java/de/tla2b/prettyprintb/ExceptTest.java new file mode 100644 index 0000000000000000000000000000000000000000..23813f430439f89d72df72d3d55ba996dd5ca693 --- /dev/null +++ b/src/test/java/de/tla2b/prettyprintb/ExceptTest.java @@ -0,0 +1,77 @@ +package de.tla2b.prettyprintb; + +import static de.tla2b.util.TestUtil.compare; +import static org.junit.Assert.assertEquals; + +import org.junit.Ignore; +import org.junit.Test; + +import util.ToolIO; +import de.tla2b.util.TestUtil; + +public class ExceptTest { + + @Test + public void testFunctionExcept() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "CONSTANTS k \n" + + "ASSUME k = [k EXCEPT ![TRUE] = 0, ![FALSE] = 0] \n" + + "================================="; + + final String expected = "MACHINE Testing\n" + "ABSTRACT_CONSTANTS k\n" + + "PROPERTIES " + + " k : BOOL +-> INTEGER " + + "& k = k <+ {TRUE |-> 0, FALSE |-> 0}" + "END"; + compare(expected, module); + } + + @Test + public void testFunctionExcept2() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "CONSTANTS k \n" + + "ASSUME k = [k EXCEPT ![TRUE] = 0, ![FALSE] = 0] \n" + + "================================="; + + final String expected = "MACHINE Testing\n" + "ABSTRACT_CONSTANTS k\n" + + "PROPERTIES " + + " k : BOOL +-> INTEGER " + + "& k = k <+ {TRUE |-> 0, FALSE |-> 0}" + "END"; + compare(expected, module); + + } + + @Test + public void testFunctionExceptAt() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "CONSTANTS k \n" + + "ASSUME k = [x \\in {1,2} |-> x] /\\ [k EXCEPT ![1] = @ + 1][1] = 2 \n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "ABSTRACT_CONSTANTS k \n" + + "PROPERTIES k : INTEGER +-> INTEGER & (k = %x.(x : {1, 2}| x) & (k <+ {1 |-> k(1) + 1})(1) = 2)\n" + + "END"; + compare(expected, module); + } + @Ignore + @Test + public void testFunctionExceptAt2() throws Exception { + ToolIO.reset(); + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "CONSTANTS k, k2 \n" + + "ASSUME k = [x,y \\in {1,2} |-> x+y] /\\ k2 = [k EXCEPT ![1,1] = @ + 4] \n" + + "================================="; + + StringBuilder sb = TestUtil.translateString(module); + System.out.println(sb); + final String expected = "MACHINE Testing\n" + + "ABSTRACT_CONSTANTS k, k2\n" + + "PROPERTIES k : POW(INTEGER*INTEGER*INTEGER) " + + "& k2 : POW(INTEGER*INTEGER*INTEGER) " + + "& k = %x,y.(x : {1, 2} & y : {1, 2}| x + y) " + + "& k2 = k <+ {(1, 1) |-> k(1, 1) + 4} \n" + "END"; + assertEquals(TestUtil.getAstStringofBMachineString(expected), TestUtil.getAstStringofBMachineString(sb.toString())); + } +} diff --git a/src/test/java/de/tla2b/prettyprintb/FunctionTest.java b/src/test/java/de/tla2b/prettyprintb/FunctionTest.java index c6d14fae72e540f46cdcaaafb69c5fb460369a68..093344021ca97dccb584880e1a43fade6990340c 100644 --- a/src/test/java/de/tla2b/prettyprintb/FunctionTest.java +++ b/src/test/java/de/tla2b/prettyprintb/FunctionTest.java @@ -132,55 +132,5 @@ public class FunctionTest { compare(expected, module); } - @Test - public void testFunctionExcept() throws Exception { - final String module = "-------------- MODULE Testing ----------------\n" - + "CONSTANTS k \n" - + "ASSUME k = [k EXCEPT ![TRUE] = 0, ![FALSE] = 0] \n" - + "================================="; - - final String expected = "MACHINE Testing\n" + "ABSTRACT_CONSTANTS k\n" - + "PROPERTIES " - + " k : BOOL +-> INTEGER " - + "& k = k <+ {TRUE |-> 0, FALSE |-> 0}" + "END"; - compare(expected, module); - } - - /********************************************************************** - * Record Except @ - **********************************************************************/ - @Test - public void testFunctionExceptAt() throws Exception { - final String module = "-------------- MODULE Testing ----------------\n" - + "EXTENDS Naturals \n" - + "CONSTANTS k \n" - + "ASSUME k = [x \\in {1,2} |-> x] /\\ [k EXCEPT ![1] = @ + 1][1] = 2 \n" - + "================================="; - - final String expected = "MACHINE Testing\n" - + "ABSTRACT_CONSTANTS k \n" - + "PROPERTIES k : INTEGER +-> INTEGER & (k = %x.(x : {1, 2}| x) & (k <+ {1 |-> k(1) + 1})(1) = 2)\n" - + "END"; - compare(expected, module); - } - @Ignore - @Test - public void testFunctionExceptAt2() throws Exception { - ToolIO.reset(); - final String module = "-------------- MODULE Testing ----------------\n" - + "EXTENDS Naturals \n" - + "CONSTANTS k, k2 \n" - + "ASSUME k = [x,y \\in {1,2} |-> x+y] /\\ k2 = [k EXCEPT ![1,1] = @ + 4] \n" - + "================================="; - StringBuilder sb = TestUtil.translateString(module); - System.out.println(sb); - final String expected = "MACHINE Testing\n" - + "ABSTRACT_CONSTANTS k, k2\n" - + "PROPERTIES k : POW(INTEGER*INTEGER*INTEGER) " - + "& k2 : POW(INTEGER*INTEGER*INTEGER) " - + "& k = %x,y.(x : {1, 2} & y : {1, 2}| x + y) " - + "& k2 = k <+ {(1, 1) |-> k(1, 1) + 4} \n" + "END"; - assertEquals(TestUtil.getAstStringofBMachineString(expected), TestUtil.getAstStringofBMachineString(sb.toString())); - } } diff --git a/src/test/java/de/tla2b/prettyprintb/MiscellaneousConstructsTest.java b/src/test/java/de/tla2b/prettyprintb/MiscellaneousConstructsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..366bb0a4a8b3b4a730f50dfe4c22bd4418ce0c4c --- /dev/null +++ b/src/test/java/de/tla2b/prettyprintb/MiscellaneousConstructsTest.java @@ -0,0 +1,145 @@ +package de.tla2b.prettyprintb; + +import static de.tla2b.util.TestUtil.compare; + +import org.junit.Test; + +public class MiscellaneousConstructsTest { + + @Test + public void testSimpleLet() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME LET foo(a) == a + a IN 4 = foo(2)\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "PROPERTIES 4 = 2 + 2 \n" + "END"; + compare(expected, module); + } + + @Test + public void testLet2Definitions() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME LET foo(a) == a + a bar(b) == b * b IN bar(2) = foo(2)\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "PROPERTIES 2 * 2 = 2 + 2 \n" + "END"; + compare(expected, module); + } + + @Test + public void testNestedLet() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME LET foo(a) == LET bar(b) == b * b IN bar(a+1) IN 9 = foo(2)\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "PROPERTIES 9 = (2 + 1) * (2 + 1) \n" + "END"; + compare(expected, module); + } + + @Test + public void testSimpleCase() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME 2 = CASE 1 = 1 -> 2 \n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES 2 = CHOOSE({t_ | 1=1 & t_ = 2}) \n" + "END"; + compare(expected, module); + } + + @Test + public void testCase2Conditions() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME 2 = CASE 1 = 1 -> 2 [] 1 = 2 -> 3\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES 2 = CHOOSE({t_ | (1 = 1 & t_ = 2) or (1 = 2 & t_ = 3)}) \n" + "END"; + compare(expected, module); + } + + @Test + public void testCaseOtherCondition() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME 4 = CASE 1 = 2 -> 2 [] 1 = 3 -> 3 [] OTHER -> 4\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES 4 = CHOOSE({t_ | ((1 = 2 & t_ = 2) or (1 = 3 & t_ = 3)) or (not(1 = 2 or 1 = 3) & t_ = 4)}) \n" + "END"; + compare(expected, module); + } + + @Test + public void testCasePredicate() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "EXTENDS Naturals \n" + + "ASSUME CASE 1 = 2 -> TRUE [] TRUE -> 1=1\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES CHOOSE({t_ | (1 = 2 & t_ = TRUE) or (TRUE = TRUE & t_ = bool(1 = 1))}) = TRUE \n" + "END"; + compare(expected, module); + } + + + @Test + public void testUnboundedChoose() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "ASSUME (CHOOSE x : x = 1) = 1\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES CHOOSE({x | x = 1}) = 1 \n" + "END"; + compare(expected, module); + } + + @Test + public void testUnboundedChoosePredicate() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "ASSUME (CHOOSE x : x = TRUE)\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES CHOOSE({x | x = TRUE}) = TRUE \n" + "END"; + compare(expected, module); + } + + @Test + public void testBoundedChoose() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "ASSUME (CHOOSE x \\in {1}: TRUE) = 1\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES CHOOSE({x | x : {1} & TRUE = TRUE}) = 1 \n" + "END"; + compare(expected, module); + } + + @Test + public void testBoundedChoosePredicate() throws Exception { + final String module = "-------------- MODULE Testing ----------------\n" + + "ASSUME (CHOOSE x \\in {TRUE}: TRUE) = TRUE\n" + + "================================="; + + final String expected = "MACHINE Testing\n" + + "DEFINITIONS CHOOSE(X) == \"a member of X\"; EXTERNAL_FUNCTION_CHOOSE(T) == POW(T) --> T;" + + "PROPERTIES CHOOSE({x | x : {TRUE} & TRUE = TRUE}) = TRUE \n" + "END"; + compare(expected, module); + } +} diff --git a/src/test/java/de/tla2b/prettyprintb/StructTest.java b/src/test/java/de/tla2b/prettyprintb/RecordTest.java similarity index 90% rename from src/test/java/de/tla2b/prettyprintb/StructTest.java rename to src/test/java/de/tla2b/prettyprintb/RecordTest.java index 55f852b53269e46095c55eb2fd0338abe97e9f04..92fa439b707ee0d5c9642c773bcf25fb748991d6 100644 --- a/src/test/java/de/tla2b/prettyprintb/StructTest.java +++ b/src/test/java/de/tla2b/prettyprintb/RecordTest.java @@ -11,7 +11,7 @@ import org.junit.Test; import util.ToolIO; -public class StructTest { +public class RecordTest { static { ToolIO.setMode(ToolIO.TOOL); } @@ -109,7 +109,6 @@ public class StructTest { /********************************************************************** * Record Except **********************************************************************/ - @Ignore @Test public void testRecordExcept() throws Exception { final String module = "-------------- MODULE Testing ----------------\n" @@ -118,7 +117,7 @@ public class StructTest { + "================================="; final String expected = "MACHINE Testing\n" + "ABSTRACT_CONSTANTS k, k2\n" - + "PROPERTIES k = rec(a : 1, b : TRUE) & k2 = rec(a : 2, b : k'b) \n" + + "PROPERTIES k : struct(a:INTEGER, b:BOOL) & k2 : struct(a:INTEGER, b:BOOL) & (k = rec(a : 1, b : TRUE) & k2 = rec(a : 2, b : k'b)) \n" + "END"; compare(expected, module); } @@ -126,7 +125,6 @@ public class StructTest { /********************************************************************** * Record Except @ **********************************************************************/ - @Ignore @Test public void testRecordExceptAt() throws Exception { final String module = "-------------- MODULE Testing ----------------\n" @@ -137,7 +135,7 @@ public class StructTest { final String expected = "MACHINE Testing\n" + "ABSTRACT_CONSTANTS k, k2\n" - + "PROPERTIES k : struct(a:INTEGER,b:BOOL) & k2 : struct(a:INTEGER,b:BOOL) & k = rec(a : 1, b : TRUE) & k2 = rec(a : k'a + 1, b : k'b) \n" + + "PROPERTIES k : struct(a:INTEGER, b:BOOL) & k2 : struct(a:INTEGER, b:BOOL) & (k = rec(a : 1, b : TRUE) & k2 = rec(a : k'a + 1, b : k'b)) \n" + "END"; compare(expected, module); } diff --git a/src/test/java/de/tla2b/typechecking/TupleVsSequenceTest.java b/src/test/java/de/tla2b/typechecking/TupleVsSequenceTest.java index 24cf8a104acb0a11d248f9d22b619725d70986fd..6f3699da480aa2d3e5d0f1a6b9f9ae0e404eea01 100644 --- a/src/test/java/de/tla2b/typechecking/TupleVsSequenceTest.java +++ b/src/test/java/de/tla2b/typechecking/TupleVsSequenceTest.java @@ -47,4 +47,17 @@ public class TupleVsSequenceTest { assertEquals("INTEGER", t.getConstantType("c")); } + @Test + public void testTupleVsSequence4() throws FrontEndException, TLA2BException { + final String module = "-------------- MODULE Testing ----------------\n" + + "CONSTANTS a, b, c\n" + + "ASSUME a = 1 /\\ b = TRUE /\\ c = <<a,b>>\n" + + "================================="; + TestTypeChecker t = TestUtil.typeCheckString(module); + assertEquals("INTEGER", t.getConstantType("a")); + assertEquals("BOOL", t.getConstantType("b")); + assertEquals("INTEGER*BOOL", t.getConstantType("c")); + } + + } diff --git a/src/test/resources/MCTests/DieHarder/DieHarder.tla b/src/test/resources/MCTests/DieHarder/DieHarder.tla new file mode 100644 index 0000000000000000000000000000000000000000..62b5771ea83b2baba251e2847a39be659a324a1d --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/DieHarder.tla @@ -0,0 +1,93 @@ +----------------------------- MODULE DieHarder ------------------------------ +(***************************************************************************) +(* We now generalize the problem from Die Hard into one with an arbitrary *) +(* number of jugs, each holding some specified amount of water. *) +(***************************************************************************) +EXTENDS Naturals + +(***************************************************************************) +(* We now declare two constant parameters. *) +(***************************************************************************) + +CONSTANT Jug, \* The set of all jugs. + Capacity, \* A function, where Capacity[j] is the capacity of jug j. + Goal \* The quantity of water our heros must measure. +(***************************************************************************) +(* We make an assumption about these constants--namely, that Capacity is a *) +(* function from jugs to positive integers, and Goal is a natural number. *) +(***************************************************************************) +ASSUME /\ Capacity \in [Jug -> {n \in Nat : n > 0}] + /\ Goal \in Nat +(***************************************************************************) +(* We are going to need the Min operator again, so let's define it here. *) +(* (I prefer defining constant operators like this in the part of the *) +(* spec where constants are declared. *) +(***************************************************************************) +Min(m,n) == IF m < n THEN m ELSE n +----------------------------------------------------------------------------- +(***************************************************************************) +(* We declare the specification's single variable and define its type *) +(* invariant and initial predicate. *) +(***************************************************************************) +VARIABLE contents \* contents[j] is the amount of water in jug j + +TypeOK == contents \in [Jug -> Nat] + +Init == contents = [j \in Jug |-> 0] +----------------------------------------------------------------------------- +(***************************************************************************) +(* Now we define the actions that can be performed. They are the obvious *) +(* generalizations of the ones from the simple DieHard spec. First come *) +(* the actions of filling and emptying jug j, then the action of *) +(* pouring water from jug j to jug k. *) +(* *) +(* Note: The definitions use the TLA+ notation *) +(* *) +(* [f EXCEPT ![c]=e] *) +(* *) +(* which is the function g that is the same as f except g[c]=e. In the *) +(* expression e, the symbol @ stands for f[c]. This has the more general *) +(* form *) +(* *) +(* [f EXCEPT ![c1] = e1, ... , ![ck] = ek] *) +(* *) +(* that has the expected meaning. *) +(***************************************************************************) +FillJug(j) == contents' = [contents EXCEPT ![j] = Capacity[j]] + +EmptyJug(j) == contents' = [contents EXCEPT ![j] = 0] + +JugToJug(j, k) == + LET amountPoured == Min(contents[j], Capacity[k]-contents[k]) + IN contents' = [contents EXCEPT ![j] = @ - amountPoured, + ![k] = @ + amountPoured] + +(***************************************************************************) +(* As usual, the next-state relation Next is the disjunction of all *) +(* possible actions, where existential quantification is a general form of *) +(* disjunction. *) +(***************************************************************************) +Next == \E j \in Jug : \/ FillJug(j) + \/ EmptyJug(j) + \/ \E k \in Jug \ {j} : JugToJug(j, k) + +(***************************************************************************) +(* We define the formula Spec to be the complete specification, asserting *) +(* of a behavior that it begins in a state satisfying Init, and that every *) +(* step either satisfies Next or else leaves contents unchanged. *) +(***************************************************************************) +Spec == Init /\ [][Next]_contents +----------------------------------------------------------------------------- +(***************************************************************************) +(* We define NotSolved to be true of a state iff no jug contains Goal *) +(* gallons of water. *) +(***************************************************************************) +NotSolved == \A j \in Jug : contents[j] # Goal + +(***************************************************************************) +(* We find a solution by having TLC check if NotSolved is an invariant, *) +(* which will cause it to print out an "error trace" consisting of a *) +(* behavior ending in a states where NotSolved is false. Such a *) +(* behavior is the desired solution. *) +(***************************************************************************) +============================================================================= diff --git a/src/test/resources/MCTests/DieHarder/MC.cfg b/src/test/resources/MCTests/DieHarder/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..05484f50619dc7bd57cbe1aec981bbdd1844c716 --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MC.cfg @@ -0,0 +1,13 @@ +\* CONSTANT definitions +CONSTANT +Jug <- const_13977234641526000 +\* CONSTANT definitions +CONSTANT +Goal <- const_13977234641637000 +\* CONSTANT definitions +CONSTANT +Capacity <- const_13977234641748000 +\* SPECIFICATION definition +SPECIFICATION +spec_13977234641859000 +\* Generated on Thu Apr 17 10:31:04 CEST 2014 \ No newline at end of file diff --git a/src/test/resources/MCTests/DieHarder/MC.out b/src/test/resources/MCTests/DieHarder/MC.out new file mode 100644 index 0000000000000000000000000000000000000000..46a9a05447634db941c7e9f7c559c8bcc2fdad74 --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MC.out @@ -0,0 +1,67 @@ +@!@!@STARTMSG 2262:0 @!@!@ +TLC2 Version 2.05 of 23 July 2013 +@!@!@ENDMSG 2262 @!@!@ +@!@!@STARTMSG 2187:0 @!@!@ +Running in Model-Checking mode. +@!@!@ENDMSG 2187 @!@!@ +@!@!@STARTMSG 2220:0 @!@!@ +Starting SANY... +@!@!@ENDMSG 2220 @!@!@ +Parsing file MC.tla +Parsing file MCDieHarder.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/TLC.tla +Parsing file DieHarder.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/Naturals.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/Sequences.tla +Semantic processing of module Naturals +Semantic processing of module DieHarder +Semantic processing of module MCDieHarder +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MC +@!@!@STARTMSG 2219:0 @!@!@ +SANY finished. +@!@!@ENDMSG 2219 @!@!@ +@!@!@STARTMSG 2185:0 @!@!@ +Starting... (2014-04-17 10:31:05) +@!@!@ENDMSG 2185 @!@!@ +@!@!@STARTMSG 2189:0 @!@!@ +Computing initial states... +@!@!@ENDMSG 2189 @!@!@ +@!@!@STARTMSG 2190:0 @!@!@ +Finished computing initial states: 1 distinct state generated. +@!@!@ENDMSG 2190 @!@!@ +@!@!@STARTMSG 2193:0 @!@!@ +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 7.0E-17 + based on the actual fingerprints: val = 2.7E-18 +@!@!@ENDMSG 2193 @!@!@ +@!@!@STARTMSG 2201:0 @!@!@ +The coverage statistics at 2014-04-17 10:31:05 +@!@!@ENDMSG 2201 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 56, col 16 to line 56, col 63 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 58, col 16 to line 58, col 53 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 62, col 7 to line 63, col 59 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2202:0 @!@!@ +End of statistics. +@!@!@ENDMSG 2202 @!@!@ +@!@!@STARTMSG 2200:0 @!@!@ +Progress(9) at 2014-04-17 10:31:05: 97 states generated (153.157 s/min), 16 distinct states found (25.263 ds/min), 0 states left on queue. +@!@!@ENDMSG 2200 @!@!@ +@!@!@STARTMSG 2199:0 @!@!@ +97 states generated, 16 distinct states found, 0 states left on queue. +@!@!@ENDMSG 2199 @!@!@ +@!@!@STARTMSG 2194:0 @!@!@ +The depth of the complete state graph search is 9. +@!@!@ENDMSG 2194 @!@!@ +@!@!@STARTMSG 2186:0 @!@!@ +Finished. (2014-04-17 10:31:05) +@!@!@ENDMSG 2186 @!@!@ diff --git a/src/test/resources/MCTests/DieHarder/MC.tla b/src/test/resources/MCTests/DieHarder/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..7d950ff54aea2246382c18e23878fa0e23e96838 --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MC.tla @@ -0,0 +1,25 @@ +---- MODULE MC ---- +EXTENDS MCDieHarder, TLC + +\* CONSTANT definitions @modelParameterConstants:0Jug +const_13977234641526000 == +MCJug +---- + +\* CONSTANT definitions @modelParameterConstants:1Goal +const_13977234641637000 == +4 +---- + +\* CONSTANT definitions @modelParameterConstants:2Capacity +const_13977234641748000 == +MCCapacity +---- + +\* SPECIFICATION definition @modelBehaviorSpec:0 +spec_13977234641859000 == +Spec +---- +============================================================================= +\* Modification History +\* Created Thu Apr 17 10:31:04 CEST 2014 by hansen diff --git a/src/test/resources/MCTests/DieHarder/MCDieHarder.cfg b/src/test/resources/MCTests/DieHarder/MCDieHarder.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a2b049287576d6aae25238d3e03b5aa4ae2e6371 --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MCDieHarder.cfg @@ -0,0 +1,7 @@ +CONSTANTS Goal = 4 + Jug <- MCJug + Capacity <- MCCapacity + +SPECIFICATION Spec +INVARIANTS TypeOK NotSolved + diff --git a/src/test/resources/MCTests/DieHarder/MCDieHarder.tla b/src/test/resources/MCTests/DieHarder/MCDieHarder.tla new file mode 100644 index 0000000000000000000000000000000000000000..a4b83157f22f1012b090f53ac80472286199dd3c --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MCDieHarder.tla @@ -0,0 +1,20 @@ +---------------------------- MODULE MCDieHarder ----------------------------- +EXTENDS DieHarder + +(***************************************************************************) +(* To have TLC find a solution, we must tell it what values to use for the *) +(* constant parameters Jug, Capacity, and Goal. However, TLC does not *) +(* allow one to write write function-valued expressions in a configuration *) +(* file. So, we use this module, which extends module DieHarder, to *) +(* define a function MCCapacity and have the configuration file TLC to *) +(* substitute MCCapacity for Capacity. Since we need to know the value of *) +(* Jug to define Capacity (which is a function having Jug as its domain), *) +(* we also define MCJug and tell TLC to substitute it for Jug. *) +(***************************************************************************) + +\* The following definitions duplicate the original Die Hard problem. +MCJug == {"j1", "j2"} +MCCapacity == + [j \in MCJug |-> CASE j = "j1" -> 3 + [] j = "j2" -> 5 ] +============================================================================= diff --git a/src/test/resources/MCTests/DieHarder/MC_TE.out b/src/test/resources/MCTests/DieHarder/MC_TE.out new file mode 100644 index 0000000000000000000000000000000000000000..46a9a05447634db941c7e9f7c559c8bcc2fdad74 --- /dev/null +++ b/src/test/resources/MCTests/DieHarder/MC_TE.out @@ -0,0 +1,67 @@ +@!@!@STARTMSG 2262:0 @!@!@ +TLC2 Version 2.05 of 23 July 2013 +@!@!@ENDMSG 2262 @!@!@ +@!@!@STARTMSG 2187:0 @!@!@ +Running in Model-Checking mode. +@!@!@ENDMSG 2187 @!@!@ +@!@!@STARTMSG 2220:0 @!@!@ +Starting SANY... +@!@!@ENDMSG 2220 @!@!@ +Parsing file MC.tla +Parsing file MCDieHarder.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/TLC.tla +Parsing file DieHarder.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/Naturals.tla +Parsing file /Users/hansen/git/tlaprob/tlatools/class/tla2sany/StandardModules/Sequences.tla +Semantic processing of module Naturals +Semantic processing of module DieHarder +Semantic processing of module MCDieHarder +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MC +@!@!@STARTMSG 2219:0 @!@!@ +SANY finished. +@!@!@ENDMSG 2219 @!@!@ +@!@!@STARTMSG 2185:0 @!@!@ +Starting... (2014-04-17 10:31:05) +@!@!@ENDMSG 2185 @!@!@ +@!@!@STARTMSG 2189:0 @!@!@ +Computing initial states... +@!@!@ENDMSG 2189 @!@!@ +@!@!@STARTMSG 2190:0 @!@!@ +Finished computing initial states: 1 distinct state generated. +@!@!@ENDMSG 2190 @!@!@ +@!@!@STARTMSG 2193:0 @!@!@ +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 7.0E-17 + based on the actual fingerprints: val = 2.7E-18 +@!@!@ENDMSG 2193 @!@!@ +@!@!@STARTMSG 2201:0 @!@!@ +The coverage statistics at 2014-04-17 10:31:05 +@!@!@ENDMSG 2201 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 56, col 16 to line 56, col 63 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 58, col 16 to line 58, col 53 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2221:0 @!@!@ + line 62, col 7 to line 63, col 59 of module DieHarder: 32 +@!@!@ENDMSG 2221 @!@!@ +@!@!@STARTMSG 2202:0 @!@!@ +End of statistics. +@!@!@ENDMSG 2202 @!@!@ +@!@!@STARTMSG 2200:0 @!@!@ +Progress(9) at 2014-04-17 10:31:05: 97 states generated (153.157 s/min), 16 distinct states found (25.263 ds/min), 0 states left on queue. +@!@!@ENDMSG 2200 @!@!@ +@!@!@STARTMSG 2199:0 @!@!@ +97 states generated, 16 distinct states found, 0 states left on queue. +@!@!@ENDMSG 2199 @!@!@ +@!@!@STARTMSG 2194:0 @!@!@ +The depth of the complete state graph search is 9. +@!@!@ENDMSG 2194 @!@!@ +@!@!@STARTMSG 2186:0 @!@!@ +Finished. (2014-04-17 10:31:05) +@!@!@ENDMSG 2186 @!@!@ diff --git a/src/test/resources/MCTests/MCDieHarder/DieHarder.tla b/src/test/resources/MCTests/MCDieHarder/DieHarder.tla new file mode 100644 index 0000000000000000000000000000000000000000..62b5771ea83b2baba251e2847a39be659a324a1d --- /dev/null +++ b/src/test/resources/MCTests/MCDieHarder/DieHarder.tla @@ -0,0 +1,93 @@ +----------------------------- MODULE DieHarder ------------------------------ +(***************************************************************************) +(* We now generalize the problem from Die Hard into one with an arbitrary *) +(* number of jugs, each holding some specified amount of water. *) +(***************************************************************************) +EXTENDS Naturals + +(***************************************************************************) +(* We now declare two constant parameters. *) +(***************************************************************************) + +CONSTANT Jug, \* The set of all jugs. + Capacity, \* A function, where Capacity[j] is the capacity of jug j. + Goal \* The quantity of water our heros must measure. +(***************************************************************************) +(* We make an assumption about these constants--namely, that Capacity is a *) +(* function from jugs to positive integers, and Goal is a natural number. *) +(***************************************************************************) +ASSUME /\ Capacity \in [Jug -> {n \in Nat : n > 0}] + /\ Goal \in Nat +(***************************************************************************) +(* We are going to need the Min operator again, so let's define it here. *) +(* (I prefer defining constant operators like this in the part of the *) +(* spec where constants are declared. *) +(***************************************************************************) +Min(m,n) == IF m < n THEN m ELSE n +----------------------------------------------------------------------------- +(***************************************************************************) +(* We declare the specification's single variable and define its type *) +(* invariant and initial predicate. *) +(***************************************************************************) +VARIABLE contents \* contents[j] is the amount of water in jug j + +TypeOK == contents \in [Jug -> Nat] + +Init == contents = [j \in Jug |-> 0] +----------------------------------------------------------------------------- +(***************************************************************************) +(* Now we define the actions that can be performed. They are the obvious *) +(* generalizations of the ones from the simple DieHard spec. First come *) +(* the actions of filling and emptying jug j, then the action of *) +(* pouring water from jug j to jug k. *) +(* *) +(* Note: The definitions use the TLA+ notation *) +(* *) +(* [f EXCEPT ![c]=e] *) +(* *) +(* which is the function g that is the same as f except g[c]=e. In the *) +(* expression e, the symbol @ stands for f[c]. This has the more general *) +(* form *) +(* *) +(* [f EXCEPT ![c1] = e1, ... , ![ck] = ek] *) +(* *) +(* that has the expected meaning. *) +(***************************************************************************) +FillJug(j) == contents' = [contents EXCEPT ![j] = Capacity[j]] + +EmptyJug(j) == contents' = [contents EXCEPT ![j] = 0] + +JugToJug(j, k) == + LET amountPoured == Min(contents[j], Capacity[k]-contents[k]) + IN contents' = [contents EXCEPT ![j] = @ - amountPoured, + ![k] = @ + amountPoured] + +(***************************************************************************) +(* As usual, the next-state relation Next is the disjunction of all *) +(* possible actions, where existential quantification is a general form of *) +(* disjunction. *) +(***************************************************************************) +Next == \E j \in Jug : \/ FillJug(j) + \/ EmptyJug(j) + \/ \E k \in Jug \ {j} : JugToJug(j, k) + +(***************************************************************************) +(* We define the formula Spec to be the complete specification, asserting *) +(* of a behavior that it begins in a state satisfying Init, and that every *) +(* step either satisfies Next or else leaves contents unchanged. *) +(***************************************************************************) +Spec == Init /\ [][Next]_contents +----------------------------------------------------------------------------- +(***************************************************************************) +(* We define NotSolved to be true of a state iff no jug contains Goal *) +(* gallons of water. *) +(***************************************************************************) +NotSolved == \A j \in Jug : contents[j] # Goal + +(***************************************************************************) +(* We find a solution by having TLC check if NotSolved is an invariant, *) +(* which will cause it to print out an "error trace" consisting of a *) +(* behavior ending in a states where NotSolved is false. Such a *) +(* behavior is the desired solution. *) +(***************************************************************************) +============================================================================= diff --git a/src/test/resources/MCTests/MCDieHarder/MCDieHarder.cfg b/src/test/resources/MCTests/MCDieHarder/MCDieHarder.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a2b049287576d6aae25238d3e03b5aa4ae2e6371 --- /dev/null +++ b/src/test/resources/MCTests/MCDieHarder/MCDieHarder.cfg @@ -0,0 +1,7 @@ +CONSTANTS Goal = 4 + Jug <- MCJug + Capacity <- MCCapacity + +SPECIFICATION Spec +INVARIANTS TypeOK NotSolved + diff --git a/src/test/resources/MCTests/MCDieHarder/MCDieHarder.tla b/src/test/resources/MCTests/MCDieHarder/MCDieHarder.tla new file mode 100644 index 0000000000000000000000000000000000000000..a4b83157f22f1012b090f53ac80472286199dd3c --- /dev/null +++ b/src/test/resources/MCTests/MCDieHarder/MCDieHarder.tla @@ -0,0 +1,20 @@ +---------------------------- MODULE MCDieHarder ----------------------------- +EXTENDS DieHarder + +(***************************************************************************) +(* To have TLC find a solution, we must tell it what values to use for the *) +(* constant parameters Jug, Capacity, and Goal. However, TLC does not *) +(* allow one to write write function-valued expressions in a configuration *) +(* file. So, we use this module, which extends module DieHarder, to *) +(* define a function MCCapacity and have the configuration file TLC to *) +(* substitute MCCapacity for Capacity. Since we need to know the value of *) +(* Jug to define Capacity (which is a function having Jug as its domain), *) +(* we also define MCJug and tell TLC to substitute it for Jug. *) +(***************************************************************************) + +\* The following definitions duplicate the original Die Hard problem. +MCJug == {"j1", "j2"} +MCCapacity == + [j \in MCJug |-> CASE j = "j1" -> 3 + [] j = "j2" -> 5 ] +============================================================================= diff --git a/src/test/resources/MCTests/Queens/MC.cfg b/src/test/resources/MCTests/Queens/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d8e4aeae30c5958141e8744b990a8e7b9b0a3fb0 --- /dev/null +++ b/src/test/resources/MCTests/Queens/MC.cfg @@ -0,0 +1,14 @@ +\* CONSTANT definitions +CONSTANT +N <- const_129269506133433000 +\* SPECIFICATION definition +SPECIFICATION +spec_129269506134534000 +\* INVARIANT definition +INVARIANT +inv_129269506135535000 +inv_129269506136536000 +\* PROPERTY definition +PROPERTY +prop_129269506137537000 +\* Generated at Sat Dec 18 18:57:41 CET 2010 \ No newline at end of file diff --git a/src/test/resources/MCTests/Queens/MC.tla b/src/test/resources/MCTests/Queens/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..56f27aec7477b98e396b7e954d80c43148d63795 --- /dev/null +++ b/src/test/resources/MCTests/Queens/MC.tla @@ -0,0 +1,27 @@ +---- MODULE MC ---- +EXTENDS QueensPlusCal, TLC + +\* CONSTANT definitions @modelParameterConstants:0N +const_129269506133433000 == +4 +---- + +\* SPECIFICATION definition @modelBehaviorSpec:0 +spec_129269506134534000 == +LiveSpec +---- +\* INVARIANT definition @modelCorrectnessInvariants:0 +inv_129269506135535000 == +TypeInvariant +---- +\* INVARIANT definition @modelCorrectnessInvariants:1 +inv_129269506136536000 == +Invariant +---- +\* PROPERTY definition @modelCorrectnessProperties:0 +prop_129269506137537000 == +Termination +---- +============================================================================= +\* Modification History +\* Created Sat Dec 18 18:57:41 CET 2010 by merz diff --git a/src/test/resources/MCTests/Queens/QueensPlusCal.tla b/src/test/resources/MCTests/Queens/QueensPlusCal.tla new file mode 100644 index 0000000000000000000000000000000000000000..bc1d9cc946187a01615f40d55acee0408ae0f807 --- /dev/null +++ b/src/test/resources/MCTests/Queens/QueensPlusCal.tla @@ -0,0 +1,124 @@ +-------------------------- MODULE QueensPlusCal ----------------------------- +EXTENDS Naturals, Sequences +(***************************************************************************) +(* Formulation of the N-queens problem and an iterative algorithm to solve *) +(* the problem in TLA+. Since there must be exactly one queen in every row *) +(* we represent placements of queens as functions of the form *) +(* queens \in [ 1..N -> 1..N ] *) +(* where queens[i] gives the column of the queen in row i. Note that such *) +(* a function is just a sequence of length N. *) +(* We will also consider partial solutions, also represented as sequences *) +(* of length \leq N. *) +(***************************************************************************) + +CONSTANT N \** number of queens and size of the board +ASSUME N \in Nat \ {0} + +(* The following predicate determines if queens i and j attack each other + in a placement of queens (represented by a sequence as above). *) +Attacks(queens,i,j) == + \/ queens[i] = queens[j] \** same column + \/ queens[i] - queens[j] = i - j \** first diagonal + \/ queens[j] - queens[i] = i - j \** second diagonal + +(* A placement represents a (partial) solution if no two different queens + attack each other in it. *) +IsSolution(queens) == + \A i \in 1 .. Len(queens)-1 : \A j \in i+1 .. Len(queens) : + ~ Attacks(queens,i,j) + +(* Compute the set of solutions of the N-queens problem. *) +Solutions == { queens \in [1..N -> 1..N] : IsSolution(queens) } + +(***************************************************************************) +(* We now describe an algorithm that iteratively computes the set of *) +(* solutions of the N-queens problem by successively placing queens. *) +(* The current state of the algorithm is given by two variables: *) +(* - todo contains a set of partial solutions, *) +(* - sols contains the set of full solutions found so far. *) +(* At every step, the algorithm picks some partial solution and computes *) +(* all possible extensions by the next queen. If N queens have been placed *) +(* these extensions are in fact full solutions, otherwise they are added *) +(* to the set todo. *) +(***************************************************************************) + +(* --algorithm Queens + variables + todo = { << >> }; + sols = {}; + + begin +nxtQ: while todo # {} + do + with queens \in todo, + nxtQ = Len(queens) + 1, + cols = { c \in 1..N : ~ \E i \in 1 .. Len(queens) : + Attacks( Append(queens, c), i, nxtQ ) }, + exts = { Append(queens,c) : c \in cols } + do + if (nxtQ = N) + then todo := todo \ {queens}; sols := sols \union exts; + else todo := (todo \ {queens}) \union exts; + end if; + end with; + end while; + end algorithm +*) + +\** BEGIN TRANSLATION +VARIABLES todo, sols, pc + +vars == << todo, sols, pc >> + +Init == (* Global variables *) + /\ todo = { << >> } + /\ sols = {} + /\ pc = "nxtQ" + +nxtQ == /\ pc = "nxtQ" + /\ IF todo # {} + THEN /\ \E queens \in todo: + LET nxtQ == Len(queens) + 1 IN + LET cols == { c \in 1..N : ~ \E i \in 1 .. Len(queens) : + Attacks( Append(queens, c), i, nxtQ ) } IN + LET exts == { Append(queens,c) : c \in cols } IN + IF (nxtQ = N) + THEN /\ todo' = todo \ {queens} + /\ sols' = (sols \union exts) + ELSE /\ todo' = ((todo \ {queens}) \union exts) + /\ UNCHANGED sols + /\ pc' = "nxtQ" + ELSE /\ pc' = "Done" + /\ UNCHANGED << todo, sols >> + +Next == nxtQ + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +\** END TRANSLATION + +TypeInvariant == + /\ todo \in SUBSET Seq(1 .. N) /\ \A s \in todo : Len(s) < N + /\ sols \in SUBSET Seq(1 .. N) /\ \A s \in sols : Len(s) = N + +(* The set of sols contains only solutions, and contains all solutions + when todo is empty. *) +Invariant == + /\ sols \subseteq Solutions + /\ todo = {} => Solutions \subseteq sols + +(* Assert that no solutions are ever computed so that TLC displays one *) +NoSolutions == sols = {} + +(* Add a fairness condition to ensure progress as long as todo is nonempty *) +Liveness == WF_vars(nxtQ) +LiveSpec == Spec /\ Liveness + +============================================================================= +\* Modification History +\* Last modified Sat Dec 18 18:57:03 CET 2010 by merz +\* Created Sat Dec 11 08:50:24 CET 2010 by merz