include "primitives.alh" include "io.alh" include "object_operations.alh" include "constructors.alh" include "metamodels.alh" include "library.alh" Element global_models = ? String function instantiated_name(element : Element, original : String): if (original == ""): return "__" + cast_id2s(element)! else: return original! Element function instantiate_bottom(): // Just create a new node that serves as the basis for everything // We don't know anything about the model yet, so just create an empty one Element new_model // The actual root node of the model new_model = create_node() // Add an empty model and empty type mapping dict_add(new_model, "model", create_node()) dict_add(new_model, "type_mapping", create_node()) dict_add(new_model, "__kind", "formalism") // Return the created model return new_model! String function model_add_node(model : Element, name : String): // Adds a new node to the specified model with the desired name // This is a bottom operation, as it doesn't take any type Element new_node String actual_name new_node = create_node() actual_name = instantiated_name(new_node, name) dict_add(model["model"], actual_name, new_node) return actual_name! String function model_add_value(model : Element, name : String, value : Element): // Similar to model_add_node, but add a value as well String actual_name actual_name = instantiated_name(value, name) dict_add(model["model"], actual_name, value) return actual_name! String function model_add_edge(model : Element, name : String, source : String, destination : String): // Add an edge between the source and destination nodes // Nodes are specified using their string representation previously defined Element new_edge String actual_name if (bool_not(dict_in(model["model"], source))): log("In link " + name) log("ERROR: source of link unknown: " + source) log("Destination: " + destination) return ""! if (bool_not(dict_in(model["model"], destination))): log("In link " + name) log("ERROR: destination of link unknown: " + destination) log("Source: " + source) return ""! new_edge = create_edge(model["model"][source], model["model"][destination]) actual_name = instantiated_name(new_edge, name) dict_add(model["model"], actual_name, new_edge) return actual_name! Void function retype_model(model : Element, metamodel : Element): // Remove the type mapping and add a new one for the specified metamodel dict_delete(model, "type_mapping") dict_add(model, "type_mapping", create_node()) dict_add(model, "metamodel", metamodel) return! Void function retype(model : Element, element : String, type : String): // Retype a model, deleting any previous type the element had // The type string is evaluated in the metamodel previously specified if (dict_in_node(model["type_mapping"], model["model"][element])): dict_delete_node(model["type_mapping"], model["model"][element]) dict_add(model["type_mapping"], model["model"][element], model["metamodel"]["model"][type]) return! Element function instantiate_model(metamodel : Element): // Instantiate a model // Basically create an untyped model and retype it Element model model = instantiate_bottom() retype_model(model, metamodel) return model! String function instantiate_node(model : Element, type_name : String, instance_name : String): // Create a node typed by a node from the metamodel // Basically create a node and type it immediately String actual_name actual_name = model_add_node(model, instance_name) retype(model, actual_name, type_name) return actual_name! String function instantiate_value(model : Element, type_name : String, instance_name : String, value : Element): // Create a node typed by a node from the metamodel // Basically create a node and type it immediately String actual_name actual_name = model_add_value(model, instance_name, value) retype(model, actual_name, type_name) return actual_name! String function find_attribute_type(model : Element, elem : String, name : String): String mm_elem String direct_type direct_type = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][elem])) mm_elem = find_attribute_definer(model["metamodel"], direct_type, name) if (value_eq(mm_elem, "")): // Couldn't find element, so is not allowed! return ""! else: return reverseKeyLookup(model["metamodel"]["model"], dict_read_edge(model["metamodel"]["model"][mm_elem], name))! Element function get_superclasses(model : Element, name : String): Element result Integer i Integer j Integer num_edges Element edge Element elem Element nodes Element inheritance nodes = create_node() set_add(nodes, model["model"][name]) inheritance = model["metamodel"]["model"]["Inheritance"] // Initialize empty set result = create_node() i = 0 while (list_len(nodes) > 0): elem = set_pop(nodes) if (bool_not(set_in(result, reverseKeyLookup(model["model"], elem)))): create_edge(result, reverseKeyLookup(model["model"], elem)) // Read out all outgoing edges num_edges = read_nr_out(elem) j = 0 while (j < num_edges): edge = read_out(elem, j) if (element_eq(dict_read_node(model["type_mapping"], edge), inheritance)): set_add(nodes, read_edge_dst(edge)) j = j + 1 return result! String function find_attribute_definer(model : Element, elem_name : String, name : String): Element superclasses String current Integer nr_out Element out String name_attr superclasses = get_superclasses(model, elem_name) while (list_len(superclasses) > 0): current = set_pop(superclasses) nr_out = read_nr_out(model["model"][current]) while (nr_out > 0): nr_out = nr_out - 1 out = read_out(model["model"][current], nr_out) name_attr = read_attribute(model, reverseKeyLookup(model["model"], out), "name") if (name_attr == name): return current! return ""! Void function instantiate_attribute(model : Element, element : String, attribute_name : String, value : Element): // Instantiate an attribute of something that needs to be instantiated // Actually a bit more difficult than all the rest, as we need to find the attribute to instantiate String attr_type String attr_name attr_type = find_attribute_type(model, element, attribute_name) if (attr_type == ""): log("Could not find attribute " + cast_v2s(attribute_name)) return! // Make a copy of the value, as it is likely that this value is reused later on value = create_value(value) attr_name = model_add_value(model, (element + ".") + attribute_name, value) retype(model, attr_name, reverseKeyLookup(model["metamodel"]["model"], read_edge_dst(model["metamodel"]["model"][attr_type]))) instantiate_link(model, attr_type, "", element, attr_name) return! Void function instantiate_attribute_ref(model : Element, element : String, attribute_name : String, ref : String): // Instantiate an attribute of something that needs to be instantiated // Actually a bit more difficult than all the rest, as we need to find the attribute to instantiate String attr_type String attr_name attr_type = find_attribute_type(model, element, attribute_name) if (attr_type == ""): log("Could not find attribute " + cast_v2s(attribute_name)) return! instantiate_link(model, attr_type, "", element, ref) return! Void function instantiate_attribute_code(model : Element, element : String, attribute_name : String, code : Element): String ref ref = add_AL(model, code) instantiate_existing_attribute(model, element, attribute_name, ref) return! Void function instantiate_existing_attribute(model : Element, element : String, attribute_name : String, attr_ref : String): // Instantiate an attribute of something that needs to be instantiated // Actually a bit more difficult than all the rest, as we need to find the attribute to instantiate String attr_type String attr_name attr_type = find_attribute_type(model, element, attribute_name) if (attr_type == ""): log("Could not find attribute " + cast_v2s(attribute_name)) return! // Make a copy of the value, as it is likely that this value is reused later on retype(model, attr_ref, reverseKeyLookup(model["metamodel"]["model"], read_edge_dst(model["metamodel"]["model"][attr_type]))) instantiate_link(model, attr_type, "", element, attr_ref) return! String function instantiate_link(model : Element, type : String, name : String, source : String, destination : String): // Create a typed link between two nodes String actual_name actual_name = model_add_edge(model, name, source, destination) if (type == ""): // Have to find the type ourselves, as it isn't defined Element out Element in Element options options = allowedAssociationsBetween(model, source, destination) if (read_nr_out(options) == 1): type = set_pop(options) elif (read_nr_out(options) == 0): log("ERROR: cannot find possible link between entries") return ""! else: log("ERROR: too many possible links between entries") return ""! retype(model, actual_name, type) return actual_name! Void function model_delete_element(model : Element, name : String): // Remove the link // 1) from the type mapping dict_delete_node(model["type_mapping"], model["model"][name]) // 2) from the model delete_element(model["model"][name]) return! String function model_define_attribute(model : Element, elem : String, name : String, type : String): // Create the necessary links to make it an attribute String edge_name edge_name = instantiate_link(model, "Association", "", elem, type) instantiate_attribute(model, edge_name, "name", name) return edge_name! Element function read_attribute(model : Element, element : String, attribute : String): Integer i Integer count Element edge Element edge_type Element elem Element typing elem = model["model"][element] typing = model["type_mapping"] count = read_nr_out(elem) i = 0 while (i < count): edge = read_out(elem, i) if (dict_in_node(typing, edge)): edge_type = dict_read_node(typing, edge) if (element_eq(edge_type, dict_read_edge(read_edge_src(edge_type), attribute))): return read_edge_dst(edge)! i = i + 1 return read_root()! Void function unset_attribute(model : Element, element : String, attribute : String): // Removes an attribute if it exists String attr_type Element attr_links String attr_link attr_type = find_attribute_type(model, element, attribute) attr_links = allOutgoingAssociationInstances(model, element, attr_type) while (list_len(attr_links) > 0): attr_link = set_pop(attr_links) dict_delete_node(model["type_mapping"], read_edge_dst(model["model"][attr_link])) dict_delete_node(model["type_mapping"], model["model"][attr_link]) dict_delete_node(model["model"], reverseKeyLookup(model["model"], read_edge_dst(model["model"][attr_link]))) delete_element(model["model"][attr_link]) return! Void function add_AL_links(model : Element, list : Element, element : Element, type: String, linkname : String, expected_type : String): if (bool_not(dict_in(element, linkname))): return! Element link link = dict_read_edge(element, linkname) // The link dict_add(model["model"], "__" + cast_id2s(link), link) dict_add(model["type_mapping"], link, model["metamodel"]["model"][(type + "_") + linkname]) // The name link link = read_out(link, 0) dict_add(model["model"], "__" + cast_id2s(link), link) dict_add(model["type_mapping"], link, model["metamodel"]["model"]["to_str"]) // The name node link = read_edge_dst(link) if (bool_not(set_in_node(model["model"], link))): dict_add(model["model"], "__" + cast_id2s(link), link) dict_add(model["type_mapping"], link, model["metamodel"]["model"]["String"]) // Now add the destination to the worker list Element node node = create_node() list_append(node, element[linkname]) list_append(node, expected_type) set_add(list, node) return! String function add_AL(model : Element, element : Element): Element todo Element node Element work_node Element elem String type todo = create_node() node = create_node() list_append(node, element) list_append(node, "funcdef") set_add(todo, node) while (0 < dict_len(todo)): work_node = set_pop(todo) elem = list_read(work_node, 0) type = list_read(work_node, 1) if (bool_not(set_in_node(model["model"], elem))): // Determine the type if we don't know it if (type == ""): if (is_physical_action(elem)): type = cast_a2s(elem) else: type = "Any" // Add the node itself dict_add(model["model"], "__" + cast_id2s(elem), elem) dict_add(model["type_mapping"], elem, model["metamodel"]["model"][type]) // Now add its edges if (type == "if"): add_AL_links(model, todo, elem, type, "cond", "") add_AL_links(model, todo, elem, type, "then", "") add_AL_links(model, todo, elem, type, "else", "") add_AL_links(model, todo, elem, type, "next", "") elif (type == "while"): add_AL_links(model, todo, elem, type, "cond", "") add_AL_links(model, todo, elem, type, "body", "") add_AL_links(model, todo, elem, type, "next", "") elif (type == "assign"): add_AL_links(model, todo, elem, type, "var", "") add_AL_links(model, todo, elem, type, "value", "") add_AL_links(model, todo, elem, type, "next", "") elif (type == "break"): add_AL_links(model, todo, elem, type, "while", "while") elif (type == "continue"): add_AL_links(model, todo, elem, type, "while", "while") elif (type == "return"): add_AL_links(model, todo, elem, type, "value", "") elif (type == "resolve"): add_AL_links(model, todo, elem, type, "var", "") elif (type == "access"): add_AL_links(model, todo, elem, type, "var", "") elif (type == "constant"): add_AL_links(model, todo, elem, type, "node", "") elif (type == "output"): add_AL_links(model, todo, elem, type, "node", "") add_AL_links(model, todo, elem, type, "next", "") elif (type == "global"): add_AL_links(model, todo, elem, type, "var", "String") add_AL_links(model, todo, elem, type, "next", "") elif (type == "param"): add_AL_links(model, todo, elem, type, "name", "String") add_AL_links(model, todo, elem, type, "value", "") add_AL_links(model, todo, elem, type, "next_param", "param") elif (type == "funcdef"): add_AL_links(model, todo, elem, type, "body", "") add_AL_links(model, todo, elem, type, "next", "") elif (type == "call"): add_AL_links(model, todo, elem, type, "func", "") add_AL_links(model, todo, elem, type, "params", "param") add_AL_links(model, todo, elem, type, "last_param", "param") add_AL_links(model, todo, elem, type, "next", "") return reverseKeyLookup(model["model"], element)! Void function add_constraint(model : Element, element : String, constraint : Action): // Add local constraints to an element Element attr_type String link_name String constraint_name constraint_name = add_AL(model, constraint) attr_type = find_attribute_type(model, element, "constraint") instantiate_link(model, attr_type, "", element, constraint_name) return! Void function construct_model(): String command log("Constructing model") initialize_SCD("models/SimpleClassDiagrams") while (True): command = input() if (command == "instantiate_bottom"): Element m m = instantiate_bottom() dict_add(global_models, input(), m) elif (command == "add_node"): model_add_node(global_models[input()], input()) elif (command == "add_value"): model_add_value(global_models[input()], input(), input()) elif (command == "add_edge"): model_add_edge(global_models[input()], input(), input(), input()) elif (command == "exit"): return! elif (command == "retype_model"): retype_model(global_models[input()], global_models[input()]) elif (command == "retype"): retype(global_models[input()], input(), input()) elif (command == "instantiate_model"): Element m m = instantiate_model(global_models[input()]) dict_add(global_models, input(), m) elif (command == "instantiate_node"): instantiate_node(global_models[input()], input(), input()) elif (command == "instantiate_attribute"): instantiate_attribute(global_models[input()], input(), input(), input()) elif (command == "instantiate_attribute_ref"): instantiate_attribute_ref(global_models[input()], input(), input(), input()) elif (command == "instantiate_attribute_code"): instantiate_attribute_code(global_models[input()], input(), input(), construct_function()) elif (command == "instantiate_link"): instantiate_link(global_models[input()], input(), input(), input(), input()) elif (command == "add_constraint"): add_constraint(global_models[input()], input(), construct_function()) elif (command == "initialize_SCD"): initialize_SCD(input()) elif (command == "initialize_bottom"): initialize_bottom(input()) elif (command == "export_node"): String local_name String location local_name = input() location = input() export_node(location, global_models[local_name]) elif (command == "import_node"): Element m command = input() m = import_node(command) if (element_eq(m, read_root())): log("Error: import not found for " + command) else: dict_add(global_models, input(), m) else: log("Modelling error: did not understand command " + command) Element function construct_model_raw(metamodel : Element): String command Element model model = instantiate_model(metamodel) while (True): command = input() if (command == "add_node"): model_add_node(model, input()) elif (command == "add_value"): model_add_value(model, input(), input()) elif (command == "add_edge"): model_add_edge(model, input(), input(), input()) elif (command == "exit"): return model! elif (command == "instantiate_node"): instantiate_node(model, input(), input()) elif (command == "instantiate_attribute"): instantiate_attribute(model, input(), input(), input()) elif (command == "instantiate_attribute_ref"): instantiate_attribute_ref(model, input(), input(), input()) elif (command == "instantiate_attribute_code"): instantiate_attribute_code(model, input(), input(), construct_function()) elif (command == "instantiate_link"): instantiate_link(model, input(), input(), input(), input()) elif (command == "add_constraint"): add_constraint(model, input(), construct_function()) else: log("Modelling error: did not understand command " + command)