include "primitives.alh" include "io.alh" include "object_operations.alh" include "constructors.alh" include "metamodels.alh" include "library.alh" include "typing.alh" include "utils.alh" Element global_models = ? String function instantiated_name(element : Element, original : String): if (original == ""): return "__" + cast_id(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 = dict_create() // Add an empty model and empty type mapping dict_add_fast(new_model, "model", dict_create()) // 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_fast(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_fast(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_fast(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 new_type_mapping(model) dict_add_fast(model, "metamodel", metamodel) 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 reuse_element(model : Element, type_name : String, instance_name : String, element : Element): String actual_name if (bool_not(dict_in(model["metamodel"]["model"], type_name))): log("ERROR: (instantiate_node) no such type in metamodel: " + type_name) log(" for " + instance_name) return ""! actual_name = instantiated_name(element, instance_name) dict_add(model["model"], actual_name, element) retype(model, actual_name, type_name) return actual_name! String function instantiate_node(model : Element, type_name : String, instance_name : String): String actual_name if (bool_not(dict_in(model["metamodel"]["model"], type_name))): log("ERROR: (instantiate_node) no such type in metamodel: " + type_name) log(" for " + instance_name) return ""! Element value value = create_node() actual_name = instantiated_name(value, instance_name) dict_add_fast(model["model"], actual_name, value) retype(model, actual_name, type_name) return actual_name! String function instantiate_value(model : Element, type_name : String, instance_name : String, value : Element): String actual_name if (bool_not(dict_in(model["metamodel"]["model"], type_name))): log("ERROR: (instantiate_value) no such type in metamodel: " + type_name) log(" for " + instance_name) return ""! actual_name = instantiated_name(value, instance_name) dict_add_fast(model["model"], actual_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 String result direct_type = read_type(model, elem) if (direct_type == ""): return ""! mm_elem = find_attribute_definer(model["metamodel"], direct_type, name) if (mm_elem == ""): // Couldn't find element, so is not allowed! return ""! else: result = reverseKeyLookup(model["metamodel"]["model"], dict_read_edge(model["metamodel"]["model"][mm_elem], name)) return result! Element function get_subclasses(model : Element, name : String): Element result Integer i Integer j Integer num_edges Element edge String elem Element nodes nodes = set_create() set_add(nodes, name) // Initialize empty set result = set_create() while (set_len(nodes) > 0): elem = set_pop(nodes) if (bool_not(set_in(result, elem))): set_add(result, elem) // Read out all incoming edges num_edges = read_nr_in(model["model"][elem]) j = 0 while (j < num_edges): edge = read_in(model["model"][elem], j) if (dict_in(model["model"], reverseKeyLookup(model["model"], edge))): if (read_type(model, reverseKeyLookup(model["model"], edge)) == "Inheritance"): set_add(nodes, reverseKeyLookup(model["model"], read_edge_src(edge))) j = j + 1 return result! Element function get_superclasses(model : Element, name : String): Element result Integer j Integer num_edges Element edge String elem Element nodes String edge_name nodes = set_create() set_add(nodes, name) // Initialize empty set result = set_create() while (set_len(nodes) > 0): elem = set_pop(nodes) if (bool_not(set_in(result, elem))): set_add(result, elem) // Read out all outgoing edges num_edges = read_nr_out(model["model"][elem]) j = 0 while (j < num_edges): edge = read_out(model["model"][elem], j) edge_name = reverseKeyLookup(model["model"], edge) if (edge_name != ""): if (read_type(model, edge_name) == "Inheritance"): set_add(nodes, reverseKeyLookup(model["model"], 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 String elem superclasses = get_superclasses(model, elem_name) while (set_len(superclasses) > 0): current = set_pop(superclasses) // TODO is it possible to use allOutgoingAssociationInstances here? 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) elem = reverseKeyLookup(model["model"], out) if (elem != ""): name_attr = read_attribute(model, elem, "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 if (element_neq(read_attribute(model, element, attribute_name), read_root())): unset_attribute(model, element, attribute_name) attr_type = find_attribute_type(model, element, attribute_name) if (attr_type == ""): return! if (has_value(value)): 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_value(attribute_name)) return! instantiate_link(model, attr_type, "", element, ref) return! Void function add_code_model(model : Element, export_name : String, code : Element): Element code_model code_model = instantiate_model(model) add_AL(code_model, code) export_node(export_name, code_model) return ! Void function instantiate_attribute_code(model : Element, element : String, attribute_name : String, code : Element): // First create a new model for the AL part String location location = "code/" + cast_id(code) add_code_model(import_node("models/ActionLanguage"), location, code) // Now link it with a complex attribute instantiate_attribute(model, element, attribute_name, location) 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_value(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 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 (set_len(options) == 1): type = set_pop(options) elif (set_len(options) == 0): log("ERROR: cannot find possible link between entries") log(" for " + source) log(" to " + destination) return ""! else: log("ERROR: too many possible links between entries") log(" options: " + set_to_string(options)) return ""! if (bool_not(dict_in(model["model"], source))): log("ERROR: source of link undefined: " + source) set_pop(create_node()) return ""! if (bool_not(dict_in(model["model"], destination))): log("ERROR: destination of link undefined: " + destination) set_pop(create_node()) return ""! if (bool_not(dict_in(model["metamodel"]["model"], type))): log("ERROR: (instantiate_link) no such type in metamodel: " + type) log(" for " + name) return ""! Element v v = create_edge(model["model"][source], model["model"][destination]) actual_name = instantiated_name(v, name) dict_add_fast(model["model"], actual_name, v) retype(model, actual_name, type) return actual_name! Void function model_delete_element(model : Element, name : String): // Delete all attributes //Element attrs //String attr //attrs = dict_keys(getAttributeList(model, name)) //while (set_len(attrs) > 0): // attr = set_pop(attrs) // log("Remove attr " + attr) // attr = reverseKeyLookup(model["model"], read_attribute(model, name, attr)) // remove_type(model, attr) // delete_element(model["model"][attr]) // Delete element itself remove_type(model, name) delete_element(model["model"][name]) return! String function model_undefine_attribute(model : Element, elem : String, attr_name : String): String attr_edge attr_edge = reverseKeyLookup(model["model"], dict_read_edge(model["model"][elem], attr_name)) unset_attribute(model, attr_edge, "name") unset_attribute(model, attr_edge, "optional") model_delete_element(model, attr_edge) return attr_edge! String function model_define_attribute(model : Element, elem : String, name : String, optional : Boolean, type : String): // Create the necessary links to make it an attribute String edge_name edge_name = (elem + "_") + name while (dict_in(model["model"], edge_name)): // Already exists, so make random name edge_name = edge_name + cast_id(model["model"][elem]) log("Name clash detected for attribute: try new name: " + edge_name) edge_name = instantiate_link(model, "AttributeLink", edge_name, elem, type) instantiate_attribute(model, edge_name, "name", name) instantiate_attribute(model, edge_name, "optional", optional) return edge_name! String function model_define_attribute_ID(model : Element, elem : String, name : String, optional : Boolean, type : String, ID : String): // Create the necessary links to make it an attribute String edge_name edge_name = ID while (dict_in(model["model"], edge_name)): // Already exists, so make random name edge_name = edge_name + cast_id(model["model"][elem]) log("Name clash detected for attribute: try new name: " + edge_name) edge_name = instantiate_link(model, "AttributeLink", edge_name, elem, type) instantiate_attribute(model, edge_name, "name", name) instantiate_attribute(model, edge_name, "optional", optional) return edge_name! Element function read_attribute(model : Element, element : String, attribute : String): if (dict_in(model["model"], element)): Integer i Integer count Element edge Element edge_type Element elem String name elem = model["model"][element] count = read_nr_out(elem) i = 0 while (i < count): edge = read_out(elem, i) name = reverseKeyLookup(model["model"], edge) if (name != ""): edge_type = model["metamodel"]["model"][read_type(model, name)] if (element_eq(edge_type, dict_read_edge(read_edge_src(edge_type), attribute))): return read_edge_dst(edge)! i = i + 1 else: log("Element does not exist: " + element) // Not found: either element doesn't exist, or we couldn't find it 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 String attr_value attr_type = find_attribute_type(model, element, attribute) attr_links = allOutgoingAssociationInstances(model, element, attr_type) while (set_len(attr_links) > 0): attr_link = set_pop(attr_links) attr_value = readAssociationDestination(model, attr_link) remove_type(model, attr_link) if (dict_in(model["model"], attr_value)): remove_type(model, attr_value) dict_delete(model["model"], attr_value) 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 if (linkname == "next"): type = "Statement" reuse_element(model, (type + "_") + linkname, "", link) // The name link link = read_out(link, 0) reuse_element(model, "dict_link_name", "", link) // The name node String link_name link = read_edge_dst(link) link_name = "__" + cast_id(link) if (bool_not(dict_in(model["model"], link_name))): reuse_element(model, "StringAttr", link_name, link) // Now add the destination to the worker list set_add_node(list, create_tuple(element[linkname], expected_type)) return! String function add_AL(model : Element, element : Element): Element todo Element node Element work_node Element elem String type String elem_name todo = set_create() set_add_node(todo, create_tuple(element, "funcdef")) while (0 < dict_len(todo)): work_node = set_pop(todo) elem = list_read(work_node, 0) type = list_read(work_node, 1) elem_name = "__" + cast_id(elem) if (bool_not(set_in(model["model"], elem_name))): // Determine the type if we don't know it if (type == ""): if (is_physical_action(elem)): type = cast_value(elem) else: type = "Element" // Add the node itself reuse_element(model, type, elem_name, elem) // 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", "resolve") 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", "resolve") 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", "") // TODO this should be added, but is not the same as "param" //add_AL_links(model, todo, elem, type, "params", "") 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", "") // Mark the node as first String initial initial = instantiate_node(model, "Initial", "") instantiate_link(model, "initial_funcdef", "", initial, reverseKeyLookup(model["model"], element)) return reverseKeyLookup(model["model"], element)! Element function get_func_AL_model(al_model : Element): Element initial_function // Find the initial function initial_function = allInstances(al_model, "Initial") if (set_len(initial_function) == 0): log("Could not find function to execute in this model!") return read_root()! elif (set_len(initial_function) > 1): log("Too many functions to execute in this model!") return read_root()! else: return al_model["model"][set_pop(allAssociationDestinations(al_model, set_pop(initial_function), "initial_funcdef"))]! Element function trim_AL_constructors(list : Element): Integer length Element lst Integer i length = list_pop_final(list) i = 0 lst = list_create() while (i < length): list_append(lst, list_pop_final(list)) i = i + 1 return lst! Element function construct_model_list(model : Element, list : Element): String command list = list_reverse(list) while (list_len(list) > 0): command = list_pop_final(list) if (command == "add_node"): model_add_node(model, list_pop_final(list)) elif (command == "add_value"): model_add_value(model, list_pop_final(list), list_pop_final(list)) elif (command == "add_edge"): model_add_edge(model, list_pop_final(list), list_pop_final(list), list_pop_final(list)) elif (command == "instantiate_node"): instantiate_node(model, list_pop_final(list), list_pop_final(list)) elif (command == "model_define_attribute"): model_define_attribute(model, list_pop_final(list), list_pop_final(list), list_pop_final(list), list_pop_final(list)) elif (command == "instantiate_attribute"): instantiate_attribute(model, list_pop_final(list), list_pop_final(list), list_pop_final(list)) elif (command == "instantiate_attribute_ref"): instantiate_attribute_ref(model, list_pop_final(list), list_pop_final(list), list_pop_final(list)) elif (command == "instantiate_attribute_code"): instantiate_attribute_code(model, list_pop_final(list), list_pop_final(list), construct_function_list(trim_AL_constructors(list))) elif (command == "instantiate_link"): instantiate_link(model, list_pop_final(list), list_pop_final(list), list_pop_final(list), list_pop_final(list)) elif (command == "add_code_model"): add_code_model(model, list_pop_final(list), construct_function_list(trim_AL_constructors(list))) else: log("Modelling error: did not understand command " + command) return model!