CSharpGenerator.cs 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. using System;
  2. using System.Linq;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. namespace csharp_sccd_compiler
  6. {
  7. public class CSharpGenerator : CodeGenerator
  8. {
  9. public CSharpGenerator() : base( new Platform[]{Platform.THREADS, Platform.GAMELOOP} )
  10. {
  11. }
  12. public override void visit(ClassDiagram class_diagram)
  13. {
  14. this.output_file.write("/*");
  15. this.output_file.indent();
  16. this.output_file.write("Statecharts + Class Diagram compiler by Glenn De Jonghe");
  17. this.output_file.write();
  18. this.output_file.write(string.Format("Generated on {0}.", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
  19. if (class_diagram.model_name != null || class_diagram.model_author != null || class_diagram.model_description != null)
  20. this.output_file.write();
  21. if (class_diagram.model_name != null)
  22. this.output_file.write("Model name: " + class_diagram.model_name);
  23. if (class_diagram.model_author != null)
  24. this.output_file.write("Model author: " + class_diagram.model_author);
  25. if (class_diagram.model_description != null)
  26. {
  27. this.output_file.write("Model description:");
  28. this.output_file.write();
  29. this.output_file.indent();
  30. this.writeCorrectIndent(class_diagram.model_description);
  31. this.output_file.dedent();
  32. }
  33. this.output_file.dedent();
  34. this.output_file.write("*/");
  35. this.output_file.write();
  36. //Use runtime libraries
  37. this.output_file.write("using System;");
  38. this.output_file.write("using System.Collections.Generic;");
  39. this.output_file.write("using sccdlib;");
  40. //Namespace using declarations by the user
  41. if (class_diagram.top_section != null)
  42. this.writeCorrectIndent(class_diagram.top_section);
  43. this.output_file.write();
  44. //visit children
  45. foreach (Class c in class_diagram.classes)
  46. c.accept(this);
  47. //writing out ObjectManager
  48. this.output_file.write("public class ObjectManager : ObjectManagerBase");
  49. this.output_file.write("{");
  50. this.output_file.indent();
  51. this.output_file.write("public ObjectManager(ControllerBase controller): base(controller)");
  52. this.output_file.write("{");
  53. this.output_file.write("}");
  54. this.output_file.write();
  55. this.output_file.write("protected override InstanceWrapper instantiate(string class_name, object[] construct_params)");
  56. this.output_file.write("{");
  57. this.output_file.indent();
  58. this.output_file.write("RuntimeClassBase instance = null;");
  59. this.output_file.write("List<Association> associations = new List<Association>();");
  60. for (int index = 0; index < class_diagram.classes.Count; ++index)
  61. {
  62. if (index == 0)
  63. this.output_file.write();
  64. else
  65. this.output_file.write("}else ");
  66. this.output_file.extendWrite("if (class_name == \"" + class_diagram.classes[index].name + "\" ){");
  67. this.output_file.indent();
  68. this.output_file.write("object[] new_parameters = new object[construct_params.Length + 1];");
  69. this.output_file.write("new_parameters[0] = this.controller;");
  70. this.output_file.write("Array.Copy(construct_params, 0, new_parameters, 1, construct_params.Length);");
  71. this.output_file.write("instance = (RuntimeClassBase) Activator.CreateInstance(typeof(" + class_diagram.classes[index].name + "), new_parameters);");
  72. foreach (Association association in class_diagram.classes[index].associations)
  73. association.accept(this);
  74. this.output_file.dedent();
  75. if (index == class_diagram.classes.Count - 1)
  76. this.output_file.write("}");
  77. }
  78. this.output_file.write("if (instance != null) {");
  79. this.output_file.indent();
  80. this.output_file.write("return new InstanceWrapper(instance, associations);");
  81. this.output_file.dedent();
  82. this.output_file.write("}");
  83. this.output_file.write("return null;");
  84. this.output_file.dedent();
  85. this.output_file.write("}");
  86. this.output_file.dedent();
  87. this.output_file.write("}");
  88. //Write out controller
  89. this.output_file.write();
  90. string controller_sub_class = "";
  91. if (this.current_platform == Platform.THREADS)
  92. controller_sub_class = "ThreadsControllerBase";
  93. else if (this.current_platform == Platform.GAMELOOP)
  94. controller_sub_class = "GameLoopControllerBase";
  95. this.output_file.write("public class Controller : " + controller_sub_class);
  96. this.output_file.write("{");
  97. this.output_file.indent();
  98. //Write out constructor(s)
  99. if (class_diagram.default_class.constructors != null)
  100. foreach (Constructor constructor in class_diagram.default_class.constructors)
  101. this.writeControllerConstructor(class_diagram, constructor.parameters);
  102. else
  103. this.writeControllerConstructor(class_diagram, new List<FormalParameter>());
  104. this.output_file.write("public static void Main()");
  105. this.output_file.write("{");
  106. this.output_file.indent();
  107. this.output_file.write("Controller controller = new Controller();");
  108. this.output_file.write("controller.start();");
  109. this.output_file.dedent();
  110. this.output_file.write("}");
  111. this.output_file.dedent();
  112. this.output_file.write("}");
  113. }
  114. /// <summary>
  115. /// Helper method
  116. /// </summary>
  117. private void writeControllerConstructor(ClassDiagram class_diagram, List<FormalParameter> parameters)
  118. {
  119. this.output_file.write("public Controller(");
  120. this.writeFormalParameters(parameters.Concat(new FormalParameter[]{new FormalParameter("keep_running", "bool", "true")}));
  121. this.output_file.extendWrite(") : base(keep_running)");
  122. this.output_file.write("{");
  123. this.output_file.indent();
  124. foreach (string p in class_diagram.inports)
  125. this.output_file.write("this.addInputPort(\"" + p + "\");");
  126. foreach (string p in class_diagram.outports)
  127. this.output_file.write("this.addOutputPort(\"" + p + "\");");
  128. this.output_file.write("this.object_manager = new ObjectManager(this);");
  129. string[] actual_parameters = (from parameter in parameters select parameter.name).ToArray();
  130. this.output_file.write("this.object_manager.createInstance(\"" + class_diagram.default_class.name + "\", new object[]{" + string.Join(", ", actual_parameters) + "});");
  131. this.output_file.dedent();
  132. this.output_file.write("}");
  133. }
  134. /// <summary>
  135. /// Generate code for Class construct
  136. /// </summary>
  137. public override void visit(Class class_node)
  138. {
  139. this.output_file.write();
  140. this.output_file.write("public class " + class_node.name);
  141. // Take care of inheritance
  142. if (class_node.super_class != null)
  143. this.output_file.extendWrite(" : " + class_node.super_class);
  144. else
  145. this.output_file.extendWrite(" : " + "RuntimeClassBase");
  146. this.output_file.write("{");
  147. this.output_file.indent();
  148. this.output_file.write();
  149. if (class_node.statechart != null)
  150. {
  151. //assign each node a unique ID
  152. this.output_file.write("/// <summary>");
  153. this.output_file.write("/// Enum uniquely representing all statechart nodes.");
  154. this.output_file.write("/// </summary>");
  155. this.output_file.write("public enum Node {");
  156. this.output_file.indent();
  157. foreach( StateChartNode node in class_node.statechart.composites.Concat(class_node.statechart.basics))
  158. this.output_file.write(node.full_name + ",");
  159. this.output_file.dedent();
  160. this.output_file.write("};");
  161. this.output_file.write();
  162. this.output_file.write("Dictionary<Node,List<Node>> current_state = new Dictionary<Node,List<Node>>();");
  163. if (class_node.statechart.histories.Count > 0)
  164. this.output_file.write("Dictionary<Node,List<Node>> history_state = new Dictionary<Node,List<Node>>();");
  165. this.output_file.write();
  166. }
  167. //User defined attributes
  168. if (class_node.attributes.Count > 0)
  169. {
  170. this.output_file.write("//User defined attributes");
  171. foreach (Attribute attribute in class_node.attributes)
  172. {
  173. this.output_file.write(attribute.type + " " + attribute.name);
  174. if (attribute.init_value != null)
  175. this.output_file.extendWrite(" = " + attribute.init_value);
  176. this.output_file.extendWrite(";");
  177. }
  178. this.output_file.write();
  179. }
  180. if (class_node.statechart != null)
  181. {
  182. this.output_file.write("/// <summary>");
  183. this.output_file.write("/// Constructor part that is common for all constructors.");
  184. this.output_file.write("/// </summary>");
  185. this.output_file.write("private void commonConstructor(ControllerBase controller = null)");
  186. this.output_file.write("{");
  187. this.output_file.indent();
  188. this.output_file.write("this.controller = controller;");
  189. this.output_file.write("this.object_manager = controller.getObjectManager();");
  190. if (class_node.statechart.nr_of_after_transitions != 0)
  191. this.output_file.write("this.timers = new Dictionary<int,double>();");
  192. this.output_file.write();
  193. this.output_file.write("//Initialize statechart :");
  194. this.output_file.write();
  195. if (class_node.statechart.histories.Count > 0)
  196. {
  197. foreach (StateChartNode node in class_node.statechart.combined_history_parents)
  198. {
  199. this.output_file.write("this.history_state[Node." + node.full_name + "] = new List<Node>();");
  200. }
  201. this.output_file.write();
  202. }
  203. foreach (StateChartNode node in class_node.statechart.composites)
  204. this.output_file.write("this.current_state[Node." + node.full_name + "] = new List<Node>();");
  205. }
  206. this.output_file.dedent();
  207. this.output_file.write("}");
  208. this.output_file.write();
  209. this.output_file.write("public override void start()");
  210. this.output_file.write("{");
  211. this.output_file.indent();
  212. this.output_file.write("base.start();");
  213. foreach (StateChartNode default_node in class_node.statechart.root.defaults)
  214. {
  215. if (default_node.is_composite)
  216. this.output_file.write("this.enterDefault_" + default_node.full_name + "();");
  217. else if (default_node.is_basic)
  218. this.output_file.write("this.enter_" + default_node.full_name + "();");
  219. }
  220. this.output_file.dedent();
  221. this.output_file.write("}");
  222. this.output_file.write();
  223. //visit children
  224. foreach( var i in class_node.constructors)
  225. i.accept(this);
  226. foreach( var i in class_node.destructors)
  227. i.accept(this);
  228. foreach( var i in class_node.methods)
  229. i.accept(this);
  230. if (class_node.statechart != null)
  231. class_node.statechart.accept(this);
  232. this.output_file.dedent();
  233. this.output_file.write("}");
  234. this.output_file.write();
  235. }
  236. /// <summary>
  237. /// Helper method that writes a correct comma separated list of formal parameters.
  238. /// </summary>
  239. private void writeFormalParameters(IEnumerable<FormalParameter> parameters)
  240. {
  241. bool first = true;
  242. foreach (FormalParameter param in parameters)
  243. {
  244. if (first)
  245. first = false;
  246. else
  247. this.output_file.extendWrite(", ");
  248. param.accept(this);
  249. }
  250. }
  251. public override void visit(FormalParameter formal_parameter)
  252. {
  253. this.output_file.extendWrite(formal_parameter.type + " " + formal_parameter.name);
  254. if (formal_parameter.default_value != null)
  255. this.output_file.extendWrite(" = " + formal_parameter.default_value);
  256. }
  257. public override void visit(Constructor constructor)
  258. {
  259. this.output_file.write(constructor.access + " " + constructor.name + "(");
  260. this.writeFormalParameters(new FormalParameter[]{new FormalParameter("controller", "ControllerBase", null)}.Concat(constructor.parameters));
  261. this.output_file.extendWrite(")");
  262. this.output_file.write("{");
  263. this.output_file.indent();
  264. this.output_file.write("this.commonConstructor(controller);");
  265. if (constructor.body != null && constructor.body.Trim() != "")
  266. {
  267. this.output_file.write();
  268. this.output_file.write("//constructor body (user-defined)");
  269. this.writeCorrectIndent(constructor.body);
  270. }
  271. this.output_file.dedent();
  272. this.output_file.write("}");
  273. this.output_file.write();
  274. }
  275. public override void visit(Destructor destructor)
  276. {
  277. this.output_file.write(destructor.name + "()");
  278. this.output_file.write("{");
  279. if (destructor.body != null)
  280. {
  281. this.output_file.indent();
  282. this.writeCorrectIndent(destructor.body);
  283. this.output_file.dedent();
  284. }
  285. this.output_file.write("}");
  286. this.output_file.write();
  287. }
  288. public override void visit(Method method)
  289. {
  290. this.output_file.write(method.access + " " + method.return_type + " " + method.name + "(");
  291. this.writeFormalParameters(method.parameters);
  292. this.output_file.extendWrite(")");
  293. this.output_file.write("{");
  294. this.output_file.indent();
  295. if (method.body != null)
  296. {
  297. this.output_file.indent();
  298. this.writeCorrectIndent(method.body);
  299. this.output_file.dedent();
  300. }
  301. this.output_file.dedent();
  302. this.output_file.write("}");
  303. this.output_file.write();
  304. }
  305. public override void visit(Association association)
  306. {
  307. this.output_file.write("associations.Add(new Association(\"" + association.name + "\", \"" + association.to_class + "\", " + association.min.ToString() + ", " + association.max.ToString() + "));");
  308. }
  309. /// <summary>
  310. /// Helper method that writes the transitions recursively.
  311. /// </summary>
  312. public void writeTransitionsRecursively(StateChartNode current_node)
  313. {
  314. this.output_file.write("private bool transition_" + current_node.full_name + "(Event e)");
  315. this.output_file.write("{");
  316. this.output_file.indent();
  317. List<StateChartNode> valid_children = new List<StateChartNode>();
  318. foreach (StateChartNode child in current_node.children)
  319. {
  320. if (child.is_composite || child.is_basic)
  321. valid_children.Add(child);
  322. }
  323. this.output_file.write("bool catched = false;");
  324. bool do_dedent = false;
  325. if (current_node.solves_conflict_outer)
  326. {
  327. this.writeFromTransitions(current_node);
  328. if (current_node.is_parallel || current_node.is_composite)
  329. {
  330. this.output_file.write("if (!catched){");
  331. this.output_file.indent();
  332. do_dedent = true;
  333. }
  334. }
  335. if (current_node.is_parallel)
  336. {
  337. foreach (StateChartNode child in valid_children)
  338. this.output_file.write("catched = this.transition_" + child.full_name + "(e) || catched;");
  339. }
  340. else if (current_node.is_composite)
  341. {
  342. this.output_file.write();
  343. for (int i=0; i < valid_children.Count; ++i)
  344. {
  345. if (i > 0)
  346. this.output_file.extendWrite(" else ");
  347. this.output_file.extendWrite("if (this.current_state[Node." + current_node.full_name + "][0] == Node." + valid_children[i].full_name + "){");
  348. this.output_file.indent();
  349. this.output_file.write("catched = this.transition_" + valid_children[i].full_name + "(e);");
  350. this.output_file.dedent();
  351. this.output_file.write("}");
  352. }
  353. }
  354. if (current_node.solves_conflict_outer)
  355. {
  356. if (do_dedent)
  357. {
  358. this.output_file.dedent();
  359. this.output_file.write("}");
  360. }
  361. }
  362. else if (current_node.transitions.Count > 0)
  363. {
  364. this.output_file.write("if (!catched) {");
  365. this.output_file.indent();
  366. this.writeFromTransitions(current_node);
  367. this.output_file.dedent();
  368. this.output_file.write("}");
  369. }
  370. this.output_file.write("return catched;");
  371. this.output_file.dedent();
  372. this.output_file.write("}");
  373. this.output_file.write();
  374. foreach (StateChartNode child in valid_children)
  375. this.writeTransitionsRecursively(child);
  376. }
  377. /// <summary>
  378. /// Helper method
  379. /// </summary>
  380. private void writeFromTransitions(StateChartNode current_node)
  381. {
  382. if (current_node.transitions.Count == 0)
  383. return;
  384. this.output_file.write("List<int> enableds = new List<int>();");
  385. for (int index=0; index < current_node.transitions.Count; ++index)
  386. this.writeTransitionCondition(current_node.transitions[index], index);
  387. this.output_file.write("if (enableds.Count > 1){");
  388. this.output_file.indent();
  389. this.output_file.write("Console.WriteLine(\"Runtime warning : indeterminism detected in a transition from node " + current_node.full_name + ". Only the first in document order enabled transition is executed.\");");
  390. this.output_file.dedent();
  391. this.output_file.write("}");
  392. this.output_file.write("if (enableds.Count > 0){");
  393. this.output_file.indent();
  394. this.output_file.write("int enabled = enableds[0];");
  395. this.output_file.write();
  396. for (int index=0; index < current_node.transitions.Count; ++index)
  397. this.writeTransitionAction(current_node.transitions[index], index);
  398. this.output_file.write("catched = true;");
  399. this.output_file.dedent();
  400. this.output_file.write("}");
  401. this.output_file.write();
  402. }
  403. public override void visit( FormalEventParameter formal_event_parameter)
  404. {
  405. this.output_file.extendWrite(formal_event_parameter.type + " " + formal_event_parameter.name);
  406. }
  407. /// <summary>
  408. /// Helper method
  409. /// </summary>
  410. private void writeFormalEventParameters(StateChartTransition transition)
  411. {
  412. if (transition.trigger.parameters.Count > 0)
  413. {
  414. this.output_file.write("object[] parameters = e.getParameters();");
  415. for (int index=0; index < transition.trigger.parameters.Count; ++index)
  416. {
  417. this.output_file.write();
  418. transition.trigger.parameters[index].accept(this);
  419. this.output_file.extendWrite(" = (" + transition.trigger.parameters[index].type + ")parameters[" + index.ToString() + "];");
  420. }
  421. }
  422. }
  423. ///
  424. private void writeTransitionAction(StateChartTransition transition, int index)
  425. {
  426. if (index > 1)
  427. this.output_file.extendWrite(" else ");
  428. else
  429. this.output_file.write();
  430. this.output_file.extendWrite("if (enabled == " + index.ToString() + "){");
  431. this.output_file.indent();
  432. //Handle parameters to actually use them
  433. this.writeFormalEventParameters(transition);
  434. //Write out exit actions
  435. StateChartNode last_exit_node = transition.exit_nodes[transition.exit_nodes.Count - 1];
  436. if (!last_exit_node.is_basic)
  437. this.output_file.write("this.exit_" + last_exit_node.full_name + "();");
  438. else
  439. {
  440. foreach (StateChartNode node in transition.exit_nodes)
  441. {
  442. if (node.is_basic)
  443. this.output_file.write("this.exit_" + node.full_name + "();");
  444. }
  445. }
  446. //Write out trigger actions
  447. transition.action.accept(this);
  448. foreach (Tuple<StateChartNode,bool> enter_node_tuple in transition.enter_nodes)
  449. {
  450. StateChartNode entering_node = enter_node_tuple.Item1;
  451. if (enter_node_tuple.Item2)
  452. {
  453. if (entering_node.is_composite)
  454. this.output_file.write("this.enterDefault_" + entering_node.full_name + "();");
  455. else if (entering_node.is_history)
  456. {
  457. if (entering_node.is_history_deep)
  458. this.output_file.write("this.enterHistoryDeep_" + entering_node.parent.full_name + "();");
  459. else
  460. this.output_file.write("this.enterHistoryShallow_" + entering_node.parent.full_name + "();");
  461. }
  462. else
  463. this.output_file.write("this.enter_" + entering_node.full_name + "();");
  464. }
  465. else
  466. {
  467. if (entering_node.is_composite)
  468. this.output_file.write("this.enter_" + entering_node.full_name + "();");
  469. }
  470. }
  471. this.output_file.dedent();
  472. this.output_file.write("}");
  473. }
  474. private void writeTransitionCondition(StateChartTransition transition, int index)
  475. {
  476. if (!transition.trigger.is_uc)
  477. {
  478. this.output_file.write("if (e.getName() == \"" + transition.trigger.event_name + "\" && e.getPort() == \"" + transition.trigger.port + "\"){");
  479. this.output_file.indent();
  480. }
  481. //Evaluate guard
  482. if (transition.guard != null)
  483. {
  484. //Handle parameters for guard evaluation
  485. this.writeFormalEventParameters(transition);
  486. this.output_file.write("if (");
  487. transition.guard.accept(this);
  488. this.output_file.extendWrite("){");
  489. this.output_file.indent();
  490. }
  491. this.output_file.write("enableds.Add(" + index.ToString() + ");");
  492. if (transition.guard != null)
  493. {
  494. this.output_file.dedent();
  495. this.output_file.write("}");
  496. }
  497. if (!transition.trigger.is_uc)
  498. {
  499. this.output_file.dedent();
  500. this.output_file.write("}");
  501. }
  502. this.output_file.write();
  503. }
  504. public override void visit(EnterAction enter_method)
  505. {
  506. this.output_file.write("private void enter_" + enter_method.parent.full_name + "()");
  507. this.output_file.write("{");
  508. this.output_file.indent();
  509. //Take care of any AFTER events
  510. foreach (StateChartTransition transition in enter_method.parent.transitions)
  511. {
  512. if (transition.trigger.is_after)
  513. {
  514. this.output_file.write("this.timers[" + transition.trigger.after_index.ToString() + "] = ");
  515. transition.trigger.after_expression.accept(this);
  516. this.output_file.extendWrite(";");
  517. }
  518. }
  519. if (enter_method.action != null)
  520. enter_method.action.accept(this);
  521. this.output_file.write("this.current_state[Node." + enter_method.parent.parent.full_name + "].Add(Node." + enter_method.parent.full_name + ");");
  522. this.output_file.dedent();
  523. this.output_file.write("}");
  524. this.output_file.write();
  525. }
  526. private void writeEnterDefault(StateChartNode entered_node)
  527. {
  528. this.output_file.write("private void enterDefault_" + entered_node.full_name + "()");
  529. this.output_file.write("{");
  530. this.output_file.indent();
  531. this.output_file.write("this.enter_" + entered_node.full_name + "();");
  532. if (entered_node.is_composite)
  533. {
  534. foreach(StateChartNode default_node in entered_node.defaults)
  535. {
  536. if (default_node.is_composite)
  537. this.output_file.write("this.enterDefault_" + default_node.full_name + "();");
  538. else if (default_node.is_basic)
  539. this.output_file.write("this.enter_" + default_node.full_name + "();");
  540. }
  541. }
  542. this.output_file.dedent();
  543. this.output_file.write("}");
  544. this.output_file.write();
  545. }
  546. public override void visit(ExitAction exit_method)
  547. {
  548. this.output_file.write("private void exit_" + exit_method.parent.full_name + "()");
  549. this.output_file.write("{");
  550. this.output_file.indent();
  551. //If the exited node is composite take care of potential history and the leaving of descendants
  552. if (exit_method.parent.is_composite)
  553. {
  554. //handle history
  555. if (exit_method.parent.save_state_on_exit)
  556. this.output_file.write("this.history_state[Node." + exit_method.parent.full_name + "].AddRange(this.current_state[Node." + exit_method.parent.full_name + "]);");
  557. //Take care of leaving children
  558. if (exit_method.parent.is_parallel)
  559. {
  560. foreach(StateChartNode child in exit_method.parent.children)
  561. {
  562. if (!child.is_history)
  563. this.output_file.write("this.exit_" + child.full_name + "();");
  564. }
  565. }
  566. else
  567. {
  568. foreach(StateChartNode child in exit_method.parent.children)
  569. {
  570. if (!child.is_history)
  571. {
  572. this.output_file.write("if (this.current_state[Node." + exit_method.parent.full_name + "].Contains(Node." + child.full_name + ")){");
  573. this.output_file.indent();
  574. this.output_file.write("this.exit_" + child.full_name + "();");
  575. this.output_file.dedent();
  576. this.output_file.write("}");
  577. }
  578. }
  579. }
  580. }
  581. //Take care of any AFTER events
  582. foreach (StateChartTransition transition in exit_method.parent.transitions)
  583. {
  584. if (transition.trigger.is_after)
  585. this.output_file.write("this.timers.Remove(" + transition.trigger.after_index.ToString() + ");");
  586. }
  587. //Execute user-defined exit action if present
  588. if (exit_method.action != null)
  589. exit_method.action.accept(this);
  590. //Adjust state
  591. this.output_file.write("this.current_state[Node." + exit_method.parent.parent.full_name + "].Remove(Node." + exit_method.parent.full_name + ");");
  592. this.output_file.dedent();
  593. this.output_file.write("}");
  594. this.output_file.write();
  595. }
  596. private void writeEnterHistory(StateChartNode entered_node, bool is_deep)
  597. {
  598. this.output_file.write("private void enterHistory");
  599. if (is_deep)
  600. this.output_file.extendWrite("Deep");
  601. else
  602. this.output_file.extendWrite("Shallow");
  603. this.output_file.extendWrite("_" + entered_node.full_name + "()");
  604. this.output_file.write("{");
  605. this.output_file.indent();
  606. this.output_file.write("if (this.history_state[Node." + entered_node.full_name + "].Count == 0){");
  607. this.output_file.indent();
  608. foreach (StateChartNode node in entered_node.defaults)
  609. {
  610. if (node.is_basic)
  611. this.output_file.write("this.enter_" + node.full_name + "();");
  612. else if (node.is_composite)
  613. this.output_file.write("this.enterDefault_" + node.full_name + "();");
  614. }
  615. this.output_file.dedent();
  616. this.output_file.write("} else {");
  617. this.output_file.indent();
  618. if (entered_node.is_parallel)
  619. {
  620. foreach (StateChartNode child in entered_node.children)
  621. {
  622. if (!child.is_history)
  623. {
  624. this.output_file.write("this.enterHistory");
  625. if (is_deep)
  626. this.output_file.extendWrite("Deep");
  627. else
  628. this.output_file.extendWrite("Shallow");
  629. this.output_file.extendWrite("_" + child.full_name + "();");
  630. }
  631. }
  632. }
  633. else
  634. {
  635. foreach (StateChartNode child in entered_node.children)
  636. {
  637. if (!child.is_history)
  638. {
  639. this.output_file.write("if (this.history_state[Node." + entered_node.full_name + "].Contains(Node." + child.full_name + ")){");
  640. this.output_file.indent();
  641. if (child.is_composite)
  642. {
  643. if (is_deep)
  644. {
  645. this.output_file.write("this.enter_" + child.full_name + "();");
  646. this.output_file.write("this.enterHistoryDeep_" + child.full_name + "();");
  647. }
  648. else
  649. this.output_file.write("this.enterDefault_" + child.full_name + "();");
  650. }
  651. else
  652. this.output_file.write("this.enter_" + child.full_name + "();");
  653. this.output_file.dedent();
  654. this.output_file.write("}");
  655. }
  656. }
  657. }
  658. this.output_file.dedent();
  659. this.output_file.write("}");
  660. this.output_file.dedent();
  661. this.output_file.write("}");
  662. this.output_file.write();
  663. }
  664. public override void visit(StateChart statechart)
  665. {
  666. this.output_file.write("//Statechart enter/exit action method(s) :");
  667. this.output_file.write();
  668. //Visit enter and exit actions of children
  669. foreach (StateChartNode node in statechart.composites.Concat(statechart.basics))
  670. {
  671. if (!object.ReferenceEquals(node, statechart.root))
  672. {
  673. node.enter_action.accept(this);
  674. node.exit_action.accept(this);
  675. }
  676. }
  677. //Write out statecharts methods for enter/exit state
  678. if (statechart.composites.Count > 1)
  679. {
  680. this.output_file.write("//Statechart enter/exit default method(s) :");
  681. this.output_file.write();
  682. foreach (StateChartNode node in statechart.composites)
  683. {
  684. if (!object.ReferenceEquals(node, statechart.root))
  685. this.writeEnterDefault(node);
  686. }
  687. }
  688. //Write out statecharts methods for enter/exit history
  689. if (statechart.histories.Count > 0)
  690. {
  691. this.output_file.write("//Statechart enter/exit history method(s) :");
  692. this.output_file.write();
  693. foreach (StateChartNode node in statechart.shallow_history_parents)
  694. this.writeEnterHistory(node, false);
  695. foreach (StateChartNode node in statechart.deep_history_parents)
  696. this.writeEnterHistory(node, true);
  697. }
  698. this.output_file.write("//Statechart transitions :");
  699. this.output_file.write();
  700. this.writeTransitionsRecursively(statechart.root);
  701. //Write out transition function
  702. this.output_file.write("protected override void transition (Event e = null)");
  703. this.output_file.write("{");
  704. this.output_file.indent();
  705. this.output_file.write("if (e == null) {");
  706. this.output_file.indent();
  707. this.output_file.write("e = new Event();");
  708. this.output_file.dedent();
  709. this.output_file.write("}");
  710. this.output_file.write("this.state_changed = this.transition_" + statechart.root.full_name + "(e);");
  711. this.output_file.dedent();
  712. this.output_file.write("}");
  713. this.output_file.write();
  714. //Write out inState function
  715. this.output_file.write("public bool inState(List<Node> nodes)");
  716. this.output_file.write("{");
  717. this.output_file.indent();
  718. this.output_file.write("foreach(List<Node> actives in current_state.Values){");
  719. this.output_file.indent();
  720. this.output_file.write("foreach(Node node in actives)");
  721. this.output_file.indent();
  722. this.output_file.write("nodes.Remove (node);");
  723. this.output_file.dedent();
  724. this.output_file.write("if (nodes.Count == 0){");
  725. this.output_file.indent();
  726. this.output_file.write("return true;");
  727. this.output_file.dedent();
  728. this.output_file.write("}");
  729. this.output_file.dedent();
  730. this.output_file.write("}");
  731. this.output_file.write("return false;");
  732. this.output_file.dedent();
  733. this.output_file.write("}");
  734. this.output_file.write();
  735. }
  736. public override void visit(ExpressionPartString expression_part_string)
  737. {
  738. this.output_file.extendWrite(expression_part_string.value);
  739. }
  740. public override void visit(SelfReference self_reference)
  741. {
  742. this.output_file.extendWrite("this");
  743. }
  744. public override void visit(StateReference state_ref)
  745. {
  746. this.output_file.extendWrite("new List<Node>() {");
  747. this.output_file.extendWrite(string.Join(", ", (from node in state_ref.target_nodes select "Node." + node.full_name)));
  748. this.output_file.extendWrite("}");
  749. }
  750. public override void visit(InStateCall in_state_call)
  751. {
  752. this.output_file.extendWrite("this.inState(");
  753. in_state_call.state_reference.accept(this);
  754. this.output_file.extendWrite(")");
  755. }
  756. public override void visit(RaiseEvent raise_event)
  757. {
  758. if (raise_event.scope == RaiseEvent.Scope.NARROW_SCOPE || raise_event.scope == RaiseEvent.Scope.BROAD_SCOPE)
  759. this.output_file.write("Event send_event = new Event(\"" + raise_event.event_name + "\", \"\", new object[] {");
  760. else if (raise_event.scope == RaiseEvent.Scope.LOCAL_SCOPE)
  761. this.output_file.write("this.addEvent( new Event(\"" + raise_event.event_name + "\", \"\", new object[] {");
  762. else if (raise_event.scope == RaiseEvent.Scope.OUTPUT_SCOPE)
  763. this.output_file.write("this.controller.outputEvent(new Event(\"" + raise_event.event_name + "\", \"" + raise_event.port + "\", new object[] {");
  764. else if (raise_event.scope == RaiseEvent.Scope.CD_SCOPE)
  765. this.output_file.write("this.object_manager.addEvent(new Event(\"" + raise_event.event_name + "\", \"\", new object[] { this, ");
  766. bool first_param = true;
  767. foreach (Expression param in raise_event.parameters)
  768. {
  769. if (first_param)
  770. first_param = false;
  771. else
  772. this.output_file.extendWrite(",");
  773. param.accept(this);
  774. }
  775. if (raise_event.scope == RaiseEvent.Scope.NARROW_SCOPE)
  776. {
  777. this.output_file.extendWrite("});");
  778. this.output_file.write("this.object_manager.addEvent(new Event(\"narrow_cast\", \"\", new object[] {this, \"" + raise_event.target + "\" ,send_event}));");
  779. }
  780. else if (raise_event.scope == RaiseEvent.Scope.BROAD_SCOPE)
  781. {
  782. this.output_file.extendWrite("});");
  783. this.output_file.write("this.object_manager.addEvent(new Event(\"broad_cast\", \"\", new object[] {send_event}));");
  784. }
  785. else
  786. this.output_file.extendWrite("}));");
  787. }
  788. public override void visit(Script script)
  789. {
  790. this.writeCorrectIndent(script.code);
  791. }
  792. public override void visit(Log log)
  793. {
  794. this.output_file.write("Console.WriteLine(\"" + log.message + "\");");
  795. }
  796. public override void visit(Assign assign)
  797. {
  798. this.output_file.write();
  799. assign.lvalue.accept(this);
  800. this.output_file.extendWrite(" = ");
  801. assign.expression.accept(this);
  802. this.output_file.extendWrite(";");
  803. }
  804. }
  805. }