PathCalculator.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. using System;
  2. using System.Linq;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. namespace csharp_sccd_compiler
  6. {
  7. /// <summary>
  8. /// Computes the states that must be exited and entered for a specific transition if the system is to make that transition.
  9. /// </summary>
  10. public class PathCalculator : Visitor
  11. {
  12. public PathCalculator()
  13. {
  14. }
  15. public override void visit(ClassDiagram class_diagram)
  16. {
  17. foreach(Class c in class_diagram.classes)
  18. c.accept(this);
  19. }
  20. public override void visit(Class c)
  21. {
  22. c.statechart.accept(this);
  23. }
  24. public override void visit(StateChart statechart)
  25. {
  26. foreach (StateChartNode node in statechart.basics.Concat(statechart.composites))
  27. node.accept(this);
  28. }
  29. public override void visit(StateChartNode node)
  30. {
  31. foreach (StateChartTransition transition in node.transitions)
  32. transition.accept(this);
  33. }
  34. public override void visit(StateChartTransition transition)
  35. {
  36. //Find the scope of the transition (lowest common proper ancestor)
  37. //TODO: Could it be made more efficient if we calculated the LCA from the source node and just one of the target nodes?
  38. StateChartNode LCA = this.calculateLCA(transition);
  39. //Calculate exit nodes
  40. transition.exit_nodes = new List<StateChartNode>(){transition.parent};
  41. foreach(StateChartNode node in transition.parent.getAncestors())
  42. {
  43. if (object.ReferenceEquals(node, LCA))
  44. break;
  45. transition.exit_nodes.Add(node);
  46. }
  47. //Calculate enter nodes
  48. transition.enter_nodes = new List<Tuple<StateChartNode, bool>>();
  49. foreach (StateChartNode target_node in transition.target.target_nodes)
  50. {
  51. var to_append = new List<Tuple<StateChartNode, bool>>(){new Tuple<StateChartNode, bool>(target_node, true)};
  52. foreach (StateChartNode anc in target_node.getAncestors())
  53. {
  54. if (object.ReferenceEquals(anc, LCA))//If we reach the LCA in the ancestor hierarchy we break
  55. break;
  56. bool to_add = true; //boolean value to see if the current ancestor should be added to the result
  57. foreach (Tuple<StateChartNode, bool> enter_node_entry in transition.enter_nodes)
  58. {
  59. if (object.ReferenceEquals(enter_node_entry.Item1, anc))
  60. {
  61. to_add = false; //If we reach an ancestor in the hierarchy that is already listed as enter node, we don't add and break
  62. break;
  63. }
  64. }
  65. if (to_add)
  66. to_append.Add(new Tuple<StateChartNode, bool>(anc, false)); //Only target nodes get true
  67. else
  68. break;
  69. }
  70. to_append.Reverse();
  71. transition.enter_nodes.AddRange(to_append);
  72. }
  73. }
  74. private StateChartNode calculateLCA(StateChartTransition transition)
  75. {
  76. foreach(StateChartNode anc in transition.parent.getAncestors())
  77. {
  78. bool all_descendants = true;
  79. foreach (StateChartNode node in transition.target.target_nodes)
  80. {
  81. if (!node.isDescendantOf(anc))
  82. {
  83. all_descendants = false;
  84. break;
  85. }
  86. }
  87. if (all_descendants)
  88. return anc;
  89. }
  90. return null;
  91. }
  92. }
  93. }