Quellcode durchsuchen

Added a minimal piece of code for SCCD execution

Yentl Van Tendeloo vor 8 Jahren
Ursprung
Commit
b96a438ea3
4 geänderte Dateien mit 540 neuen und 0 gelöschten Zeilen
  1. 32 0
      integration/code/minimal_SCCD.mvc
  2. 270 0
      models/SCCD.mvc
  3. 214 0
      models/SCCD_execute.alc
  4. 24 0
      wrappers/test_SCCD.py

+ 32 - 0
integration/code/minimal_SCCD.mvc

@@ -0,0 +1,32 @@
+Diagram my_SCCD {
+    name = "SimpleSCCD"
+    author = "Yentl"
+}
+
+Class main {
+    name = "Main"
+    default = True
+}
+
+CompositeState main_statechart {
+    name = "root"
+    isInitial = True
+
+    {composite_children} BasicState root_a {
+        name = "a"
+        isInitial = True
+    }
+
+    {composite_children} BasicState root_b {
+        name = "b"
+        isInitial = False
+    }
+
+}
+
+transition (root_a, root_b) {
+    name = "A2B"
+}
+
+diagram_classes (my_SCCD, main) {}
+behaviour (main, main_statechart) {}

+ 270 - 0
models/SCCD.mvc

@@ -0,0 +1,270 @@
+include "primitives.alh"
+include "object_operations.alh"
+include "modelling.alh"
+
+SimpleAttribute Neutral {}
+SimpleAttribute Boolean {
+    constraint = $
+    String function constraint(model: Element, id: String):
+        if (bool_not(is_physical_boolean(model["model"][id]))):
+            return "Boolean has no boolean value at " + id!
+        else:
+            return "OK"!
+    $
+}
+SimpleAttribute String {
+    constraint = $
+    String function constraint(model: Element, id: String):
+        if (bool_not(is_physical_string(model["model"][id]))):
+            return "String has no string value at " + id!
+        else:
+            return "OK"!
+    $
+}
+SimpleAttribute Natural {
+    constraint =$
+    String function constraint(model: Element, id: String):
+        if (bool_not(is_physical_int(model["model"][id]))):
+            return "Natural has no integer value at " + id!
+        elif (integer_lt(model["model"][id], 0)):
+            return "Natural does not have a positive or zero value at " + id!
+        else:
+            return "OK"!
+     $
+}
+SimpleAttribute PositiveFloat {
+    constraint =$
+    String function constraint(model: Element, id: String):
+        if (bool_not(is_physical_float(model["model"][id]))):
+            return "PositiveFloat has no float value at " + id!
+        elif (integer_lt(model["model"][id], 0)):
+            return "PositiveFloat does not have a positive or zero value at " + id!
+        else:
+            return "OK"!
+     $
+}
+SimpleAttribute EventScope {
+    constraint =$
+    String function constraint(model: Element, id: String):
+        String self
+        self = model["model"][id]
+        if (bool_not(is_physical_string(self))):
+            return "EventScope has no string value at " + id!
+        elif (bool_or(bool_or(bool_or(self != "broad", self != "cd"), bool_or(self != "narrow", self != "output")), self != 'local')):
+            return "EventScope can be either 'local', 'broad', 'cd', 'narrow' or 'output' and it does not have a proper value at " + id!
+        else:
+            return "OK"!
+    $
+}
+
+Class Diagram{
+    name : String
+    author ?: String
+    description ?: String
+    top ?: String
+    class_reference_items ?: String
+    lower_cardinality = 1
+    upper_cardinality = 1
+}
+Class Inport{
+    name: String
+}
+Class Outport{
+    name: String
+}
+Association diagram_inports(Diagram, Inport){}
+Association diagram_outports(Diagram, Outport){}
+
+Class Class{
+    name : String
+    constructor_body ?: String
+    destructor ?: String
+    default ?: Boolean
+    external ?: Boolean
+    class_behaviour_items ?: String
+}
+Association diagram_classes(Diagram, Class){
+    target_lower_cardinality = 1
+}
+
+Class Attribute{
+    name : String
+    type ?: String
+}
+Association class_attributes(Class, Attribute){}
+
+Class Method{
+    name : String
+    body : String
+    return_type ?: String
+}
+
+Class FormalParameter{
+    name: String
+    type ?: String
+    default ?: String
+}
+Association method_parameters(Method, FormalParameter){}
+Association class_methods(Class, Method){}
+Association class_constructor_parameters(Class, FormalParameter){}
+
+Class CanvasPosition{
+    x1: Natural
+    y1: Natural
+    x2 ?: Natural
+    y2 ?: Natural
+}
+Association class_ref_position(Class, CanvasPosition){
+    target_upper_cardinality = 1
+}
+Association class_beh_position(Class, CanvasPosition){
+    target_upper_cardinality = 1
+}
+
+Association association(Class, Class){
+    name : String
+    min ?: Natural
+    max ?: Natural
+    source_upper_cardinality = 1
+}
+Association association_positions(association, CanvasPosition){
+    order: Natural
+}
+
+Association inheritance(Class, Class){
+    priority ?: Natural
+    source_upper_cardinality = 1
+}
+
+Class SuperClassConstructorParameter{
+    value : Neutral
+}
+Association inheritance_parent_constructor_parameters(inheritance, SuperClassConstructorParameter){
+    order : Natural
+}
+Association inheritance_positions(inheritance, CanvasPosition){
+    order: Natural
+}
+
+Class State{
+    name : String
+    state_reference_path ?: String
+}
+Association state_position(State, CanvasPosition){
+    target_upper_cardinality = 1
+}
+
+Class BasicState : State{
+    isInitial : Boolean
+    onEntryScript ?: String
+    onExitScript ?: String
+}
+
+Association behaviour(Class, BasicState){
+    target_lower_cardinality = 1
+    target_upper_cardinality = 1
+}
+Association behaviour_positions(behaviour, CanvasPosition){
+    order: Natural
+}
+
+Class ActualParameter{
+    exp: String
+}
+
+Class Raise{
+    event: String
+    scope ?: EventScope
+    port ?: String
+    target ?: String
+}
+Association raise_parameters(Raise, ActualParameter){
+    order : Natural
+}
+Association state_onentry_raises(BasicState, Raise){
+    order : Natural
+}
+Association state_onexit_raises(BasicState, Raise){
+    order : Natural
+}
+
+Class CompositeState : BasicState{}
+Association composite_children(CompositeState, State){
+    source_upper_cardinality = 1
+}
+
+Class ParallelState : BasicState{}
+Association parallel_children(ParallelState, CompositeState){
+    source_upper_cardinality = 1
+}
+
+Class HistoryState : State{
+    type : String
+}
+
+Association transition(State, State){
+    name: String
+    cond ?: String
+    script ?: String
+    after ?: PositiveFloat
+    event ?: String
+    port ?: String
+    source_upper_cardinality = 1
+}
+Association transition_parameters(transition, FormalParameter){
+    order : Natural
+}
+Association transition_raises(transition, Raise){
+    order : Natural
+}
+Association transition_positions(transition, CanvasPosition){
+    order: Natural
+}
+
+GlobalConstraint {
+        global_constraint = $
+            String function constraint(model : Element):
+                Element composite_states
+                Element parallel_states
+                Element children
+                String state
+                String child
+                String name
+                Boolean CompInitialFound
+                Element encountered_names
+
+                composite_states = allInstances(model, "CompositeState")
+                parallel_states = allInstances(model, "ParallelState")
+
+                while (list_len(composite_states) >0):
+                    CompInitialFound = False
+                    encountered_names = create_node()
+                    state = set_pop(composite_states)
+                    children = allAssociationDestinations(model, state, "composite_children")
+                    while (list_len(children)>0):
+                        child = set_pop(children)
+                        name = read_attribute(model, child, 'name')
+                        if (set_in(encountered_names, name)):
+                            return "Unique state identifier names on the same level/parent violated"!
+                        else:
+                            set_add(encountered_names, name)
+                        if bool_and(read_type(model, child) != 'HistoryState' , read_attribute(model, child, 'isInitial')):
+                            CompInitialFound = True
+                    if CompInitialFound == False:
+                        return "Composite state does not have an initial child state"!
+
+                while (list_len(parallel_states) >0):
+                    encountered_names = create_node()
+                    state = set_pop(parallel_states)
+                    children = allAssociationDestinations(model, state, "parallel_children")
+                    while (list_len(children)>0):
+                        child = set_pop(children)
+                        name = read_attribute(model, child, 'name')
+                        if (set_in(encountered_names, name)):
+                            return "Unique state identifier names on the same level/parent violated"!
+                        else:
+                            set_add(encountered_names, name)
+
+                return "OK"!
+        $
+}

+ 214 - 0
models/SCCD_execute.alc

@@ -0,0 +1,214 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+include "utils.alh"
+include "random.alh"
+
+Void function print_states(model : Element, data : Element):
+	Element classes
+	Element states
+	Element class
+	String state
+
+	log("Current states:")
+	classes = set_copy(data["classes"])
+	while (read_nr_out(classes) > 0):
+		class = set_pop(classes)
+		log(string_join(string_join(string_join("  ", class["ID"]), " : "), read_attribute(model, class["type"], "name")))
+
+		states = set_copy(class["states"])
+		while (read_nr_out(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 = create_node()
+	while (read_nr_out(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 expand_state(model : Element, state : String):
+	String t
+	t = read_type(model, state)
+	if (t == "SCCD/CompositeState"):
+		// Recurse further in the composite
+		return expand_composite_state(model, state)!
+	elif (t == "SCCD/ParallelState"):
+		// Split up all components
+		return expand_parallel_state(model, state)!
+	else:
+		// Probably just an atomic, so return this one only
+		Element result
+		result = create_node()
+		set_add(result, state)
+		return result!
+
+Element function expand_composite_state(model : Element, composite_state : String):
+	// 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))
+	log("Got initial state: " + initial)
+
+	// Expand the initial state, depending on what it is
+	return expand_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 result
+	Element expanded_children
+
+	children = allAssociationDestinations(model, parallel_state, "SCCD/parallel_children")
+	result = create_node()
+
+	while (read_nr_out(children) > 0):
+		set_merge(result, expand_state(model, set_pop(children)))
+
+	return result!
+
+Void function start_class(model : Element, data : Element, class : String):
+	// Start up the class and assign its initial state to it
+
+	// Create the data structure for a running class
+	Element class_handle
+	class_handle = create_node()
+	dict_add(class_handle, "type", class)
+	dict_add(class_handle, "ID", cast_id2s(create_node()))
+
+	// 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_state(model, initial_state))
+
+	set_add(data["classes"], class_handle)
+
+	return!
+
+Element function get_enabled_transitions(model : Element, state : String, interrupt : Element):
+	// Returns all enabled transitions
+	// TODO ignore conditions and afters
+	Element result
+	Element to_filter
+	String attr
+	String transition
+
+	result = create_node()
+	to_filter = allOutgoingAssociationInstances(model, state, "SCCD/transition")
+
+	while (read_nr_out(to_filter) > 0):
+		transition = set_pop(to_filter)
+		attr = read_attribute(model, transition, "event")
+		if (element_eq(attr, read_root())):
+			// No event defined, so is fine
+			set_add(result, transition)
+		elif (value_eq(attr, interrupt)):
+			// Event defined, and that is the one of the event we got in
+			set_add(result, transition)
+
+	return result!
+
+Float function step_class(model : Element, data : Element, class : Element, interrupt : Element):
+	// 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
+
+	log(string_join("Stepping ", class["ID"]))
+	states = set_copy(class["states"])
+	new_states = create_node()
+
+	while (read_nr_out(states) > 0):
+		state = set_pop(states)
+
+		// Fetch transitions in this state specifically (NO parent)
+		transitions = get_enabled_transitions(model, state, interrupt)
+		log("Got enabled transitions: " + cast_v2s(read_nr_out(transitions)))
+		if (read_nr_out(transitions) != 0):
+			// Found an enabled transition, so store that one
+			transition = random_choice(transitions)
+			log("Executing enabled transition: " + cast_v2s(read_attribute(model, transition, "name")))
+
+			set_add(new_states, readAssociationDestination(model, transition))
+			log("Found new state: " + cast_v2s(read_attribute(model, readAssociationDestination(model, transition), "name")))
+		else:
+			// Try going to the parent
+			// TODO
+
+			// Nothing found, so stay in the current state
+			set_add(new_states, state)
+
+	// Update states
+	dict_overwrite(class, "states", new_states)
+
+	return 1.0!
+
+Float function step(model : Element, data : Element, interrupt : Element):
+	// Step through all classes
+	Element classes
+	Element class
+	Float t_min
+	Float t_class
+
+	t_min = 99999.0
+	classes = set_copy(data["classes"])
+
+	while (read_nr_out(classes) > 0):
+		class = set_pop(classes)
+		t_class = step_class(model, data, class, interrupt)
+		if (t_class < t_min):
+			t_min = t_class
+
+	return t_min!
+
+Boolean function main(model : Element):
+	// Executes the provided SCCD model
+	Element data
+	data = create_node()
+	dict_add(data, "classes", create_node())
+
+	// Prepare for input
+	output("Ready for input!")
+
+	// Find initial
+	String default_class
+	default_class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "default", True))
+	log("Found default class: " + default_class)
+
+	// Start up the default class
+	start_class(model, data, default_class)
+
+	Float timeout
+	Element interrupt
+	timeout = 0.0
+	while (True):
+		print_states(model, data)
+		interrupt = input_timeout(timeout)
+
+		if (value_eq(interrupt, "#EXIT#")):
+			// Stop execution
+			return True!
+
+		if (element_neq(interrupt, read_root())):
+			// Got interrupt
+			log("Got event: " + cast_v2s(interrupt))
+			output("Processed event, ready for more!")
+
+		timeout = step(model, data, interrupt)
+
+	return True!

+ 24 - 0
wrappers/test_SCCD.py

@@ -0,0 +1,24 @@
+import sys
+sys.path.append("wrappers")
+from modelverse import *
+
+init()
+login("admin", "admin")
+
+try:
+    model_add("SCCD", "SimpleClassDiagrams", open("models/SCCD.mvc", 'r').read())
+    model_add("my_SCCD", "SCCD", open("integration/code/minimal_SCCD.mvc", 'r').read())
+except ModelExists:
+    pass
+
+if "SCCD_execute" in [i[0] for i in model_list()]:
+    print("Detected previous version; removing")
+    model_delete("SCCD_execute")
+
+transformation_add_AL({"SCCD": "SCCD"}, {}, "SCCD_execute", open("models/SCCD_execute.alc", 'r').read())
+
+def callback(inp):
+    print(inp)
+    return raw_input()
+
+transformation_execute_AL("SCCD_execute", {"SCCD": "my_SCCD"}, {}, callback=callback)