de.tla2b.analysis.BOperation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tla2bAST Show documentation
Show all versions of tla2bAST Show documentation
Translator from TLA+ to ProB's AST representation.
The newest version!
package de.tla2b.analysis;
import de.be4.classicalb.core.parser.node.*;
import de.tla2b.global.BBuiltInOPs;
import de.tla2b.global.TranslationGlobals;
import de.tla2b.types.TLAType;
import de.tla2bAst.BAstCreator;
import tla2sany.semantic.*;
import tlc2.tool.BuiltInOPs;
import tlc2.tool.ToolGlobals;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public class BOperation extends BuiltInOPs implements ASTConstants, ToolGlobals, TranslationGlobals {
private final String name;
private final OpApplNode node;
private final List existQuans;
private List opParams;
private List formalParams;
private List unchangedVariables;
private final List unchangedVariablesList;
private final List guards;
private final List beforeAfterPredicates;
private final Map assignments = new LinkedHashMap<>();
private List anyVariables;
private final SpecAnalyser specAnalyser;
public BOperation(String name, OpApplNode n, List existQuans, SpecAnalyser specAnalyser) {
this.name = name;
this.node = n;
this.existQuans = existQuans;
this.specAnalyser = specAnalyser;
this.unchangedVariablesList = new ArrayList<>();
this.guards = new ArrayList<>();
this.beforeAfterPredicates = new ArrayList<>();
anyVariables = new ArrayList<>(Arrays.asList(specAnalyser.getModuleNode().getVariableDecls()));
evalParams();
// System.out.println("Construction B Operation for TLA+ action: " + name);
findUnchangedVariables();
// System.out.println(" UNCHANGED = " + unchangedVariables.toString());
separateGuardsAndBeforeAfterPredicates(node);
findAssignments();
}
public AOperation getBOperation(BAstCreator bASTCreator) {
bASTCreator.setUnchangedVariablesNames(unchangedVariables);
List whereList = new ArrayList<>();
for (OpApplNode o : this.getExistQuans()) {
whereList.add(bASTCreator.visitBoundsOfLocalVariables(o));
}
for (ExprOrOpArgNode g : guards) {
whereList.add(bASTCreator.visitExprOrOpArgNodePredicate(g));
}
List leftSideOfAssigment = new ArrayList<>();
List rightSideOfAssigment = new ArrayList<>();
for (Entry entry : assignments.entrySet()) {
leftSideOfAssigment.add(bASTCreator.createIdentifierNode(entry.getKey()));
rightSideOfAssigment.add(bASTCreator.visitExprOrOpArgNodeExpression(entry.getValue()));
}
PSubstitution operationBody;
AAssignSubstitution assign = new AAssignSubstitution();
if (!anyVariables.isEmpty()) { // ANY x_n WHERE P THEN A END
List anyParams = new ArrayList<>();
for (OpDeclNode var : anyVariables) {
String nextName = var.getName().toString() + "_n";
anyParams.add(BAstCreator.createIdentifierNode(nextName));
whereList.add(new AMemberPredicate(
BAstCreator.createIdentifierNode(nextName),
((TLAType) var.getToolObject(TYPE_ID)).getBNode()
));
leftSideOfAssigment.add(bASTCreator.createIdentifierNode(var));
rightSideOfAssigment.add(BAstCreator.createIdentifierNode(nextName));
}
whereList.addAll(createBeforeAfterPredicates(bASTCreator));
operationBody = new AAnySubstitution(anyParams, bASTCreator.createConjunction(whereList), assign);
} else if (!whereList.isEmpty()) { // SELECT P THEN A END
whereList.addAll(createBeforeAfterPredicates(bASTCreator));
for (ExprOrOpArgNode e : beforeAfterPredicates) {
whereList.add(bASTCreator.visitExprOrOpArgNodePredicate(e));
}
operationBody = new ASelectSubstitution(bASTCreator.createConjunction(whereList), assign, new ArrayList<>(), null);
} else { // BEGIN A END
operationBody = new ABlockSubstitution(assign);
}
if (!leftSideOfAssigment.isEmpty()) {
assign.setLhsExpression(leftSideOfAssigment);
assign.setRhsExpressions(rightSideOfAssigment);
} else { // skip
assign.replaceBy(new ASkipSubstitution());
}
return new AOperation(
new ArrayList<>(),
bASTCreator.createPositionedTIdentifierLiteral(name, getNode()),
this.getFormalParams().stream().map(bASTCreator::createIdentifierNode).collect(Collectors.toList()),
operationBody
);
}
private ArrayList createBeforeAfterPredicates(BAstCreator bAstCreator) {
ArrayList predicates = new ArrayList<>();
for (ExprOrOpArgNode e : beforeAfterPredicates) {
PPredicate body = null;
if (e instanceof OpApplNode) {
OpApplNode opApplNode = (OpApplNode) e;
if (opApplNode.getOperator().getKind() == UserDefinedOpKind
&& !BBuiltInOPs.contains(opApplNode.getOperator().getName())) {
OpDefNode def = (OpDefNode) opApplNode.getOperator();
FormalParamNode[] params = def.getParams();
for (int j = 0; j < params.length; j++) {
FormalParamNode param = params[j];
param.setToolObject(SUBSTITUTE_PARAM, opApplNode.getArgs()[j]);
}
body = bAstCreator.visitExprNodePredicate(def.getBody());
}
}
if (body == null) {
body = bAstCreator.visitExprOrOpArgNodePredicate(e);
}
predicates.add(body);
}
return predicates;
}
private void findAssignments() {
PrimedVariablesFinder primedVariablesFinder = new PrimedVariablesFinder(beforeAfterPredicates);
for (ExprOrOpArgNode node : new ArrayList<>(beforeAfterPredicates)) {
if (node instanceof OpApplNode) {
OpApplNode opApplNode = (OpApplNode) node;
if (opApplNode.getOperator().getKind() == BuiltInKind) {
if (OPCODE_eq == getOpCode(opApplNode.getOperator().getName())) {
ExprOrOpArgNode arg1 = opApplNode.getArgs()[0]; // we have equality arg1 = RHS
try {
OpApplNode arg11 = (OpApplNode) arg1;
if (getOpCode(arg11.getOperator().getName()) == OPCODE_prime) {
OpApplNode v = (OpApplNode) arg11.getArgs()[0];
SymbolNode var = v.getOperator();
// we have equality var' = RHS
if (!primedVariablesFinder.getTwiceUsedVariables().contains(var)) {
// var' is only used once in all before after predicates
// meaning we do not need it as parameter of the ANY
// and can add an assignment var := RHS
assignments.put(v.getOperator(), opApplNode.getArgs()[1]); // RHS of assignment
beforeAfterPredicates.remove(node);
// System.out.println("Detected assignment " + var.getName().toString() + "' = ");
}
}
} catch (ClassCastException e) {
}
}
}
}
}
anyVariables = new ArrayList<>();
Collections.addAll(anyVariables, specAnalyser.getModuleNode().getVariableDecls());
// for (SymbolNode symbol : primedVariablesFinder.getAllVariables()) {
// anyVariables.add((OpDeclNode) symbol);
// }
anyVariables.removeAll(assignments.keySet());
anyVariables.removeAll(unchangedVariablesList);
}
private void separateGuardsAndBeforeAfterPredicates(ExprOrOpArgNode node) {
if (node instanceof OpApplNode) {
OpApplNode opApplNode = (OpApplNode) node;
if (opApplNode.getOperator().getKind() == BuiltInKind) {
switch (getOpCode(opApplNode.getOperator().getName())) {
case OPCODE_land: // \land
{
separateGuardsAndBeforeAfterPredicates(opApplNode.getArgs()[0]);
separateGuardsAndBeforeAfterPredicates(opApplNode.getArgs()[1]);
return;
}
case OPCODE_cl: // $ConjList
{
for (int i = 0; i < opApplNode.getArgs().length; i++) {
separateGuardsAndBeforeAfterPredicates(opApplNode
.getArgs()[i]);
}
return;
}
default: {
if (opApplNode.level < 2) {
guards.add(node); // should we be checking nonLeibnizParams is empty ?
} else {
beforeAfterPredicates.add(node);
}
return;
}
}
}
}
if (node.level < 2) {
guards.add(node);
} else {
beforeAfterPredicates.add(node);
}
// beforeAfterPredicates.add(node);
}
private void evalParams() {
opParams = new ArrayList<>();
formalParams = new ArrayList<>();
for (OpApplNode n : existQuans) {
FormalParamNode[][] params = n.getBdedQuantSymbolLists();
for (FormalParamNode[] param : params) {
for (FormalParamNode formalParamNode : param) {
formalParams.add(formalParamNode);
opParams.add(formalParamNode.getName().toString());
}
}
}
}
public SymbolNode getSymbolNode() {
if (node != null && node.getOperator().getKind() == UserDefinedOpKind) {
return node.getOperator();
}
return null;
}
public String getName() {
return name;
}
public ExprNode getNode() {
return node;
}
public List getExistQuans() {
return new ArrayList<>(existQuans);
}
public List getOpParams() {
return opParams;
}
public List getFormalParams() {
return formalParams;
}
public List getUnchangedVariables() {
return unchangedVariables;
}
private void findUnchangedVariables() {
unchangedVariables = new ArrayList<>();
findUnchangedVariablesInSemanticNode(node);
}
private void findUnchangedVariablesInSemanticNode(SemanticNode node) {
switch (node.getKind()) {
case OpApplKind: {
findUnchangedVariablesInOpApplNode((OpApplNode) node);
return;
}
case LetInKind: {
LetInNode letNode = (LetInNode) node;
findUnchangedVariablesInSemanticNode(letNode.getBody());
return;
}
case SubstInKind: {
SubstInNode substInNode = (SubstInNode) node;
findUnchangedVariablesInSemanticNode(substInNode.getBody());
}
}
}
private void findUnchangedVariablesInOpApplNode(OpApplNode n) {
int kind = n.getOperator().getKind();
if (kind == UserDefinedOpKind && !BBuiltInOPs.contains(n.getOperator().getName())) {
OpDefNode def = (OpDefNode) n.getOperator();
findUnchangedVariablesInSemanticNode(def.getBody());
} else if (kind == BuiltInKind) {
int opcode = BuiltInOPs.getOpCode(n.getOperator().getName());
switch (opcode) {
case OPCODE_land: // \land
case OPCODE_cl: { // $ConjList
for (int i = 0; i < n.getArgs().length; i++) {
findUnchangedVariablesInSemanticNode(n.getArgs()[i]);
}
return;
}
case OPCODE_unchanged: {
n.setToolObject(USED, false);
OpApplNode k = (OpApplNode) n.getArgs()[0];
if (k.getOperator().getKind() == VariableDeclKind) {
unchangedVariablesList.add((OpDeclNode) k.getOperator());
String name = k.getOperator().getName().toString();
unchangedVariables.add(name);
} else {
// Tuple
for (int i = 0; i < k.getArgs().length; i++) {
OpApplNode var = (OpApplNode) k.getArgs()[i];
//findUnchangedVariablesInOpApplNode(var);
// System.out.println("var.getOperator() = " + var.getOperator().getName() + " at " + var.getOperator() + " of class " + var.getOperator().getClass().getSimpleName());
if (var.getOperator() instanceof OpDefNode) {
// we have a definition
OpDefNode def = (OpDefNode) var.getOperator();
if (def.getParams().length > 0) {
// we do not support definitions with arguments yet
throw new RuntimeException("Declaration with parameters not supported for UNCHANGED: " + var.getOperator().getName() + " " + var.getLocation());
}
ExprNode body = def.getBody();
// System.out.println("Body = " + body + " of class " + body.getClass().getSimpleName());
if (body instanceof OpApplNode) {
OpApplNode obody = (OpApplNode) body;
// System.out.println("Operator = " + obody.getOperator()); // In module --TLA+ BUILTINS--
findUnchangedVariablesInOpApplNode(obody);
}
} else if (!(var.getOperator() instanceof OpDeclNode)) {
throw new RuntimeException("Cannot convert to list of UNCHANGED variables: " + var.getOperator().getName() + " " + var.getLocation());
} else {
unchangedVariablesList.add((OpDeclNode) var.getOperator());
String name = var.getOperator().getName().toString();
unchangedVariables.add(name);
}
}
}
}
}
}
}
}
class PrimedVariablesFinder extends AbstractASTVisitor {
private final Set all;
private final Set twiceUsedVariables;
public PrimedVariablesFinder(List list) {
this.all = new HashSet<>();
this.twiceUsedVariables = new HashSet<>();
for (ExprOrOpArgNode exprOrOpArgNode : list) {
findPrimedVariables(exprOrOpArgNode);
}
}
public void findPrimedVariables(ExprOrOpArgNode n) {
this.visitExprOrOpArgNode(n);
}
public void visitBuiltInNode(OpApplNode n) {
if (getOpCode(n.getOperator().getName()) == OPCODE_prime) { // prime
if (n.getArgs()[0] instanceof OpApplNode) {
OpApplNode varNode = (OpApplNode) n.getArgs()[0];
SymbolNode var = varNode.getOperator();
if (all.contains(var)) {
twiceUsedVariables.add(var);
} else {
all.add(var);
}
}
}
super.visitBuiltInNode(n);
}
public Set getTwiceUsedVariables() {
return this.twiceUsedVariables;
}
public Set getAllVariables() {
return this.all;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy