public override bool Apply(SequenceInvocationParameterBindings sequenceInvocation, IGraphProcessingEnvironment procEnv) { // If this sequence definition is currently executed // we must copy it and use the copy in its place // to prevent state corruption. if(executionState == SequenceExecutionState.Underway) { return ApplyCopy(sequenceInvocation, procEnv); } procEnv.EnteringSequence(this); executionState = SequenceExecutionState.Underway; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Before executing sequence definition " + Id + ": " + Symbol); #endif bool res = ApplyImpl(sequenceInvocation, procEnv); #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("After executing sequence definition " + Id + ": " + Symbol + " result " + res); #endif executionState = res ? SequenceExecutionState.Success : SequenceExecutionState.Fail; procEnv.EndOfIteration(false, this); procEnv.ExitingSequence(this); ResetExecutionState(); // state is shown by call, we don't exist any more for the debugger return res; }
protected override bool ApplyImpl(IGraphProcessingEnvironment procEnv) { bool res = true; // first get all matches of the rule object[] parameters; if(Rule.ParamBindings.ArgumentExpressions.Length > 0) { parameters = Rule.ParamBindings.Arguments; for(int j = 0; j < Rule.ParamBindings.ArgumentExpressions.Length; j++) { if(Rule.ParamBindings.ArgumentExpressions[j] != null) parameters[j] = Rule.ParamBindings.ArgumentExpressions[j].Evaluate(procEnv); } } else parameters = null; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Matching for rule " + Rule.GetRuleCallString(procEnv)); #endif #if DEBUGACTIONS || MATCHREWRITEDETAIL procEnv.PerformanceInfo.StartLocal(); #endif IMatches matches = Rule.ParamBindings.Action.Match(procEnv, procEnv.MaxMatches, parameters); for(int i=0; i<Rule.Filters.Count; ++i) Rule.ParamBindings.Action.Filter(procEnv, matches, Rule.Filters[i]); #if DEBUGACTIONS || MATCHREWRITEDETAIL procEnv.PerformanceInfo.StopMatch(); // total match time does NOT include listeners anymore #endif procEnv.PerformanceInfo.MatchesFound += matches.Count; if(matches.Count == 0) { procEnv.EndOfIteration(false, this); Rule.executionState = SequenceExecutionState.Fail; return res; } #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Rule " + Rule.GetRuleCallString(procEnv) + " matched " + matches.Count + " times"); #endif // the rule might be called again in the sequence, overwriting the matches object of the action // normally it's safe to assume the rule is not called again until its matches were processed, // allowing for the one matches object memory optimization, but here we must clone to prevent bad side effect // TODO: optimization; if it's ensured the sequence doesn't call this action again, we can omit this, requires call analysis matches = matches.Clone(); // apply the sequence for every match found bool first = true; foreach(IMatch match in matches) { if(!first) procEnv.EndOfIteration(true, this); Var.SetVariableValue(match, procEnv); #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Iterating match: " + MatchPrinter.ToString(match, procEnv.Graph, "")); #endif procEnv.EnteringSequence(Rule); Rule.executionState = SequenceExecutionState.Underway; procEnv.Matched(matches, match, Rule.Special); Rule.executionState = SequenceExecutionState.Success; procEnv.ExitingSequence(Rule); // rule matching simulated so it can be shown in the debugger, now execute the sequence Seq.ResetExecutionState(); res &= Seq.Apply(procEnv); first = false; } procEnv.EndOfIteration(false, this); return res; }
protected bool ApplyRule(SequenceRuleCall rule, IGraphProcessingEnvironment procEnv, IMatches matches, IMatch match) { bool result; procEnv.EnteringSequence(rule); rule.executionState = SequenceExecutionState.Underway; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Before executing sequence " + rule.Id + ": " + rule.Symbol); #endif procEnv.Matched(matches, null, rule.Special); result = rule.Rewrite(procEnv, matches, match); #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("After executing sequence " + rule.Id + ": " + rule.Symbol + " result " + result); #endif rule.executionState = result ? SequenceExecutionState.Success : SequenceExecutionState.Fail; procEnv.ExitingSequence(rule); return result; }
protected override bool ApplyImpl(IGraphProcessingEnvironment procEnv) { // first get all matches of the rule object[] parameters; if(Rule.ParamBindings.ArgumentExpressions.Length > 0) { parameters = Rule.ParamBindings.Arguments; for(int j = 0; j < Rule.ParamBindings.ArgumentExpressions.Length; j++) { if(Rule.ParamBindings.ArgumentExpressions[j] != null) parameters[j] = Rule.ParamBindings.ArgumentExpressions[j].Evaluate(procEnv); } } else parameters = null; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Matching backtrack all " + Rule.GetRuleCallString(procEnv)); #endif #if DEBUGACTIONS || MATCHREWRITEDETAIL procEnv.PerformanceInfo.StartLocal(); #endif IMatches matches = Rule.ParamBindings.Action.Match(procEnv, procEnv.MaxMatches, parameters); for(int i=0; i<Rule.Filters.Count; ++i) Rule.ParamBindings.Action.Filter(procEnv, matches, Rule.Filters[i]); #if DEBUGACTIONS || MATCHREWRITEDETAIL procEnv.PerformanceInfo.StopMatch(); // total match time does NOT include listeners anymore #endif procEnv.PerformanceInfo.MatchesFound += matches.Count; if(matches.Count == 0) { Rule.executionState = SequenceExecutionState.Fail; return false; } #if LOG_SEQUENCE_EXECUTION for(int i = 0; i < matches.Count; ++i) { procEnv.Recorder.WriteLine("match " + i + ": " + MatchPrinter.ToString(matches.GetMatch(i), procEnv.Graph, "")); } #endif // the rule might be called again in the sequence, overwriting the matches object of the action // normally it's safe to assume the rule is not called again until its matches were processed, // allowing for the one matches object memory optimization, but here we must clone to prevent bad side effect // TODO: optimization; if it's ensured the sequence doesn't call this action again, we can omit this, requires call analysis matches = matches.Clone(); #if LOG_SEQUENCE_EXECUTION for(int i = 0; i < matches.Count; ++i) { procEnv.Recorder.WriteLine("cloned match " + i + ": " + MatchPrinter.ToString(matches.GetMatch(i), procEnv.Graph, "")); } #endif // apply the rule and the following sequence for every match found, // until the first rule and sequence execution succeeded // rolling back the changes of failing executions until then int matchesTried = 0; foreach(IMatch match in matches) { ++matchesTried; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Applying backtrack match " + matchesTried + "/" + matches.Count + " of " + Rule.GetRuleCallString(procEnv)); procEnv.Recorder.WriteLine("match: " + MatchPrinter.ToString(match, procEnv.Graph, "")); #endif // start a transaction int transactionID = procEnv.TransactionManager.Start(); int oldRewritesPerformed = procEnv.PerformanceInfo.RewritesPerformed; procEnv.EnteringSequence(Rule); Rule.executionState = SequenceExecutionState.Underway; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Before executing sequence " + Rule.Id + ": " + Rule.Symbol); #endif procEnv.Matched(matches, match, Rule.Special); bool result = Rule.Rewrite(procEnv, matches, match); #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("After executing sequence " + Rule.Id + ": " + Rule.Symbol + " result " + result); #endif Rule.executionState = result ? SequenceExecutionState.Success : SequenceExecutionState.Fail; procEnv.ExitingSequence(Rule); // rule applied, now execute the sequence result = Seq.Apply(procEnv); // if sequence execution failed, roll the changes back and try the next match of the rule if(!result) { procEnv.TransactionManager.Rollback(transactionID); procEnv.PerformanceInfo.RewritesPerformed = oldRewritesPerformed; if(matchesTried < matches.Count) { procEnv.EndOfIteration(true, this); Rule.ResetExecutionState(); Seq.ResetExecutionState(); continue; } else { // all matches tried, all failed later on -> end in fail #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Applying backtrack match exhausted " + Rule.GetRuleCallString(procEnv)); #endif procEnv.EndOfIteration(false, this); return false; } } // if sequence execution succeeded, commit the changes so far and succeed procEnv.TransactionManager.Commit(transactionID); procEnv.EndOfIteration(false, this); return true; } return false; // to satisfy the compiler, we return from inside the loop }
/// <summary> /// Applies this sequence. /// </summary> /// <param name="procEnv">The graph processing environment on which this sequence is to be applied. /// Contains especially the graph on which this sequence is to be applied. /// And the user proxy queried when choices are due. /// The rules will only be chosen during the Sequence object instantiation, so /// exchanging rules will have no effect for already existing Sequence objects.</param> /// <returns>True, iff the sequence succeeded</returns> public bool Apply(IGraphProcessingEnvironment procEnv) { procEnv.EnteringSequence(this); executionState = SequenceExecutionState.Underway; #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("Before executing sequence " + Id + ": " + Symbol); #endif bool res = ApplyImpl(procEnv); #if LOG_SEQUENCE_EXECUTION procEnv.Recorder.WriteLine("After executing sequence " + Id + ": " + Symbol + " result " + res); #endif executionState = res ? SequenceExecutionState.Success : SequenceExecutionState.Fail; procEnv.ExitingSequence(this); return res; }