using System; using System.Linq; using System.Collections; using System.Collections.Generic; namespace csharp_sccd_compiler { /// /// Computes the states that must be exited and entered for a specific transition if the system is to make that transition. /// public class PathCalculator : Visitor { public PathCalculator() { } public override void visit(ClassDiagram class_diagram) { foreach(Class c in class_diagram.classes) c.accept(this); } public override void visit(Class c) { c.statechart.accept(this); } public override void visit(StateChart statechart) { foreach (StateChartNode node in statechart.basics.Concat(statechart.composites)) node.accept(this); } public override void visit(StateChartNode node) { foreach (StateChartTransition transition in node.transitions) transition.accept(this); } public override void visit(StateChartTransition transition) { //Find the scope of the transition (lowest common proper ancestor) //TODO: Could it be made more efficient if we calculated the LCA from the source node and just one of the target nodes? StateChartNode LCA = this.calculateLCA(transition); //Calculate exit nodes transition.exit_nodes = new List(){transition.parent}; foreach(StateChartNode node in transition.parent.getAncestors()) { if (object.ReferenceEquals(node, LCA)) break; transition.exit_nodes.Add(node); } //Calculate enter nodes transition.enter_nodes = new List>(); foreach (StateChartNode target_node in transition.target.target_nodes) { var to_append = new List>(){new Tuple(target_node, true)}; foreach (StateChartNode anc in target_node.getAncestors()) { if (object.ReferenceEquals(anc, LCA))//If we reach the LCA in the ancestor hierarchy we break break; bool to_add = true; //boolean value to see if the current ancestor should be added to the result foreach (Tuple enter_node_entry in transition.enter_nodes) { if (object.ReferenceEquals(enter_node_entry.Item1, anc)) { to_add = false; //If we reach an ancestor in the hierarchy that is already listed as enter node, we don't add and break break; } } if (to_add) to_append.Add(new Tuple(anc, false)); //Only target nodes get true else break; } to_append.Reverse(); transition.enter_nodes.AddRange(to_append); } } private StateChartNode calculateLCA(StateChartTransition transition) { foreach(StateChartNode anc in transition.parent.getAncestors()) { bool all_descendants = true; foreach (StateChartNode node in transition.target.target_nodes) { if (!node.isDescendantOf(anc)) { all_descendants = false; break; } } if (all_descendants) return anc; } return null; } } }