SCCD_execute.alc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. include "primitives.alh"
  2. include "modelling.alh"
  3. include "object_operations.alh"
  4. include "utils.alh"
  5. include "random.alh"
  6. include "library.alh"
  7. include "io.alh"
  8. Element function resolve_function(location : String, data : Element):
  9. if (bool_not(dict_in(data["cache_operations"], location))):
  10. dict_add(data["cache_operations"], location, get_func_AL_model(import_node(location)))
  11. return data["cache_operations"][location]!
  12. Void function print_states(model : Element, data : Element):
  13. Element classes
  14. Element states
  15. Element class
  16. String state
  17. log("Current states:")
  18. classes = dict_keys(data["classes"])
  19. while (set_len(classes) > 0):
  20. class = set_pop(classes)
  21. class = data["classes"][class]
  22. log(string_join(string_join(string_join(" ", class["ID"]), " : "), read_attribute(model, class["type"], "name")))
  23. log(" Attributes: " + dict_to_string(class["attributes"]))
  24. states = set_copy(class["states"])
  25. log(" States:")
  26. while (set_len(states) > 0):
  27. state = set_pop(states)
  28. log(string_join(" ", read_attribute(model, state, "name")))
  29. return!
  30. Element function filter(model : Element, set : Element, attribute_name : String, attribute_value : Element):
  31. Element keys
  32. String key
  33. Element result
  34. result = set_create()
  35. while (set_len(set) > 0):
  36. key = set_pop(set)
  37. if (value_eq(read_attribute(model, key, attribute_name), attribute_value)):
  38. set_add(result, key)
  39. return result!
  40. Element function filter_exists(model : Element, set : Element, attribute_name : String):
  41. Element keys
  42. String key
  43. Element result
  44. result = set_create()
  45. while (set_len(set) > 0):
  46. key = set_pop(set)
  47. if (element_neq(read_attribute(model, key, attribute_name), read_root())):
  48. set_add(result, key)
  49. return result!
  50. Element function expand_current_state(model : Element, state : String, data : Element):
  51. // Find the hierarchy of all current states, and select those that contain the currently selected state
  52. Element result
  53. Element current_states
  54. result = set_create()
  55. current_states = set_copy(data["current_class_handle"]["states"])
  56. Element hierarchy
  57. String deep_state
  58. while (set_len(current_states) > 0):
  59. deep_state = set_pop(current_states)
  60. hierarchy = find_hierarchy(model, deep_state, data)
  61. // Got the hierarchy of one of the states
  62. if (list_in(hierarchy, state)):
  63. // This hierarchy contains the root state we are checking for, so add to set
  64. set_add(result, deep_state)
  65. return result!
  66. Element function expand_initial_state(model : Element, state : String, data : Element):
  67. String t
  68. t = read_type(model, state)
  69. if (t == "SCCD/CompositeState"):
  70. // Recurse further in the composite
  71. return expand_composite_state(model, state, data)!
  72. elif (t == "SCCD/ParallelState"):
  73. // Split up all components
  74. return expand_parallel_state(model, state, data)!
  75. elif (t == "SCCD/HistoryState"):
  76. // Reset the history
  77. // This is not really an initial state, but it is called in exactly the same places
  78. return data["current_class_handle"]["history"][get_parent(model, state)]!
  79. else:
  80. // Probably just an atomic, so return this one only
  81. Element result
  82. result = set_create()
  83. set_add(result, state)
  84. return result!
  85. Element function expand_composite_state(model : Element, composite_state : String, data : Element):
  86. // Resolve all initial states from a single composite state
  87. String initial
  88. // Fetch the initial state
  89. initial = set_pop(filter(model, allAssociationDestinations(model, composite_state, "SCCD/composite_children"), "isInitial", True))
  90. // Expand the initial state, depending on what it is
  91. return expand_initial_state(model, initial, data)!
  92. Element function expand_parallel_state(model : Element, parallel_state : String, data : Element):
  93. // Resolve all initial states from a single parallel state
  94. Element children
  95. Element result
  96. Element expanded_children
  97. children = allAssociationDestinations(model, parallel_state, "SCCD/parallel_children")
  98. result = set_create()
  99. while (set_len(children) > 0):
  100. set_merge(result, expand_initial_state(model, set_pop(children), data))
  101. return result!
  102. Void function delete_class(model : Element, data : Element, identifier : String):
  103. // Stop a specific class instance, with attached statechart, from executing
  104. dict_delete(data["classes"], identifier)
  105. Void function start_class(model : Element, data : Element, class : String, identifier : String, parameters : Element):
  106. // Start up the class and assign its initial state to it
  107. // Create the data structure for a running class
  108. Element class_handle
  109. class_handle = dict_create()
  110. dict_add(class_handle, "type", class)
  111. dict_add(class_handle, "ID", identifier)
  112. dict_add(class_handle, "events", set_create())
  113. dict_add(class_handle, "new_events", set_create())
  114. dict_add(class_handle, "timers", dict_create())
  115. dict_add(data["classes"], class_handle["ID"], class_handle)
  116. String prev_class
  117. prev_class = data["current_class"]
  118. dict_overwrite(data, "current_class", identifier)
  119. dict_overwrite(data, "current_class_handle", data["classes"][identifier])
  120. // Add the current state of the class
  121. String initial_state
  122. // Should only be one behaviour linked to it!
  123. initial_state = set_pop(allAssociationDestinations(model, class, "SCCD/behaviour"))
  124. dict_add(class_handle, "states", expand_initial_state(model, initial_state, class_handle))
  125. // Initialize history for all composite states
  126. Element history
  127. Element cstates
  128. String cstate
  129. history = dict_create()
  130. dict_add(class_handle, "history", history)
  131. cstates = allInstances(model, "SCCD/CompositeState")
  132. while (set_len(cstates) > 0):
  133. cstate = set_pop(cstates)
  134. dict_add(history, cstate, expand_initial_state(model, cstate, class_handle))
  135. // Add all attributes
  136. Element attributes
  137. attributes = dict_create()
  138. Element attrs
  139. attrs = allAssociationDestinations(model, class, "SCCD/class_attributes")
  140. while (set_len(attrs) > 0):
  141. dict_add(attributes, read_attribute(model, set_pop(attrs), "name"), read_root())
  142. dict_add(class_handle, "attributes", attributes)
  143. // Invoke constructor
  144. Element constructor
  145. constructor = read_attribute(model, class, "constructor_body")
  146. if (element_neq(constructor, read_root())):
  147. // Constructor, so execute
  148. constructor = resolve_function(constructor, data)
  149. constructor(attributes, parameters)
  150. // Execute all entry actions
  151. Element init
  152. init = set_create()
  153. set_add(init, "")
  154. // Initial state before initialization is the set with an empty hierarchy
  155. // Empty set would not find any difference between the source and target
  156. execute_actions(model, init, set_copy(class_handle["states"]), data, "")
  157. dict_overwrite(data, "current_class", prev_class)
  158. dict_overwrite(data, "current_class_handle", data["classes"][prev_class])
  159. return!
  160. Element function get_enabled_transitions(model : Element, state : String, data : Element):
  161. // Returns all enabled transitions
  162. Element result
  163. Element to_filter
  164. String attr
  165. String transition
  166. Element cond
  167. String evt_name
  168. Element evt
  169. Element events
  170. Element event_names
  171. Element event_parameters
  172. result = set_create()
  173. to_filter = allOutgoingAssociationInstances(model, state, "SCCD/transition")
  174. event_names = set_create()
  175. event_parameters = set_create()
  176. events = set_copy(data["current_class_handle"]["events"])
  177. while (set_len(events) > 0):
  178. evt = set_pop(events)
  179. evt_name = list_read(evt, 0)
  180. if (bool_not(set_in(event_names, evt_name))):
  181. // Not yet registered the event
  182. set_add(event_names, evt_name)
  183. dict_add(event_parameters, evt_name, set_create())
  184. // Add event parameters
  185. set_add_node(event_parameters[evt_name], list_read(evt, 1))
  186. while (set_len(to_filter) > 0):
  187. transition = set_pop(to_filter)
  188. // Check event
  189. attr = read_attribute(model, transition, "event")
  190. if (bool_not(bool_or(element_eq(attr, read_root()), set_in(event_names, attr)))):
  191. // At least one enabled event is found
  192. continue!
  193. // Check after
  194. // Only an after if there was no event!
  195. if (bool_and(element_eq(attr, read_root()), read_attribute(model, transition, "after"))):
  196. if (dict_in(data["current_class_handle"]["timers"], transition)):
  197. // Registered timer already, let's check if it has expired
  198. if (float_gt(data["current_class_handle"]["timers"][transition], data["time_sim"])):
  199. // Not enabled yet
  200. continue!
  201. else:
  202. // Not registered even, so not enabled either
  203. continue!
  204. // Check condition, but depends on whether there was an event or not
  205. cond = read_attribute(model, transition, "cond")
  206. if (element_neq(cond, read_root())):
  207. // Got a condition, so resolve
  208. cond = resolve_function(cond, data)
  209. if (element_neq(attr, read_root())):
  210. // We have an event to take into account!
  211. Element params
  212. Element param
  213. params = set_copy(event_parameters[attr])
  214. while (set_len(params) > 0):
  215. param = set_pop(params)
  216. if (element_neq(cond, read_root())):
  217. // Got a condition to check first
  218. if (bool_not(cond(data["current_class_handle"]["attributes"], param))):
  219. // Condition failed, so skip
  220. continue!
  221. // Fine to add this one with the specified parameters
  222. set_add_node(result, create_tuple(transition, param))
  223. else:
  224. // No event to think about, just add the transition
  225. if (element_neq(cond, read_root())):
  226. // Check the condition first
  227. if (bool_not(cond(data["current_class_handle"]["attributes"], read_root()))):
  228. // Condition false, so skip
  229. continue!
  230. // Fine to add this one without event parameters (no event)
  231. set_add_node(result, create_tuple(transition, read_root()))
  232. return result!
  233. Void function process_raised_event(model : Element, event : Element, parameter_action : Element, data : Element):
  234. String scope
  235. scope = read_attribute(model, event, "scope")
  236. if (scope == "cd"):
  237. // Is an event for us internally, so don't append
  238. // Instead, we process it directly
  239. String operation
  240. operation = read_attribute(model, event, "event")
  241. if (operation == "create_instance"):
  242. // Start up a new class of the desired type
  243. // Parameters of this call:
  244. // class -- type of the class to instantiate
  245. // identifier -- name of this instance, for future reference
  246. // parameters -- parameters for constructor
  247. String class
  248. String identifier
  249. Element parameters
  250. class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "name", list_read(parameter_action, 0)))
  251. identifier = list_read(parameter_action, 1)
  252. parameters = list_read(parameter_action, 2)
  253. start_class(model, data, class, identifier, parameters)
  254. elif (operation == "delete_instance"):
  255. // Delete the requested class
  256. String identifier
  257. identifier = list_read(parameter_action, 0)
  258. delete_class(model, data, identifier)
  259. elif (scope == "broad"):
  260. // Send to all classes
  261. Element classes
  262. classes = dict_keys(data["classes"])
  263. while(set_len(classes) > 0):
  264. set_add_node(data["classes"][set_pop(classes)]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
  265. elif (scope == "narrow"):
  266. // Send to the specified class only
  267. // TODO some error checking would be nice...
  268. set_add_node(data["classes"][read_attribute(model, event, "target")]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
  269. else:
  270. // Same as local
  271. set_add_node(data["current_class_handle"]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
  272. return !
  273. Element function execute_transition(model : Element, data : Element, transition_tuple : Element):
  274. // Execute the script (if any)
  275. Element script
  276. String transition
  277. Element event_parameter
  278. transition = list_read(transition_tuple, 0)
  279. event_parameter = list_read(transition_tuple, 1)
  280. script = read_attribute(model, transition, "script")
  281. if (element_neq(script, read_root())):
  282. script = resolve_function(script, data)
  283. script(data["current_class_handle"]["attributes"], event_parameter)
  284. // Raise events (if any)
  285. Element events
  286. String event
  287. events = allAssociationDestinations(model, transition, "SCCD/transition_raises")
  288. while (set_len(events) > 0):
  289. event = set_pop(events)
  290. Element parameter_action
  291. parameter_action = read_attribute(model, event, "parameter")
  292. if (element_neq(parameter_action, read_root())):
  293. // Got a parameter to evaluate
  294. parameter_action = resolve_function(parameter_action, data)
  295. parameter_action = parameter_action(data["current_class_handle"]["attributes"], event_parameter)
  296. process_raised_event(model, event, parameter_action, data)
  297. // Find new set of states
  298. Element target_states
  299. Element source_states
  300. source_states = expand_current_state(model, readAssociationSource(model, transition), data)
  301. target_states = expand_initial_state(model, readAssociationDestination(model, transition), data)
  302. execute_actions(model, source_states, target_states, data, readAssociationSource(model, transition))
  303. return target_states!
  304. Boolean function step_class(model : Element, data : Element, class : String):
  305. // Find enabled transitions in a class and execute it, updating the state
  306. // Iterate over all current states, searching for enabled transitions
  307. // Search for enabled transitions in higher levels as well!
  308. Element states
  309. Element new_states
  310. String state
  311. Element transitions
  312. String transition
  313. Boolean transitioned
  314. Element hierarchy
  315. String current_state
  316. Boolean found
  317. if (bool_not(dict_in(data["classes"], class))):
  318. // Seems like this class was removed, so stop execution
  319. return False!
  320. // Notify everyone of the current class
  321. dict_overwrite(data, "current_class", class)
  322. dict_overwrite(data, "current_class_handle", data["classes"][class])
  323. states = set_copy(data["current_class_handle"]["states"])
  324. new_states = set_create()
  325. transitioned = False
  326. while (set_len(states) > 0):
  327. state = set_pop(states)
  328. found = False
  329. // Loop over the hierarchy of this state and try to apply transitions
  330. hierarchy = find_hierarchy(model, state, data)
  331. while (list_len(hierarchy) > 0):
  332. current_state = list_pop(hierarchy, 0)
  333. transitions = get_enabled_transitions(model, current_state, data)
  334. if (set_len(transitions) > 0):
  335. // Found an enabled transition, so store that one
  336. transition = random_choice(set_to_list(transitions))
  337. // Execute transition
  338. set_merge(new_states, execute_transition(model, data, transition))
  339. // When leaving an orthogonal component, we must also pop all related states that might be processed in the future!
  340. Element leaving
  341. leaving = expand_current_state(model, current_state, data)
  342. set_difference(states, leaving)
  343. transitioned = True
  344. found = True
  345. break!
  346. if (bool_not(found)):
  347. // Nothing found, so stay in the current state
  348. set_add(new_states, state)
  349. // Update states
  350. dict_overwrite(data["current_class_handle"], "states", new_states)
  351. return transitioned!
  352. String function get_parent(model : Element, state : String):
  353. Element tmp_set
  354. tmp_set = allAssociationOrigins(model, state, "SCCD/composite_children")
  355. set_merge(tmp_set, allAssociationOrigins(model, state, "SCCD/parallel_children"))
  356. if (set_len(tmp_set) > 0):
  357. return set_pop(tmp_set)!
  358. else:
  359. return ""!
  360. Element function find_hierarchy(model : Element, state : String, data : Element):
  361. // Try to cache as much as possible!
  362. if (bool_not(dict_in(data["cache_hierarchy"], state))):
  363. Element result
  364. if (state == ""):
  365. result = list_create()
  366. else:
  367. String parent
  368. parent = get_parent(model, state)
  369. // We have a parent, so take the parent list first
  370. result = find_hierarchy(model, parent, data)
  371. list_append(result, state)
  372. dict_add(data["cache_hierarchy"], state, result)
  373. return dict_copy(data["cache_hierarchy"][state])!
  374. Void function execute_actions(model : Element, source_states : Element, target_states : Element, data : Element, transition_source : String):
  375. Element exit
  376. Element entry
  377. exit = list_create()
  378. entry = list_create()
  379. source_states = set_copy(source_states)
  380. target_states = set_copy(target_states)
  381. // Add all exit and entry actions to the list of actions to execute
  382. // Do this by finding the common parent, and then doing all exit actions up to that node, and all entry actions up to the target_state
  383. // First, find the hierarchy!
  384. Element hierarchy_sources
  385. Element hierarchy_targets
  386. Element all_hierarchies
  387. hierarchy_sources = set_create()
  388. while (set_len(source_states) > 0):
  389. set_add_node(hierarchy_sources, find_hierarchy(model, set_pop(source_states), data))
  390. hierarchy_targets = set_create()
  391. while (set_len(target_states) > 0):
  392. set_add_node(hierarchy_targets, find_hierarchy(model, set_pop(target_states), data))
  393. all_hierarchies = set_copy(hierarchy_sources)
  394. set_merge(all_hierarchies, hierarchy_targets)
  395. // Difference these all lists, finding the first common entry
  396. Element iter_hierarchies
  397. Integer i
  398. String current
  399. Element hierarchy
  400. Boolean finished
  401. Integer transition_depth
  402. Integer lca_depth
  403. lca_depth = 0
  404. finished = False
  405. if (transition_source != ""):
  406. // Find out the level of the transition_source by fetching its hierarchy
  407. transition_depth = list_len(find_hierarchy(model, transition_source, data)) - 1
  408. // Now check for the least common ancestor
  409. while (bool_not(finished)):
  410. // Check the i-th element in both and see if they are equal
  411. current = ""
  412. iter_hierarchies = set_copy(all_hierarchies)
  413. while (set_len(iter_hierarchies) > 0):
  414. hierarchy = set_pop(iter_hierarchies)
  415. // Exhausted one of the lists
  416. if (lca_depth >= list_len(hierarchy)):
  417. finished = True
  418. break!
  419. // Reached the same level as transition depth already, so no need to increase
  420. if (lca_depth == transition_depth):
  421. finished = True
  422. break!
  423. // First entry, so read out value as reference
  424. if (current == ""):
  425. current = list_read(hierarchy, lca_depth)
  426. // Check with reference element
  427. if (bool_not(value_eq(list_read(hierarchy, lca_depth), current))):
  428. finished = True
  429. break!
  430. // i-th element equal for all hierarchies, so go to next element
  431. if (bool_not(finished)):
  432. lca_depth = lca_depth + 1
  433. if (lca_depth < transition_depth):
  434. i = lca_depth
  435. else:
  436. i = transition_depth
  437. else:
  438. // Initial, so just set i to zero
  439. i = 0
  440. // Found the first differing element at position i
  441. // All elements remaining in hierarchy_source are to be traversed in REVERSE order for the exit actions
  442. // All elements remaining in hierarchy_target are to be traversed in NORMAL order for the entry actions
  443. // This is not that simple either, as we need to consider that some actions might already have been added to the list...
  444. // Add hierarchy_sources actions
  445. String state
  446. Element visited
  447. Element action
  448. Element spliced_hierarchy
  449. Element hierarchy_source
  450. Element hierarchy_target
  451. visited = set_create()
  452. while (set_len(hierarchy_sources) > 0):
  453. // Get one of these hierarchies
  454. hierarchy_source = set_pop(hierarchy_sources)
  455. spliced_hierarchy = list_splice(hierarchy_source, i, list_len(hierarchy_source))
  456. while (list_len(spliced_hierarchy) > 0):
  457. state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
  458. if (set_in(visited, state)):
  459. // Already added this state, so don't bother
  460. continue!
  461. else:
  462. // New state, so prepend it to the list
  463. // Prepend, instead of append, as we want to do these operations in reverse order!
  464. list_insert(exit, state, 0)
  465. // Add this state as visited
  466. set_add(visited, state)
  467. // Add hierarchy_targets actions
  468. // Clear visited, just to be safe, though it should not matter
  469. visited = set_create()
  470. while (set_len(hierarchy_targets) > 0):
  471. // Get one of these hierarchies
  472. hierarchy_target = set_pop(hierarchy_targets)
  473. spliced_hierarchy = list_splice(hierarchy_target, i, list_len(hierarchy_target))
  474. while (list_len(spliced_hierarchy) > 0):
  475. state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
  476. if (set_in(visited, state)):
  477. // Already added this state, so don't bother
  478. continue!
  479. else:
  480. // New state, so append it to the list
  481. // Append, instead of prepend, as we want to do these operations in normal order!
  482. list_append(entry, state)
  483. // Add this state as visited, even though there might not have been an associated action
  484. set_add(visited, state)
  485. // Now we have a list of traversed states!
  486. // Start executing all their operations in order
  487. Element events
  488. String event
  489. // First do exit actions
  490. while (list_len(exit) > 0):
  491. state = list_pop(exit, 0)
  492. // Set history when leaving
  493. if (read_type(model, state) == "SCCD/CompositeState"):
  494. dict_overwrite(data["current_class_handle"]["history"], state, expand_current_state(model, state, data))
  495. // Do exit actions
  496. action = read_attribute(model, state, "onExitScript")
  497. if (element_neq(action, read_root())):
  498. // Got a script, so execute!
  499. action = resolve_function(action, data)
  500. action(data["current_class_handle"]["attributes"])
  501. // Raise events
  502. events = allAssociationDestinations(model, state, "SCCD/onExitRaise")
  503. while (set_len(events) > 0):
  504. event = set_pop(events)
  505. Element parameter_action
  506. parameter_action = read_attribute(model, event, "parameter")
  507. if (element_neq(parameter_action, read_root())):
  508. // Got a parameter to evaluate
  509. parameter_action = resolve_function(parameter_action, data)
  510. parameter_action = parameter_action(data["current_class_handle"]["attributes"])
  511. process_raised_event(model, event, parameter_action, data)
  512. // Unschedule after events
  513. Element timed_transitions
  514. timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
  515. while (set_len(timed_transitions) > 0):
  516. dict_delete(data["current_class_handle"]["timers"], set_pop(timed_transitions))
  517. // Then do entry actions
  518. while (list_len(entry) > 0):
  519. state = list_pop(entry, 0)
  520. // Do entry actions
  521. action = read_attribute(model, state, "onEntryScript")
  522. if (element_neq(action, read_root())):
  523. // Got a script, so execute!
  524. action = resolve_function(action, data)
  525. action(data["current_class_handle"]["attributes"])
  526. // Raise events
  527. events = allAssociationDestinations(model, state, "SCCD/onEntryRaise")
  528. while (set_len(events) > 0):
  529. event = set_pop(events)
  530. Element parameter_action
  531. parameter_action = read_attribute(model, event, "parameter")
  532. if (element_neq(parameter_action, read_root())):
  533. // Got a parameter to evaluate
  534. parameter_action = resolve_function(parameter_action, data)
  535. parameter_action = parameter_action(data["current_class_handle"]["attributes"])
  536. process_raised_event(model, event, parameter_action, data)
  537. // Schedule after events
  538. Element timed_transitions
  539. String transition
  540. Element after
  541. timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
  542. while (set_len(timed_transitions) > 0):
  543. transition = set_pop(timed_transitions)
  544. after = resolve_function(read_attribute(model, transition, "after"), data)
  545. dict_add(data["current_class_handle"]["timers"], transition, float_addition(data["time_sim"], after(data["current_class_handle"]["attributes"])))
  546. return !
  547. Float function step(model : Element, data : Element):
  548. // Step through all classes
  549. Element classes
  550. Element class
  551. Float t_min
  552. Float t_current
  553. Boolean transitioned
  554. Element keys
  555. String key
  556. t_min = 999999.0
  557. classes = dict_keys(data["classes"])
  558. transitioned = False
  559. while (set_len(classes) > 0):
  560. class = set_pop(classes)
  561. if (step_class(model, data, class)):
  562. transitioned = True
  563. if (bool_not(transitioned)):
  564. // Find minimum timer for this class, and store that
  565. keys = dict_keys(data["classes"][class]["timers"])
  566. while (set_len(keys) > 0):
  567. key = set_pop(keys)
  568. t_current = data["classes"][class]["timers"][key]
  569. if (t_current < t_min):
  570. t_min = t_current
  571. if (transitioned):
  572. // Do another step, as we can transition
  573. return data["time_sim"]!
  574. else:
  575. return t_min!
  576. Boolean function main(model : Element):
  577. // Executes the provided SCCD model
  578. Element data
  579. data = dict_create()
  580. dict_add(data, "classes", dict_create())
  581. dict_add(data, "cache_operations", dict_create())
  582. dict_add(data, "cache_hierarchy", dict_create())
  583. dict_add(data, "current_class", "")
  584. Float time_0
  585. Float time_sim
  586. Float time_wallclock
  587. time_0 = time()
  588. time_sim = 0.0
  589. dict_add(data, "time_sim", 0.0)
  590. // Prepare for input
  591. output("Ready for input!")
  592. // Find initial
  593. String default_class
  594. default_class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "default", True))
  595. // Start up the default class
  596. start_class(model, data, default_class, "main", read_root())
  597. Float timeout
  598. Element interrupt
  599. timeout = 0.0
  600. while (True):
  601. interrupt = input_timeout(timeout)
  602. if (value_eq(interrupt, "#EXIT#")):
  603. // Stop execution
  604. return True!
  605. if (element_neq(interrupt, read_root())):
  606. // Send out, as otherwise the client doesn't get a dialog
  607. output("Processed event, ready for more!")
  608. // Update the simulated time to the time of interrupt
  609. time_sim = time() - time_0
  610. dict_overwrite(data, "new_events", set_create())
  611. Element classes
  612. classes = dict_keys(data["classes"])
  613. while(set_len(classes) > 0):
  614. String class
  615. class = set_pop(classes)
  616. dict_overwrite(data["classes"][class], "events", data["classes"][class]["new_events"])
  617. dict_overwrite(data["classes"][class], "new_events", set_create())
  618. if (element_neq(interrupt, read_root())):
  619. // Got interrupt, so append it already
  620. set_add_node(data["classes"][class]["events"], create_tuple(interrupt, read_root()))
  621. // Else we timeout, and thus keep the time_sim
  622. dict_overwrite(data, "time_sim", time_sim)
  623. time_sim = step(model, data)
  624. if (float_gt(time_sim, data["time_sim"])):
  625. print_states(model, data)
  626. if (dict_len(data["classes"]) == 0):
  627. // No more active classes left: terminate!
  628. log("Finished SCCD execution")
  629. break!
  630. time_wallclock = time() - time_0
  631. timeout = time_sim - time_wallclock
  632. log("Pause for: " + cast_v2s(timeout))
  633. // We should never get here!
  634. return False!