SCCD_execute.alc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. Void function print_states(model : Element, data : Element):
  8. Element classes
  9. Element states
  10. Element class
  11. String state
  12. log("Current states:")
  13. classes = set_copy(data["classes"])
  14. while (read_nr_out(classes) > 0):
  15. class = set_pop(classes)
  16. log(string_join(string_join(string_join(" ", class["ID"]), " : "), read_attribute(model, class["type"], "name")))
  17. log(" Attributes: " + dict_to_string(class["attributes"]))
  18. states = set_copy(class["states"])
  19. log(" States:")
  20. while (read_nr_out(states) > 0):
  21. state = set_pop(states)
  22. log(string_join(" ", read_attribute(model, state, "name")))
  23. return!
  24. Element function filter(model : Element, set : Element, attribute_name : String, attribute_value : Element):
  25. Element keys
  26. String key
  27. Element result
  28. result = create_node()
  29. while (read_nr_out(set) > 0):
  30. key = set_pop(set)
  31. if (value_eq(read_attribute(model, key, attribute_name), attribute_value)):
  32. set_add(result, key)
  33. return result!
  34. Element function expand_state(model : Element, state : String):
  35. String t
  36. t = read_type(model, state)
  37. if (t == "SCCD/CompositeState"):
  38. // Recurse further in the composite
  39. return expand_composite_state(model, state)!
  40. elif (t == "SCCD/ParallelState"):
  41. // Split up all components
  42. return expand_parallel_state(model, state)!
  43. else:
  44. // Probably just an atomic, so return this one only
  45. Element result
  46. result = create_node()
  47. set_add(result, state)
  48. return result!
  49. Element function expand_composite_state(model : Element, composite_state : String):
  50. // Resolve all initial states from a single composite state
  51. String initial
  52. // Fetch the initial state
  53. initial = set_pop(filter(model, allAssociationDestinations(model, composite_state, "SCCD/composite_children"), "isInitial", True))
  54. // Expand the initial state, depending on what it is
  55. return expand_state(model, initial)!
  56. Element function expand_parallel_state(model : Element, parallel_state : String):
  57. // Resolve all initial states from a single parallel state
  58. Element children
  59. Element result
  60. Element expanded_children
  61. children = allAssociationDestinations(model, parallel_state, "SCCD/parallel_children")
  62. result = create_node()
  63. while (read_nr_out(children) > 0):
  64. set_merge(result, expand_state(model, set_pop(children)))
  65. return result!
  66. Void function start_class(model : Element, data : Element, class : String):
  67. // Start up the class and assign its initial state to it
  68. // Create the data structure for a running class
  69. Element class_handle
  70. class_handle = create_node()
  71. dict_add(class_handle, "type", class)
  72. dict_add(class_handle, "ID", cast_id2s(create_node()))
  73. // Add the current state of the class
  74. String initial_state
  75. // Should only be one behaviour linked to it!
  76. initial_state = set_pop(allAssociationDestinations(model, class, "SCCD/behaviour"))
  77. dict_add(class_handle, "states", expand_state(model, initial_state))
  78. // Add all attributes
  79. Element attributes
  80. attributes = create_node()
  81. Element attrs
  82. attrs = allAssociationDestinations(model, class, "SCCD/class_attributes")
  83. while (read_nr_out(attrs) > 0):
  84. dict_add(attributes, read_attribute(model, set_pop(attrs), "name"), read_root())
  85. dict_add(class_handle, "attributes", attributes)
  86. dict_add(data["classes"], class_handle["ID"], class_handle)
  87. return!
  88. Element function get_enabled_transitions(model : Element, state : String, data : Element, class : String):
  89. // Returns all enabled transitions
  90. // TODO ignore conditions and afters
  91. Element result
  92. Element to_filter
  93. String attr
  94. String transition
  95. Element cond
  96. result = create_node()
  97. to_filter = allOutgoingAssociationInstances(model, state, "SCCD/transition")
  98. while (read_nr_out(to_filter) > 0):
  99. transition = set_pop(to_filter)
  100. attr = read_attribute(model, transition, "event")
  101. if (bool_or(element_eq(attr, read_root()), set_in(data["events"], attr))):
  102. // Event is OK
  103. cond = read_attribute(model, transition, "cond")
  104. if (element_neq(cond, read_root())):
  105. cond = get_func_AL_model(import_node(cond))
  106. // Execute condition
  107. if (bool_not(cond(data["classes"][class]["attributes"]))):
  108. // Condition false, so skip
  109. continue!
  110. // Condition is OK
  111. set_add(result, transition)
  112. return result!
  113. Element function execute_transition(model : Element, data : Element, class : String, transition : String):
  114. // Execute the script (if any)
  115. Element script
  116. script = read_attribute(model, transition, "script")
  117. if (element_neq(script, read_root())):
  118. script = get_func_AL_model(import_node(script))
  119. script(data["classes"][class]["attributes"])
  120. // Raise events (if any)
  121. Element events
  122. events = allAssociationDestinations(model, transition, "SCCD/transition_raises")
  123. while (read_nr_out(events) > 0):
  124. event = set_pop(events)
  125. set_add(data["events"], read_attribute(model, event, "event"))
  126. // Return new set of states
  127. return expand_state(model, readAssociationDestination(model, transition))!
  128. Float function step_class(model : Element, data : Element, class : String):
  129. // Find enabled transitions in a class and execute it, updating the state
  130. // Iterate over all current states, searching for enabled transitions
  131. // Search for enabled transitions in higher levels as well!
  132. Element states
  133. Element new_states
  134. String state
  135. Element transitions
  136. String transition
  137. Float t_min
  138. Float t_current
  139. states = set_copy(data["classes"][class]["states"])
  140. new_states = create_node()
  141. while (read_nr_out(states) > 0):
  142. state = set_pop(states)
  143. // Fetch transitions in this state specifically (NO parent)
  144. transitions = get_enabled_transitions(model, state, data, class)
  145. if (read_nr_out(transitions) != 0):
  146. // Found an enabled transition, so store that one
  147. transition = random_choice(transitions)
  148. // Execute transition
  149. set_merge(new_states, execute_transition(model, data, class, transition))
  150. else:
  151. // Try going to the parent
  152. // TODO
  153. // Nothing found, so stay in the current state
  154. set_add(new_states, state)
  155. // Update states
  156. dict_overwrite(data["classes"][class], "states", new_states)
  157. return 1.0!
  158. Float function step(model : Element, data : Element):
  159. // Step through all classes
  160. Element classes
  161. Element class
  162. Float t_min
  163. Float t_class
  164. t_min = 1.0
  165. classes = dict_keys(data["classes"])
  166. while (read_nr_out(classes) > 0):
  167. class = set_pop(classes)
  168. t_class = step_class(model, data, class)
  169. if (t_class < t_min):
  170. t_min = t_class
  171. return t_min!
  172. Boolean function main(model : Element):
  173. // Executes the provided SCCD model
  174. Element data
  175. data = create_node()
  176. dict_add(data, "classes", create_node())
  177. // Prepare for input
  178. output("Ready for input!")
  179. // Find initial
  180. String default_class
  181. default_class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "default", True))
  182. // Start up the default class
  183. start_class(model, data, default_class)
  184. Float timeout
  185. Element interrupt
  186. timeout = 0.0
  187. while (True):
  188. print_states(model, data)
  189. interrupt = input_timeout(timeout)
  190. if (value_eq(interrupt, "#EXIT#")):
  191. // Stop execution
  192. return True!
  193. dict_overwrite(data, "events", create_node())
  194. if (element_neq(interrupt, read_root())):
  195. // Got interrupt
  196. log("Got event: " + cast_v2s(interrupt))
  197. set_add(data["events"], interrupt)
  198. output("Processed event, ready for more!")
  199. timeout = step(model, data)
  200. // We should never get here!
  201. return False!