123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811 |
- include "primitives.alh"
- include "modelling.alh"
- include "object_operations.alh"
- include "utils.alh"
- include "random.alh"
- include "library.alh"
- include "io.alh"
- Boolean afap = False
- Element function resolve_function(location : String, data : Element):
- if (bool_not(dict_in(data["cache_operations"], location))):
- dict_add(data["cache_operations"], location, get_func_AL_model(import_node(location)))
- return data["cache_operations"][location]!
- Void function print_states(model : Element, data : Element):
- Element classes
- Element states
- Element class
- String state
- log("Current states:")
- classes = dict_keys(data["classes"])
- while (set_len(classes) > 0):
- class = set_pop(classes)
- class = data["classes"][class]
- log(string_join(string_join(string_join(" ", class["ID"]), " : "), read_attribute(model, class["type"], "name")))
- log(" Attributes: " + dict_to_string(class["attributes"]))
- states = set_copy(class["states"])
- log(" States:")
- while (set_len(states) > 0):
- state = set_pop(states)
- log(string_join(" ", read_attribute(model, state, "name")))
- return!
- Element function filter(model : Element, set : Element, attribute_name : String, attribute_value : Element):
- Element keys
- String key
- Element result
- result = set_create()
- while (set_len(set) > 0):
- key = set_pop(set)
- if (value_eq(read_attribute(model, key, attribute_name), attribute_value)):
- set_add(result, key)
- return result!
- Element function filter_exists(model : Element, set : Element, attribute_name : String):
- Element keys
- String key
- Element result
- result = set_create()
- while (set_len(set) > 0):
- key = set_pop(set)
- if (element_neq(read_attribute(model, key, attribute_name), read_root())):
- set_add(result, key)
- return result!
- Element function expand_current_state(model : Element, state : String, data : Element):
- // Find the hierarchy of all current states, and select those that contain the currently selected state
- Element result
- Element current_states
- result = set_create()
- current_states = set_copy(data["current_class_handle"]["states"])
- Element hierarchy
- String deep_state
- while (set_len(current_states) > 0):
- deep_state = set_pop(current_states)
- hierarchy = find_hierarchy(model, deep_state, data)
- // Got the hierarchy of one of the states
- if (list_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, data : Element):
- String t
- t = read_type(model, state)
- if (t == "SCCD/CompositeState"):
- // Recurse further in the composite
- return expand_composite_state(model, state, data)!
- elif (t == "SCCD/ParallelState"):
- // Split up all components
- return expand_parallel_state(model, state, data)!
- elif (t == "SCCD/HistoryState"):
- // Reset the history
- // This is not really an initial state, but it is called in exactly the same places
- return data["current_class_handle"]["history"][get_parent(model, state)]!
- else:
- // Probably just an atomic, so return this one only
- Element result
- result = set_create()
- set_add(result, state)
- return result!
- Element function expand_composite_state(model : Element, composite_state : String, data : Element):
- // Resolve all initial states from a single composite state
- String initial
- // Fetch the initial state
- 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_initial_state(model, initial, data)!
- Element function expand_parallel_state(model : Element, parallel_state : String, data : Element):
- // Resolve all initial states from a single parallel state
- Element children
- Element result
- Element expanded_children
- children = allAssociationDestinations(model, parallel_state, "SCCD/parallel_children")
- result = set_create()
- while (set_len(children) > 0):
- set_merge(result, expand_initial_state(model, set_pop(children), data))
- return result!
- Void function delete_class(model : Element, data : Element, identifier : String):
- // Stop a specific class instance, with attached statechart, from executing
- dict_delete(data["classes"], identifier)
- String function start_class(model : Element, data : Element, class : String, parameters : Element):
- // Start up the class and assign its initial state to it
- // First find an empty identifier
- String identifier
- identifier = cast_string(dict_len(data["classes"]))
- // Create the data structure for a running class
- Element class_handle
- class_handle = dict_create()
- dict_add(class_handle, "type", class)
- dict_add(class_handle, "ID", identifier)
- dict_add(class_handle, "events", set_create())
- dict_add(class_handle, "new_events", set_create())
- dict_add(class_handle, "timers", dict_create())
- dict_add(data["classes"], class_handle["ID"], class_handle)
- String prev_class
- prev_class = data["current_class"]
- dict_overwrite(data, "current_class", identifier)
- dict_overwrite(data, "current_class_handle", data["classes"][identifier])
- // Add the current state of the class
- 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_initial_state(model, initial_state, class_handle))
- // Initialize history for all composite states
- Element history
- Element cstates
- String cstate
- history = dict_create()
- dict_add(class_handle, "history", history)
- cstates = allInstances(model, "SCCD/CompositeState")
- while (set_len(cstates) > 0):
- cstate = set_pop(cstates)
- dict_add(history, cstate, expand_initial_state(model, cstate, class_handle))
- // Add all attributes
- Element attributes
- attributes = dict_create()
- Element attrs
- attrs = allAssociationDestinations(model, class, "SCCD/class_attributes")
- while (set_len(attrs) > 0):
- dict_add(attributes, read_attribute(model, set_pop(attrs), "name"), read_root())
- dict_add(class_handle, "attributes", attributes)
- // Invoke constructor
- Element constructor
- constructor = read_attribute(model, class, "constructor_body")
- if (element_neq(constructor, read_root())):
- // Constructor, so execute
- constructor = resolve_function(constructor, data)
- constructor(attributes, parameters)
- // Execute all entry actions
- Element init
- init = set_create()
- set_add(init, "")
- // Initial state before initialization is the set with an empty hierarchy
- // Empty set would not find any difference between the source and target
- execute_actions(model, init, set_copy(class_handle["states"]), data, "")
- dict_overwrite(data, "current_class", prev_class)
- dict_overwrite(data, "current_class_handle", data["classes"][prev_class])
- return identifier!
- Element function get_enabled_transitions(model : Element, state : String, data : Element):
- // Returns all enabled transitions
- Element result
- Element to_filter
- String attr
- String transition
- Element cond
- String evt_name
- Element evt
- Element events
- Element event_names
- Element event_parameters
- result = set_create()
- to_filter = allOutgoingAssociationInstances(model, state, "SCCD/transition")
- event_names = set_create()
- event_parameters = set_create()
- events = set_copy(data["current_class_handle"]["events"])
- while (set_len(events) > 0):
- evt = set_pop(events)
- evt_name = list_read(evt, 0)
- if (bool_not(set_in(event_names, evt_name))):
- // Not yet registered the event
- set_add(event_names, evt_name)
- dict_add(event_parameters, evt_name, set_create())
- // Add event parameters
- set_add_node(event_parameters[evt_name], list_read(evt, 1))
- while (set_len(to_filter) > 0):
- transition = set_pop(to_filter)
- // Check event
- attr = read_attribute(model, transition, "event")
- if (bool_not(bool_or(element_eq(attr, read_root()), set_in(event_names, attr)))):
- // At least one enabled event is found
- continue!
- // Check after
- // Only an after if there was no event!
- if (bool_and(element_eq(attr, read_root()), read_attribute(model, transition, "after"))):
- if (dict_in(data["current_class_handle"]["timers"], transition)):
- // Registered timer already, let's check if it has expired
- if (float_gt(data["current_class_handle"]["timers"][transition], data["time_sim"])):
- // Not enabled yet
- continue!
- else:
- // Not registered even, so not enabled either
- continue!
- // Check condition, but depends on whether there was an event or not
- cond = read_attribute(model, transition, "cond")
- if (element_neq(cond, read_root())):
- // Got a condition, so resolve
- cond = resolve_function(cond, data)
- if (element_neq(attr, read_root())):
- // We have an event to take into account!
- Element params
- Element param
- params = set_copy(event_parameters[attr])
- while (set_len(params) > 0):
- param = set_pop(params)
- if (element_neq(cond, read_root())):
- // Got a condition to check first
- if (bool_not(cond(data["current_class_handle"]["attributes"], param))):
- // Condition failed, so skip
- continue!
- // Fine to add this one with the specified parameters
- set_add_node(result, create_tuple(transition, param))
- else:
- // No event to think about, just add the transition
- if (element_neq(cond, read_root())):
- // Check the condition first
- if (bool_not(cond(data["current_class_handle"]["attributes"], read_root()))):
- // Condition false, so skip
- continue!
- // Fine to add this one without event parameters (no event)
- set_add_node(result, create_tuple(transition, read_root()))
- return result!
- Void function process_raised_event(model : Element, event : Element, parameter_action : Element, data : Element):
- String scope
- scope = read_attribute(model, event, "scope")
- if (scope == "cd"):
- // Is an event for us internally, so don't append
- // Instead, we process it directly
- String operation
- operation = read_attribute(model, event, "event")
- if (operation == "create_instance"):
- // Start up a new class of the desired type
- // Parameters of this call:
- // class -- type of the class to instantiate
- // identifier -- name of this instance, for future reference
- // parameters -- parameters for constructor
- String class
- String identifier
- Element parameters
- class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "name", list_read(parameter_action, 1)))
- parameters = list_read(parameter_action, 2)
- identifier = start_class(model, data, class, parameters)
- // Notify the creator of the ID of the created instance
- Element lst
- lst = list_create()
- list_append(lst, identifier)
- set_add_node(data["current_class_handle"]["new_events"], create_tuple("instance_created", lst))
- elif (operation == "delete_instance"):
- // Delete the requested class
- String identifier
- identifier = list_read(parameter_action, 0)
- delete_class(model, data, identifier)
- set_add_node(data["current_class_handle"]["new_events"], create_tuple("instance_deleted", parameter_action))
- elif (scope == "broad"):
- // Send to all classes
- Element classes
- classes = dict_keys(data["classes"])
- while(set_len(classes) > 0):
- set_add_node(data["classes"][set_pop(classes)]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
- elif (scope == "narrow"):
- // Send to the specified class only
- Element func
- func = resolve_function(read_attribute(model, event, "target"), data)
- String dest
- dest = func(data["current_class_handle"]["attributes"])
- set_add_node(data["classes"][dest]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
- elif (scope == "output"):
- // Store it in the output event model
- String evt
- if (bool_not(afap)):
- Element val
- val = dict_create()
- dict_add(val, "timestamp", data["time_sim"])
- dict_add(val, "name", read_attribute(model, event, "event"))
- dict_add(val, "parameter", parameter_action)
- output("EVENT: " + dict_to_string(val))
- evt = instantiate_node(model, "trace/Event", "")
- instantiate_attribute(model, evt, "timestamp", data["time_sim"])
- instantiate_attribute(model, evt, "name", read_attribute(model, event, "event"))
- instantiate_attribute(model, evt, "parameter", parameter_action)
- else:
- // Same as local
- set_add_node(data["current_class_handle"]["new_events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
- return !
- Element function execute_transition(model : Element, data : Element, transition_tuple : Element):
- // Execute the script (if any)
- Element script
- String transition
- Element event_parameter
- transition = list_read(transition_tuple, 0)
- event_parameter = list_read(transition_tuple, 1)
- script = read_attribute(model, transition, "script")
- if (element_neq(script, read_root())):
- script = resolve_function(script, data)
- script(data["current_class_handle"]["attributes"], event_parameter)
- // Raise events (if any)
- Element events
- String event
- events = allAssociationDestinations(model, transition, "SCCD/transition_raises")
- while (set_len(events) > 0):
- event = set_pop(events)
- Element parameter_action
- parameter_action = read_attribute(model, event, "parameter")
- if (element_neq(parameter_action, read_root())):
- // Got a parameter to evaluate
- parameter_action = resolve_function(parameter_action, data)
- parameter_action = parameter_action(data["current_class_handle"]["attributes"], event_parameter)
- process_raised_event(model, event, parameter_action, data)
- // Find new set of states
- Element target_states
- Element source_states
- source_states = expand_current_state(model, readAssociationSource(model, transition), data)
- target_states = expand_initial_state(model, readAssociationDestination(model, transition), data)
- execute_actions(model, source_states, target_states, data, readAssociationSource(model, transition))
- 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
- // Iterate over all current states, searching for enabled transitions
- // Search for enabled transitions in higher levels as well!
- Element states
- Element new_states
- String state
- Element transitions
- String transition
- Boolean transitioned
- Element hierarchy
- String current_state
- Boolean found
- if (bool_not(dict_in(data["classes"], class))):
- // Seems like this class was removed, so stop execution
- return False!
- // Notify everyone of the current class
- dict_overwrite(data, "current_class", class)
- dict_overwrite(data, "current_class_handle", data["classes"][class])
- states = set_copy(data["current_class_handle"]["states"])
- new_states = set_create()
- transitioned = False
- while (set_len(states) > 0):
- state = set_pop(states)
- found = False
- // Loop over the hierarchy of this state and try to apply transitions
- hierarchy = find_hierarchy(model, state, data)
- while (list_len(hierarchy) > 0):
- current_state = list_pop(hierarchy, 0)
- transitions = get_enabled_transitions(model, current_state, data)
- if (set_len(transitions) > 0):
- // Found an enabled transition, so store that one
- transition = random_choice(set_to_list(transitions))
-
- // Execute transition
- set_merge(new_states, execute_transition(model, data, transition))
- // When leaving an orthogonal component, we must also pop all related states that might be processed in the future!
- Element leaving
- leaving = expand_current_state(model, current_state, data)
- set_subtract(states, leaving)
- transitioned = True
- found = True
- break!
- if (bool_not(found)):
- // Nothing found, so stay in the current state
- set_add(new_states, state)
-
- // Update states
- dict_overwrite(data["current_class_handle"], "states", new_states)
- return transitioned!
- String function get_parent(model : Element, state : String):
- Element tmp_set
- tmp_set = allAssociationOrigins(model, state, "SCCD/composite_children")
- set_merge(tmp_set, allAssociationOrigins(model, state, "SCCD/parallel_children"))
- if (set_len(tmp_set) > 0):
- return set_pop(tmp_set)!
- else:
- return ""!
- Element function find_hierarchy(model : Element, state : String, data : Element):
- // Try to cache as much as possible!
- if (bool_not(dict_in(data["cache_hierarchy"], state))):
- Element result
- if (state == ""):
- result = list_create()
- else:
- String parent
- parent = get_parent(model, state)
- // We have a parent, so take the parent list first
- result = find_hierarchy(model, parent, data)
- list_append(result, state)
- dict_add(data["cache_hierarchy"], state, result)
- return dict_copy(data["cache_hierarchy"][state])!
- Void function execute_actions(model : Element, source_states : Element, target_states : Element, data : Element, transition_source : String):
- Element exit
- Element entry
- exit = list_create()
- entry = list_create()
- 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 = set_create()
- while (set_len(source_states) > 0):
- set_add_node(hierarchy_sources, find_hierarchy(model, set_pop(source_states), data))
- hierarchy_targets = set_create()
- while (set_len(target_states) > 0):
- set_add_node(hierarchy_targets, find_hierarchy(model, set_pop(target_states), data))
- 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
- Boolean finished
- Integer transition_depth
- Integer lca_depth
- lca_depth = 0
- finished = False
- if (transition_source != ""):
- // Find out the level of the transition_source by fetching its hierarchy
- transition_depth = list_len(find_hierarchy(model, transition_source, data)) - 1
- // Now check for the least common ancestor
- while (bool_not(finished)):
- // Check the i-th element in both and see if they are equal
- current = ""
- iter_hierarchies = set_copy(all_hierarchies)
- while (set_len(iter_hierarchies) > 0):
- hierarchy = set_pop(iter_hierarchies)
- // Exhausted one of the lists
- if (lca_depth >= list_len(hierarchy)):
- finished = True
- break!
- // Reached the same level as transition depth already, so no need to increase
- if (lca_depth == transition_depth):
- finished = True
- break!
- // First entry, so read out value as reference
- if (current == ""):
- current = list_read(hierarchy, lca_depth)
- // Check with reference element
- if (bool_not(value_eq(list_read(hierarchy, lca_depth), current))):
- finished = True
- break!
- // i-th element equal for all hierarchies, so go to next element
- if (bool_not(finished)):
- lca_depth = lca_depth + 1
- if (lca_depth < transition_depth):
- i = lca_depth
- else:
- i = transition_depth
- else:
- // Initial, so just set i to zero
- i = 0
- // 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 = set_create()
- while (set_len(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!
- list_insert(exit, state, 0)
- // Add this state as visited
- set_add(visited, state)
- // Add hierarchy_targets actions
- // Clear visited, just to be safe, though it should not matter
- visited = set_create()
- while (set_len(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!
- list_append(entry, state)
- // Add this state as visited, even though there might not have been an associated action
- set_add(visited, state)
- // Now we have a list of traversed states!
- // Start executing all their operations in order
- Element events
- String event
- // First do exit actions
- while (list_len(exit) > 0):
- state = list_pop(exit, 0)
- // Set history when leaving
- if (read_type(model, state) == "SCCD/CompositeState"):
- dict_overwrite(data["current_class_handle"]["history"], state, expand_current_state(model, state, data))
- // Do exit actions
- action = read_attribute(model, state, "onExitScript")
- if (element_neq(action, read_root())):
- // Got a script, so execute!
- action = resolve_function(action, data)
- action(data["current_class_handle"]["attributes"])
- // Raise events
- events = allAssociationDestinations(model, state, "SCCD/onExitRaise")
- while (set_len(events) > 0):
- event = set_pop(events)
- Element parameter_action
- parameter_action = read_attribute(model, event, "parameter")
- if (element_neq(parameter_action, read_root())):
- // Got a parameter to evaluate
- parameter_action = resolve_function(parameter_action, data)
- parameter_action = parameter_action(data["current_class_handle"]["attributes"])
- process_raised_event(model, event, parameter_action, data)
- // Unschedule after events
- Element timed_transitions
- timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
- while (set_len(timed_transitions) > 0):
- dict_delete(data["current_class_handle"]["timers"], set_pop(timed_transitions))
- // Then do entry actions
- while (list_len(entry) > 0):
- state = list_pop(entry, 0)
- // Do entry actions
- action = read_attribute(model, state, "onEntryScript")
- if (element_neq(action, read_root())):
- // Got a script, so execute!
- action = resolve_function(action, data)
- action(data["current_class_handle"]["attributes"])
- // Raise events
- events = allAssociationDestinations(model, state, "SCCD/onEntryRaise")
- while (set_len(events) > 0):
- event = set_pop(events)
- Element parameter_action
- parameter_action = read_attribute(model, event, "parameter")
- if (element_neq(parameter_action, read_root())):
- // Got a parameter to evaluate
- parameter_action = resolve_function(parameter_action, data)
- parameter_action = parameter_action(data["current_class_handle"]["attributes"])
- process_raised_event(model, event, parameter_action, data)
- // Schedule after events
- Element timed_transitions
- String transition
- Element after
- timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
- while (set_len(timed_transitions) > 0):
- transition = set_pop(timed_transitions)
- after = resolve_function(read_attribute(model, transition, "after"), data)
- dict_add(data["current_class_handle"]["timers"], transition, float_addition(data["time_sim"], after(data["current_class_handle"]["attributes"])))
- return !
- Float function step(model : Element, data : Element):
- // Step through all classes
- Element classes
- Element class
- Float t_min
- Float t_current
- Boolean transitioned
- Element keys
- String key
- t_min = 999999.0
- classes = dict_keys(data["classes"])
- transitioned = False
- while (set_len(classes) > 0):
- class = set_pop(classes)
- if (step_class(model, data, class)):
- transitioned = True
- if (bool_not(transitioned)):
- // Find minimum timer for this class, and store that
- keys = dict_keys(data["classes"][class]["timers"])
- while (set_len(keys) > 0):
- key = set_pop(keys)
- t_current = data["classes"][class]["timers"][key]
- if (t_current < t_min):
- t_min = t_current
- if (transitioned):
- // Do another step, as we can transition
- return data["time_sim"]!
- else:
- return t_min!
- Boolean function main(model : Element):
- // Executes the provided SCCD model
- Element data
- data = dict_create()
- dict_add(data, "classes", dict_create())
- dict_add(data, "cache_operations", dict_create())
- dict_add(data, "cache_hierarchy", dict_create())
- dict_add(data, "current_class", "")
-
- Float time_0
- Float time_sim
- Float time_wallclock
- time_0 = time()
- time_sim = 0.0
- dict_add(data, "time_sim", 0.0)
- // Prepare for input
- output("Ready for input!")
- // Find initial
- String default_class
- default_class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "default", True))
- // Start up the default class
- String identifier
- identifier = start_class(model, data, default_class, read_root())
- // Notify this class itself of its ID
- Element lst
- lst = list_create()
- list_append(lst, identifier)
- set_add_node(data["current_class_handle"]["new_events"], create_tuple("instance_created", lst))
- Float timeout
- Element interrupt
- timeout = 0.0
- while (True):
- if (afap):
- timeout = 0.0
- interrupt = input_timeout(timeout)
- if (value_eq(interrupt, "#EXIT#")):
- // Stop execution
- return True!
- if (element_neq(interrupt, read_root())):
- // Send out, as otherwise the client doesn't get a dialog
- output("Processed event, ready for more!")
- // Update the simulated time to the time of interrupt
- time_sim = time() - time_0
- Element classes
- classes = dict_keys(data["classes"])
- while(set_len(classes) > 0):
- String class
- class = set_pop(classes)
- dict_overwrite(data["classes"][class], "events", data["classes"][class]["new_events"])
- dict_overwrite(data["classes"][class], "new_events", set_create())
- if (element_neq(interrupt, read_root())):
- // Got interrupt, so append it already
- set_add_node(data["classes"][class]["events"], create_tuple(interrupt, read_root()))
- // Else we timeout, and thus keep the time_sim
- dict_overwrite(data, "time_sim", time_sim)
- time_sim = step(model, data)
- if (float_gt(time_sim, data["time_sim"])):
- print_states(model, data)
- if (dict_len(data["classes"]) == 0):
- // No more active classes left: terminate!
- log("Finished SCCD execution")
- break!
- time_wallclock = time() - time_0
- timeout = time_sim - time_wallclock
- // We have finished without error
- return True!
|