Skip to content
Snippets Groups Projects
Select Git revision
  • 595288671a9bc0c6af4200ca1d7cccb043549472
  • master default protected
  • dev
  • sybilNLO
  • gprBug
  • maximumtotalflux
  • easyConstraint
  • switchbug
  • thuong
  • momafix
  • rmReactBug
11 results

changeColsBndsObjCoefs-methods.Rd

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    SpecAnalyser.java 9.75 KiB
    package de.tla2b.analysis;
    
    import de.tla2b.config.ConfigfileEvaluator;
    import de.tla2b.exceptions.ConfigFileErrorException;
    import de.tla2b.exceptions.NotImplementedException;
    import de.tla2b.exceptions.SemanticErrorException;
    import de.tla2b.global.BBuiltInOPs;
    import de.tla2b.translation.BDefinitionsFinder;
    import de.tla2b.translation.OperationsFinder;
    import de.tla2b.translation.UsedDefinitionsFinder;
    import de.tla2b.util.DebugUtils;
    import de.tla2b.util.TlaUtils;
    import tla2sany.semantic.*;
    import tlc2.tool.BuiltInOPs;
    
    import java.util.*;
    import java.util.stream.Stream;
    
    public class SpecAnalyser extends BuiltInOPs {
    	private OpDefNode spec;
    	private OpDefNode init;
    	private OpDefNode next;
    	private List<OpDefNode> invariants = new ArrayList<>();
    	private List<OpDeclNode> bConstants = new ArrayList<>();
    	// used to check if a b constant has arguments and is not overridden in the configfile
    
    	private OpDefNode expressionOpdefNode;
    	private final Map<String, SymbolNode> namingMap = new HashMap<>();
    
    	private final ModuleNode moduleNode;
    	private ExprNode nextExpr;
    
    	private List<BOperation> bOperations = new ArrayList<>();
    	private final List<ExprNode> inits = new ArrayList<>();
    
    	private Set<OpDefNode> bDefinitionsSet = new HashSet<>();
    	// set of OpDefNodes which will appear in the resulting B Machine
    	private Set<OpDefNode> usedDefinitions = new HashSet<>();
    	// definitions which are used for the type inference algorithm
    	private final Map<OpDefNode, FormalParamNode[]> letParams = new HashMap<>();
    	// additional parameters of a let Operator, these parameters are from the surrounding operator
    	private final List<String> definitionMacros = new ArrayList<>();
    
    	private final List<OpDefNode> recursiveFunctions = new ArrayList<>();
    	private final List<RecursiveDefinition> recursiveDefinitions = new ArrayList<>();
    
    	private ConfigfileEvaluator configFileEvaluator;
    
    	private SpecAnalyser(ModuleNode m) {
    		this.moduleNode = m;
    	}
    
    	public static SpecAnalyser createSpecAnalyser(ModuleNode m, ConfigfileEvaluator conEval) {
    		SpecAnalyser specAnalyser = new SpecAnalyser(m);
    		specAnalyser.spec = conEval.getSpecNode();
    		specAnalyser.init = conEval.getInitNode();
    		specAnalyser.next = conEval.getNextNode();
    		specAnalyser.invariants = conEval.getInvariants();
    		specAnalyser.bConstants = conEval.getbConstantList();
    		specAnalyser.configFileEvaluator = conEval;
    		return specAnalyser;
    	}
    
    	public static SpecAnalyser createSpecAnalyserForTlaExpression(ModuleNode m) {
    		SpecAnalyser specAnalyser = new SpecAnalyser(m);
    		specAnalyser.expressionOpdefNode = m.getOpDefs()[m.getOpDefs().length - 1];
    		specAnalyser.usedDefinitions.add(specAnalyser.expressionOpdefNode);
    		specAnalyser.bDefinitionsSet.add(specAnalyser.expressionOpdefNode);
    		return specAnalyser;
    	}
    
    	public static SpecAnalyser createSpecAnalyser(ModuleNode m) {
    		Map<String, OpDefNode> definitions = TlaUtils.getOpDefsMap(m.getOpDefs());
    		SpecAnalyser specAnalyser = new SpecAnalyser(m);
    
    		specAnalyser.spec = detectClause(Stream.of("Spec", "SPECIFICATION", "SPEC"),
    				definitions, "INITIALISATION+OPERATIONS");
    		specAnalyser.init = detectClause(Stream.of("Init", "INIT", "Initialisation", "INITIALISATION"),
    				definitions, "INITIALISATION");
    		specAnalyser.next = detectClause(Stream.of("Next", "NEXT"), definitions, "OPERATIONS");
    		OpDefNode invariant = detectClause(Stream.of("Inv", "INVARIANTS", "INVARIANT", "INV", "Invariant",
    						"Invariants", "TypeInv", "TypeOK", "IndInv"),
    				definitions, "INVARIANTS");
    
    		if (invariant != null) {
    			specAnalyser.invariants.add(invariant);
    		} else {
    			DebugUtils.printMsg("No default Invariant detected");
    		}
    
    		// TODO are constant in the right order
    		specAnalyser.bConstants.addAll(Arrays.asList(m.getConstantDecls()));
    		return specAnalyser;
    	}
    
    	private static OpDefNode detectClause(Stream<String> keywords, Map<String, OpDefNode> definitions, String bClause) {
    		return keywords.filter(definitions::containsKey)
    				.findFirst()
    				.map(keyword -> {
    					DebugUtils.printMsg("Detected TLA+ Default Definition " + keyword + " for Clause: " + bClause);
    					return definitions.get(keyword);
    				})
    				.orElse(null);
    	}
    
    	public void start() throws SemanticErrorException, ConfigFileErrorException, NotImplementedException {
    		evalSpec();
    
    		for (OpDefNode inv : new ArrayList<>(invariants)) {
    			try {
    				OpApplNode opApplNode = (OpApplNode) inv.getBody();
    				OpDefNode opDefNode = (OpDefNode) opApplNode.getOperator();
    
    				if (opDefNode.getKind() == UserDefinedOpKind && !BBuiltInOPs.contains(opDefNode.getName())) {
    					int i = invariants.indexOf(inv);
    					invariants.set(i, opDefNode);
    					DebugUtils.printDebugMsg("Adding invariant " + i);
    				}
    			} catch (ClassCastException e) {
    			}
    		}
    
    		DebugUtils.printDebugMsg("Detecting OPERATIONS from disjunctions");
    		bOperations = new OperationsFinder(this).getBOperations();
    
    		DebugUtils.printDebugMsg("Finding used definitions");
    		this.usedDefinitions = new UsedDefinitionsFinder(this).getUsedDefinitions();
    		this.bDefinitionsSet = new BDefinitionsFinder(this).getBDefinitionsSet();
    		// usedDefinitions.addAll(bDefinitionsSet);
    
    		DebugUtils.printDebugMsg("Computing variable declarations");
    		// test whether there is an init predicate if there is a variable
    		if (moduleNode.getVariableDecls().length > 0 && inits == null) {
    			throw new SemanticErrorException("No initial predicate is defined.");
    		}
    
    		// check if there is B constant with arguments.
    		for (OpDeclNode con : bConstants) {
    			if (con.getArity() > 0) {
    				throw new ConfigFileErrorException(
    					String.format("Constant '%s' must be overridden in the configuration file.", con.getName()));
    			}
    		}
    		findRecursiveConstructs();
    
    		for (OpDeclNode var : moduleNode.getVariableDecls()) {
    			namingMap.put(var.getName().toString(), var);
    		}
    		DebugUtils.printMsg("Number of variables detected: " + moduleNode.getVariableDecls().length);
    
    		namingMap.putAll(TlaUtils.getConstantsMap(moduleNode.getConstantDecls()));
    		DebugUtils.printMsg("Number of constants detected: " + moduleNode.getConstantDecls().length);
    
    		namingMap.putAll(TlaUtils.getOpDefsMap(usedDefinitions.toArray(new OpDefNode[0])));
    	}
    
    	private void evalSpec() throws SemanticErrorException {
    		if (spec != null) {
    			DebugUtils.printMsg("Using TLA+ Spec to determine B INITIALISATION and OPERATIONS");
    			processConfigSpec(spec.getBody());
    		} else {
    			if (init != null) {
    				DebugUtils.printMsg("Using TLA+ Init definition to determine B INITIALISATION");
    				inits.add(init.getBody());
    			}
    			if (next != null) {
    				DebugUtils.printMsg("Using TLA+ Next definition to determine B OPERATIONS");
    				nextExpr = next.getBody();
    			}
    		}
    	}
    
    	private void processConfigSpec(ExprNode exprNode) throws SemanticErrorException {
    		if (exprNode instanceof OpApplNode) {
    			OpApplNode opApp = (OpApplNode) exprNode;
    			ExprOrOpArgNode[] args = opApp.getArgs();
    			if (args.length == 0) {
    				SymbolNode opNode = opApp.getOperator();
    				if (opNode instanceof OpDefNode) {
    					OpDefNode def = (OpDefNode) opNode;
    					ExprNode body = def.getBody();
    					body.levelCheck(1);
    					if (body.getLevel() == 1) {
    						inits.add(exprNode);
    					} else {
    						processConfigSpec(body);
    					}
    					return;
    				}
    				throw new SemanticErrorException("Can not handle specification conjunction.");
    			}
    
    			int opcode = BuiltInOPs.getOpCode(opApp.getOperator().getName());
    			if (opcode == OPCODE_cl || opcode == OPCODE_land) {
    				for (ExprOrOpArgNode arg : args) {
    					this.processConfigSpec((ExprNode) arg);
    				}
    				return;
    			}
    
    			if (opcode == OPCODE_box) {
    				SemanticNode boxArg = args[0];
    				if ((boxArg instanceof OpApplNode)
    					&& BuiltInOPs.getOpCode(((OpApplNode) boxArg).getOperator().getName()) == OPCODE_sa) {
    					this.nextExpr = (ExprNode) ((OpApplNode) boxArg).getArgs()[0];
    					return;
    				}
    			}
    		}
    		if (exprNode.getLevel() <= 1) {
    			// init
    			inits.add(exprNode);
    		} else if (exprNode.getLevel() == 3) {
    			// temporal
    
    		} else {
    			throw new SemanticErrorException("Can not handle specification conjunction.");
    		}
    	}
    
    	private void findRecursiveConstructs() throws NotImplementedException {
    		Set<OpDefNode> set = new HashSet<>(usedDefinitions);
    		for (OpDefNode def : set) {
    			if (def.getInRecursive()) {
    				throw new NotImplementedException("Recursive definitions are currently not supported: " + def.getName()
    					+ "\n" + def.getLocation());
    				// bDefinitionsSet.remove(def);
    				// RecursiveDefinition rd = new RecursiveDefinition(def);
    				// recursiveDefinitions.add(rd);
    			} else if (def.getBody() instanceof OpApplNode) {
    				OpApplNode o = (OpApplNode) def.getBody();
    				if (getOpCode(o.getOperator().getName()) == OPCODE_rfs) {// recursive Function
    					bDefinitionsSet.remove(def);
    					recursiveFunctions.add(def);
    				}
    			}
    		}
    	}
    
    	public List<BOperation> getBOperations() {
    		return this.bOperations;
    	}
    
    	public List<ExprNode> getInits() {
    		return this.inits;
    	}
    
    	public ExprNode getNext() {
    		return this.nextExpr;
    	}
    
    	public Set<OpDefNode> getBDefinitions() {
    		return bDefinitionsSet;
    	}
    
    	public Map<OpDefNode, FormalParamNode[]> getLetParams() {
    		return new HashMap<>(letParams);
    	}
    
    	public List<String> getDefinitionMacros() {
    		return definitionMacros;
    	}
    
    	public Set<OpDefNode> getUsedDefinitions() {
    		return usedDefinitions;
    	}
    
    	public List<OpDefNode> getRecursiveFunctions() {
    		return recursiveFunctions;
    	}
    
    	public List<RecursiveDefinition> getRecursiveDefinitions() {
    		return recursiveDefinitions;
    	}
    
    	public ModuleNode getModuleNode() {
    		return this.moduleNode;
    	}
    
    	public ConfigfileEvaluator getConfigFileEvaluator() {
    		return configFileEvaluator;
    	}
    
    	public List<OpDefNode> getInvariants() {
    		return invariants;
    	}
    
    	public OpDefNode getInitDef() {
    		return init;
    	}
    
    	public OpDefNode getExpressionOpdefNode() {
    		return expressionOpdefNode;
    	}
    
    	public SymbolNode getSymbolNodeByName(String name) {
    		return namingMap.get(name);
    	}
    
    }