@Override public ResultValue<Integer> eval(AutomatonExpressionArguments pArgs) { if (TRANSITION_VARS_PATTERN.matcher(varId).matches()) { // $1 AutomatonTransitionVariables // no exception here (would have come in the constructor) int key = Integer.parseInt(varId.substring(1)); String val = pArgs.getTransitionVariable(key); if (val == null) { pArgs .getLogger() .log(Level.WARNING, "could not find the transition variable $" + key + "."); return new ResultValue<>( "could not find the transition variable $" + key + ".", "AutomatonIntExpr.VarAccess"); } try { int value = Integer.parseInt(val); return new ResultValue<>(Integer.valueOf(value)); } catch (NumberFormatException e) { pArgs .getLogger() .log( Level.WARNING, "could not parse the contents of transition variable $" + key + "=\"" + val + "\"."); return new ResultValue<>( "could not parse the contents of transition variable $" + key + "=\"" + val + "\".", "AutomatonIntExpr.VarAccess"); } } else if (varId.equals("$line")) { // $line line number in sourcecode return new ResultValue<>(Integer.valueOf(pArgs.getCfaEdge().getLineNumber())); } else { AutomatonVariable variable = pArgs.getAutomatonVariables().get(varId); if (variable != null) { return new ResultValue<>(Integer.valueOf(variable.getValue())); } else { pArgs .getLogger() .log(Level.WARNING, "could not find the automaton variable " + varId + "."); return new ResultValue<>( "could not find the automaton variable " + varId + ".", "AutomatonIntExpr.VarAccess"); } } }
@Override public ResultValue<Integer> eval(AutomatonExpressionArguments pArgs) { // replace transition variables String modifiedQueryString = pArgs.replaceVariables(queryString); if (modifiedQueryString == null) { return new ResultValue<>( "Failed to modify queryString \"" + queryString + "\"", "AutomatonIntExpr.CPAQuery"); } for (AbstractState ae : pArgs.getAbstractStates()) { if (ae instanceof AbstractQueryableState) { AbstractQueryableState aqe = (AbstractQueryableState) ae; if (aqe.getCPAName().equals(cpaName)) { try { Object result = aqe.evaluateProperty(modifiedQueryString); if (result instanceof NumericValue) { result = ((NumericValue) result).getNumber(); } if (result instanceof Integer) { String message = "CPA-Check succeeded: ModifiedCheckString: \"" + modifiedQueryString + "\" CPAElement: (" + aqe.getCPAName() + ") \"" + aqe.toString() + "\""; pArgs.getLogger().log(Level.FINER, message); return new ResultValue<>((Integer) result); } else if (result instanceof Long) { String message = "CPA-Check succeeded: ModifiedCheckString: \"" + modifiedQueryString + "\" CPAElement: (" + aqe.getCPAName() + ") \"" + aqe.toString() + "\""; pArgs.getLogger().log(Level.FINER, message); return new ResultValue<>(((Long) result).intValue()); } else { pArgs .getLogger() .log( Level.WARNING, "Automaton got a non-Numeric value during Query of the " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + "."); return new ResultValue<>( "Automaton got a non-Numeric value during Query of the " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + ".", "AutomatonIntExpr.CPAQuery"); } } catch (InvalidQueryException e) { pArgs .getLogger() .logException( Level.WARNING, e, "Automaton encountered an Exception during Query of the " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + "."); return new ResultValue<>( "Automaton encountered an Exception during Query of the " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + ".", "AutomatonIntExpr.CPAQuery"); } } } } pArgs .getLogger() .log( Level.WARNING, "Did not find the CPA to be queried " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + "."); return new ResultValue<>( "Did not find the CPA to be queried " + cpaName + " CPA on Edge " + pArgs.getCfaEdge().getDescription() + ".", "AutomatonIntExpr.CPAQuery"); }
/** * 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); } }