|
@@ -52,7 +52,39 @@ Element function filter_exists(model : Element, set : Element, attribute_name :
|
|
|
|
|
|
return result!
|
|
|
|
|
|
-Element function expand_state(model : Element, state : String):
|
|
|
+Element function filter_resolve_exists(model : Element, set : Element, attribute_name : String):
|
|
|
+ Element keys
|
|
|
+ String key
|
|
|
+ Element result
|
|
|
+
|
|
|
+ result = create_node()
|
|
|
+ while (read_nr_out(set) > 0):
|
|
|
+ key = set_pop(set)
|
|
|
+ if (element_neq(read_attribute(model, key, attribute_name), read_root())):
|
|
|
+ set_add(result, read_attribute(model, key, attribute_name))
|
|
|
+
|
|
|
+ return result!
|
|
|
+
|
|
|
+Element function expand_current_state(model : Element, state : String, current_states : Element):
|
|
|
+ // Find the hierarchy of all current states, and select those that contain the currently selected state
|
|
|
+ Element result
|
|
|
+ result = create_node()
|
|
|
+ current_states = set_copy(current_states)
|
|
|
+
|
|
|
+ Element hierarchy
|
|
|
+ String deep_state
|
|
|
+ while (read_nr_out(current_states) > 0):
|
|
|
+ deep_state = set_pop(current_states)
|
|
|
+ hierarchy = find_hierarchy(model, deep_state)
|
|
|
+ // Got the hierarchy of one of the states
|
|
|
+
|
|
|
+ if (set_in(hierarchy, state)):
|
|
|
+ // This hierarchy contains the root state we are checking for, so add to set
|
|
|
+ set_add(result, deep_state)
|
|
|
+
|
|
|
+ return result!
|
|
|
+
|
|
|
+Element function expand_initial_state(model : Element, state : String):
|
|
|
String t
|
|
|
t = read_type(model, state)
|
|
|
if (t == "SCCD/CompositeState"):
|
|
@@ -76,11 +108,11 @@ Element function expand_composite_state(model : Element, composite_state : Strin
|
|
|
initial = set_pop(filter(model, allAssociationDestinations(model, composite_state, "SCCD/composite_children"), "isInitial", True))
|
|
|
|
|
|
// Expand the initial state, depending on what it is
|
|
|
- return expand_state(model, initial)!
|
|
|
+ return expand_initial_state(model, initial)!
|
|
|
|
|
|
Element function expand_parallel_state(model : Element, parallel_state : String):
|
|
|
// Resolve all initial states from a single parallel state
|
|
|
- Element children
|
|
|
+ Element children
|
|
|
Element result
|
|
|
Element expanded_children
|
|
|
|
|
@@ -88,7 +120,7 @@ Element function expand_parallel_state(model : Element, parallel_state : String)
|
|
|
result = create_node()
|
|
|
|
|
|
while (read_nr_out(children) > 0):
|
|
|
- set_merge(result, expand_state(model, set_pop(children)))
|
|
|
+ set_merge(result, expand_initial_state(model, set_pop(children)))
|
|
|
|
|
|
return result!
|
|
|
|
|
@@ -106,7 +138,7 @@ Void function start_class(model : Element, data : Element, class : String):
|
|
|
String initial_state
|
|
|
// Should only be one behaviour linked to it!
|
|
|
initial_state = set_pop(allAssociationDestinations(model, class, "SCCD/behaviour"))
|
|
|
- dict_add(class_handle, "states", expand_state(model, initial_state))
|
|
|
+ dict_add(class_handle, "states", expand_initial_state(model, initial_state))
|
|
|
|
|
|
// Add all attributes
|
|
|
Element attributes
|
|
@@ -183,8 +215,22 @@ Element function execute_transition(model : Element, data : Element, class : Str
|
|
|
event = set_pop(events)
|
|
|
set_add(data["events"], read_attribute(model, event, "event"))
|
|
|
|
|
|
- // Return new set of states
|
|
|
- return expand_state(model, readAssociationDestination(model, transition))!
|
|
|
+ // Find new set of states
|
|
|
+ Element target_states
|
|
|
+ Element source_states
|
|
|
+ source_states = expand_current_state(model, readAssociationSource(model, transition), data["classes"][class]["states"])
|
|
|
+ target_states = expand_initial_state(model, readAssociationDestination(model, transition))
|
|
|
+
|
|
|
+ // Do all required operations
|
|
|
+ Element actions
|
|
|
+ actions = get_actions_to_execute(model, source_states, target_states)
|
|
|
+ while (read_nr_out(actions) > 0):
|
|
|
+ Element action
|
|
|
+ action = list_pop(actions, 0)
|
|
|
+ action = get_func_AL_model(import_node(action))
|
|
|
+ action(data["attributes"])
|
|
|
+
|
|
|
+ return target_states!
|
|
|
|
|
|
Boolean function step_class(model : Element, data : Element, class : String):
|
|
|
// Find enabled transitions in a class and execute it, updating the state
|
|
@@ -241,7 +287,7 @@ Void function reschedule_timeouts(model : Element, data : Element, class : Strin
|
|
|
state = set_pop(states)
|
|
|
|
|
|
// NOTE this set_merge does not eliminate duplicates, though this should happen later on when adding the timer (see other NOTE)
|
|
|
- timed_transitions = set_merge(timed_transitions, filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after"))
|
|
|
+ set_merge(timed_transitions, filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after"))
|
|
|
|
|
|
// Remove timers that no longer exist
|
|
|
old_timed_transitions = dict_keys(data["classes"][class]["timers"])
|
|
@@ -270,6 +316,148 @@ Void function reschedule_timeouts(model : Element, data : Element, class : Strin
|
|
|
|
|
|
return !
|
|
|
|
|
|
+String function get_parent(model : Element, state : String):
|
|
|
+ Element tmp_set
|
|
|
+ tmp_set = allAssociationOrigins(model, state, "composite_children")
|
|
|
+ set_merge(tmp_set, allAssociationOrigins(model, state, "parallel_children"))
|
|
|
+ if (read_nr_out(tmp_set) > 0):
|
|
|
+ return set_pop(tmp_set)!
|
|
|
+ else:
|
|
|
+ return ""!
|
|
|
+
|
|
|
+Element function find_hierarchy(model : Element, state : String):
|
|
|
+ Element result
|
|
|
+ String parent
|
|
|
+
|
|
|
+ parent = get_parent(model, state)
|
|
|
+ if (parent == ""):
|
|
|
+ // Are at the topmost element, so empty hierarchy for us
|
|
|
+ result = create_node()
|
|
|
+ else:
|
|
|
+ // We have a parent, so take the parent list first
|
|
|
+ result = find_hierarchy(model, parent)
|
|
|
+
|
|
|
+ // Now append ourself
|
|
|
+ list_append(result, state)
|
|
|
+ return result!
|
|
|
+
|
|
|
+Element function get_actions_to_execute(model : Element, source_states : Element, target_states : Element):
|
|
|
+ Element result
|
|
|
+ result = create_node()
|
|
|
+
|
|
|
+ source_states = set_copy(source_states)
|
|
|
+ target_states = set_copy(target_states)
|
|
|
+
|
|
|
+ // Add all exit and entry actions to the list of actions to execute
|
|
|
+ // 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
|
|
|
+
|
|
|
+ // First, find the hierarchy!
|
|
|
+ Element hierarchy_sources
|
|
|
+ Element hierarchy_targets
|
|
|
+ Element all_hierarchies
|
|
|
+
|
|
|
+ hierarchy_sources = create_node()
|
|
|
+ while (read_nr_out(source_states) > 0):
|
|
|
+ set_add(hierarchy_sources, find_hierarchy(model, set_pop(source_states)))
|
|
|
+
|
|
|
+ hierarchy_targets = create_node()
|
|
|
+ while (read_nr_out(target_states) > 0):
|
|
|
+ set_add(hierarchy_targets, find_hierarchy(model, set_pop(target_states)))
|
|
|
+
|
|
|
+ all_hierarchies = set_copy(hierarchy_sources)
|
|
|
+ set_merge(all_hierarchies, hierarchy_targets)
|
|
|
+
|
|
|
+ // Difference these all lists, finding the first common entry
|
|
|
+ Element iter_hierarchies
|
|
|
+ Integer i
|
|
|
+ String current
|
|
|
+ Element hierarchy
|
|
|
+ i = 0
|
|
|
+ while (True):
|
|
|
+ // Check the i-th element in both and see if they are equal
|
|
|
+ current = ""
|
|
|
+ iter_hierarchies = set_copy(all_hierarchies)
|
|
|
+ while (read_nr_out(iter_hierarchies) > 0):
|
|
|
+ hierarchy = set_pop(iter_hierarchies)
|
|
|
+
|
|
|
+ // Exhausted one of the lists
|
|
|
+ if (i == list_len(hierarchy)):
|
|
|
+ break!
|
|
|
+
|
|
|
+ // First entry, so read out value as reference
|
|
|
+ if (current == ""):
|
|
|
+ current = list_read(hierarchy, i)
|
|
|
+
|
|
|
+ // Check with reference element
|
|
|
+ if (bool_not(value_eq(list_read(hierarchy, i), current))):
|
|
|
+ break!
|
|
|
+
|
|
|
+ // i-th element equal for all hierarchies, so go to next element
|
|
|
+ i = i + 1
|
|
|
+
|
|
|
+ // Found the first differing element at position i
|
|
|
+
|
|
|
+ // All elements remaining in hierarchy_source are to be traversed in REVERSE order for the exit actions
|
|
|
+ // All elements remaining in hierarchy_target are to be traversed in NORMAL order for the entry actions
|
|
|
+ // This is not that simple either, as we need to consider that some actions might already have been added to the list...
|
|
|
+
|
|
|
+ // Add hierarchy_sources actions
|
|
|
+ String state
|
|
|
+ Element visited
|
|
|
+ Element action
|
|
|
+ Element spliced_hierarchy
|
|
|
+ Element hierarchy_source
|
|
|
+ Element hierarchy_target
|
|
|
+ visited = create_node()
|
|
|
+ while (read_nr_out(hierarchy_sources) > 0):
|
|
|
+ // Get one of these hierarchies
|
|
|
+ hierarchy_source = set_pop(hierarchy_sources)
|
|
|
+ spliced_hierarchy = list_splice(hierarchy_source, i, list_len(hierarchy_source))
|
|
|
+ while (list_len(spliced_hierarchy) > 0):
|
|
|
+ state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
|
|
|
+ if (set_in(visited, state)):
|
|
|
+ // Already added this state, so don't bother
|
|
|
+ continue!
|
|
|
+ else:
|
|
|
+ // New state, so prepend it to the list
|
|
|
+ // Prepend, instead of append, as we want to do these operations in reverse order!
|
|
|
+
|
|
|
+ // First check if there is any exit action at all
|
|
|
+ action = read_attribute(model, state, "exit_action")
|
|
|
+ if (element_neq(action, read_root())):
|
|
|
+ // An exit action is found!
|
|
|
+ list_insert(result, 0, get_func_AL_model(import_node(action)))
|
|
|
+
|
|
|
+ // Add this state as visited, even though there might not have been an associated action
|
|
|
+ set_add(visited, state)
|
|
|
+
|
|
|
+ // Add hierarchy_targets actions
|
|
|
+ // Clear visited, just to be safe, though it should not matter
|
|
|
+ visited = create_node()
|
|
|
+ while (read_nr_out(hierarchy_targets) > 0):
|
|
|
+ // Get one of these hierarchies
|
|
|
+ hierarchy_target = set_pop(hierarchy_targets)
|
|
|
+ spliced_hierarchy = list_splice(hierarchy_target, i, list_len(hierarchy_target))
|
|
|
+ while (list_len(spliced_hierarchy) > 0):
|
|
|
+ state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
|
|
|
+ if (set_in(visited, state)):
|
|
|
+ // Already added this state, so don't bother
|
|
|
+ continue!
|
|
|
+ else:
|
|
|
+ // New state, so append it to the list
|
|
|
+ // Append, instead of prepend, as we want to do these operations in normal order!
|
|
|
+
|
|
|
+ // First check if there is any entry action at all
|
|
|
+ action = read_attribute(model, state, "entry_action")
|
|
|
+ if (element_neq(action, read_root())):
|
|
|
+ // An entry action is found!
|
|
|
+ list_append(result, get_func_AL_model(import_node(action)))
|
|
|
+
|
|
|
+ // Add this state as visited, even though there might not have been an associated action
|
|
|
+ set_add(visited, state)
|
|
|
+
|
|
|
+ return result!
|
|
|
+
|
|
|
Float function step(model : Element, data : Element):
|
|
|
// Step through all classes
|
|
|
Element classes
|