/** * Returns the <code>AutomatonStates</code> that follow this State in the ControlAutomatonCPA. If * the passed <code>AutomatonExpressionArguments</code> are not sufficient to determine the * following state this method returns a <code>AutomatonUnknownState</code> that contains this as * previous State. The strengthen method of the <code>AutomatonUnknownState</code> should be used * once enough Information is available to determine the correct following State. * * <p>If the state is a NonDet-State multiple following states may be returned. If the only * following state is BOTTOM an empty set is returned. * * @throws CPATransferException */ private Collection<AutomatonState> getFollowStates( AutomatonState state, List<AbstractState> otherElements, CFAEdge edge, boolean failOnUnknownMatch) throws CPATransferException { Preconditions.checkArgument(!(state instanceof AutomatonUnknownState)); if (state == cpa.getBottomState()) { return Collections.emptySet(); } if (collectTokenInformation) { SourceLocationMapper.getKnownToEdge(edge); } if (state.getInternalState().getTransitions().isEmpty()) { // shortcut return Collections.singleton(state); } Collection<AutomatonState> lSuccessors = Sets.newHashSetWithExpectedSize(2); AutomatonExpressionArguments exprArgs = new AutomatonExpressionArguments(state, state.getVars(), otherElements, edge, logger); boolean edgeMatched = false; int failedMatches = 0; boolean nonDetState = state.getInternalState().isNonDetState(); // these transitions cannot be evaluated until last, because they might have sideeffects on // other CPAs (dont want to execute them twice) // the transitionVariables have to be cached (produced during the match operation) // the list holds a Transition and the TransitionVariables generated during its match List<Pair<AutomatonTransition, Map<Integer, String>>> transitionsToBeTaken = new ArrayList<>(2); for (AutomatonTransition t : state.getInternalState().getTransitions()) { exprArgs.clearTransitionVariables(); matchTime.start(); ResultValue<Boolean> match = t.match(exprArgs); matchTime.stop(); // System.out.println("----------------------"); // System.out.println(t.getTrigger()); // System.out.println(t.getFollowState().getName()); // System.out.println(edge.getPredecessor().getNodeNumber()); // System.out.println(edge.getCode()); // System.out.println(match.getValue()); if (match.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition condition could not be evaluated: " + match.getFailureMessage()); } // if one transition cannot be evaluated the evaluation must be postponed until enough // information is available return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else { if (match.getValue()) { edgeMatched = true; assertionsTime.start(); ResultValue<Boolean> assertionsHold = t.assertionsHold(exprArgs); assertionsTime.stop(); if (assertionsHold.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition assertions could not be evaluated: " + assertionsHold.getFailureMessage()); } // cannot yet be evaluated return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else if (assertionsHold.getValue()) { if (!t.canExecuteActionsOn(exprArgs)) { if (failOnUnknownMatch) { throw new CPATransferException("Automaton transition action could not be executed"); } // cannot yet execute, goto UnknownState return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } // delay execution as described above Map<Integer, String> transitionVariables = ImmutableMap.copyOf(exprArgs.getTransitionVariables()); transitionsToBeTaken.add(Pair.of(t, transitionVariables)); } else { // matching transitions, but unfulfilled assertions: goto error state AutomatonState errorState = AutomatonState.automatonStateFactory( Collections.<String, AutomatonVariable>emptyMap(), AutomatonInternalState.ERROR, cpa, 0, 0, ""); logger.log( Level.INFO, "Automaton going to ErrorState on edge \"" + edge.getDescription() + "\""); lSuccessors.add(errorState); } if (!nonDetState) { // not a nondet State, break on the first matching edge break; } } else { // do nothing if the edge did not match failedMatches++; } } } if (edgeMatched) { // execute Transitions for (Pair<AutomatonTransition, Map<Integer, String>> pair : transitionsToBeTaken) { // this transition will be taken. copy the variables AutomatonTransition t = pair.getFirst(); Map<Integer, String> transitionVariables = pair.getSecond(); actionTime.start(); Map<String, AutomatonVariable> newVars = deepCloneVars(state.getVars()); exprArgs.setAutomatonVariables(newVars); exprArgs.putTransitionVariables(transitionVariables); t.executeActions(exprArgs); actionTime.stop(); String violatedPropertyDescription = null; if (t.getFollowState().isTarget()) { violatedPropertyDescription = t.getViolatedPropertyDescription(exprArgs); } AutomatonState lSuccessor = AutomatonState.automatonStateFactory( newVars, t.getFollowState(), cpa, t.getAssumptions(), state.getMatches() + 1, state.getFailedMatches(), violatedPropertyDescription); if (!(lSuccessor instanceof AutomatonState.BOTTOM)) { lSuccessors.add(lSuccessor); } else { // add nothing } } return lSuccessors; } else { // stay in same state, no transitions to be executed here (no transition matched) AutomatonState stateNewCounters = AutomatonState.automatonStateFactory( state.getVars(), state.getInternalState(), cpa, state.getMatches(), state.getFailedMatches() + failedMatches, null); if (collectTokenInformation) { stateNewCounters.addNoMatchTokens(state.getTokensSinceLastMatch()); if (edge.getEdgeType() != CFAEdgeType.DeclarationEdge) { stateNewCounters.addNoMatchTokens( SourceLocationMapper.getAbsoluteTokensFromCFAEdge(edge, true)); } } return Collections.singleton(stateNewCounters); } }