Add ActionCode primitive type. Fix constraint checking.
This commit is contained in:
parent
0785b9218e
commit
59de61d0a3
11 changed files with 256 additions and 82 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
from state.base import State, UUID
|
from state.base import State, UUID
|
||||||
from services.bottom.V0 import Bottom
|
from services.bottom.V0 import Bottom
|
||||||
from services.primitives.integer_type import Integer
|
from services.primitives.integer_type import Integer
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_type(type_name: str, python_type: str, scd_root: UUID, model_root: UUID, state: State):
|
def bootstrap_type(type_name: str, scd_root: UUID, model_root: UUID, integer_type: UUID, state: State):
|
||||||
bottom = Bottom(state)
|
bottom = Bottom(state)
|
||||||
# create class
|
# create class
|
||||||
class_node = bottom.create_node() # create class node
|
class_node = bottom.create_node() # create class node
|
||||||
|
|
@ -17,7 +18,7 @@ def bootstrap_type(type_name: str, python_type: str, scd_root: UUID, model_root:
|
||||||
bottom.create_edge(model_root, min_c_node, f"{type_name}.lower_cardinality")
|
bottom.create_edge(model_root, min_c_node, f"{type_name}.lower_cardinality")
|
||||||
min_c_link = bottom.create_edge(class_node, min_c_node)
|
min_c_link = bottom.create_edge(class_node, min_c_node)
|
||||||
bottom.create_edge(model_root, min_c_link, f"{type_name}_lower_cardinality")
|
bottom.create_edge(model_root, min_c_link, f"{type_name}_lower_cardinality")
|
||||||
scd_node, = bottom.read_outgoing_elements(scd_root, "Integer")
|
scd_node = integer_type
|
||||||
scd_link, = bottom.read_outgoing_elements(scd_root, "Class_lower_cardinality")
|
scd_link, = bottom.read_outgoing_elements(scd_root, "Class_lower_cardinality")
|
||||||
bottom.create_edge(min_c_node, scd_node, "Morphism")
|
bottom.create_edge(min_c_node, scd_node, "Morphism")
|
||||||
bottom.create_edge(min_c_link, scd_link, "Morphism")
|
bottom.create_edge(min_c_link, scd_link, "Morphism")
|
||||||
|
|
@ -28,36 +29,61 @@ def bootstrap_type(type_name: str, python_type: str, scd_root: UUID, model_root:
|
||||||
bottom.create_edge(model_root, max_c_node, f"{type_name}.upper_cardinality")
|
bottom.create_edge(model_root, max_c_node, f"{type_name}.upper_cardinality")
|
||||||
max_c_link = bottom.create_edge(class_node, max_c_node)
|
max_c_link = bottom.create_edge(class_node, max_c_node)
|
||||||
bottom.create_edge(model_root, max_c_link, f"{type_name}_upper_cardinality")
|
bottom.create_edge(model_root, max_c_link, f"{type_name}_upper_cardinality")
|
||||||
scd_node, = bottom.read_outgoing_elements(scd_root, "Integer")
|
scd_node = integer_type
|
||||||
scd_link, = bottom.read_outgoing_elements(scd_root, "Class_upper_cardinality")
|
scd_link, = bottom.read_outgoing_elements(scd_root, "Class_upper_cardinality")
|
||||||
bottom.create_edge(max_c_node, scd_node, "Morphism")
|
bottom.create_edge(max_c_node, scd_node, "Morphism")
|
||||||
bottom.create_edge(max_c_link, scd_link, "Morphism")
|
bottom.create_edge(max_c_link, scd_link, "Morphism")
|
||||||
|
return class_node
|
||||||
|
|
||||||
|
def bootstrap_constraint(class_node, type_name: str, python_type: str, scd_root: UUID, model_root: UUID, actioncode_type: UUID, state: State):
|
||||||
|
|
||||||
# set constraint
|
# set constraint
|
||||||
constraint_node = bottom.create_node(f"isinstance(read_value(element),{python_type})")
|
# chicken-and-egg problem: we cannot create an action-code constraint because the action-code MM doesn't exist yet
|
||||||
|
|
||||||
|
bottom = Bottom(state)
|
||||||
|
constraint_model = bottom.create_node()
|
||||||
|
ActionCode(constraint_model, state).create(f"isinstance(read_value(element),{python_type})")
|
||||||
|
constraint_node = bottom.create_node(str(constraint_model))
|
||||||
bottom.create_edge(model_root, constraint_node, f"{type_name}.constraint")
|
bottom.create_edge(model_root, constraint_node, f"{type_name}.constraint")
|
||||||
constraint_link = bottom.create_edge(class_node, constraint_node)
|
constraint_link = bottom.create_edge(class_node, constraint_node)
|
||||||
bottom.create_edge(model_root, constraint_link, f"{type_name}_constraint")
|
bottom.create_edge(model_root, constraint_link, f"{type_name}_constraint")
|
||||||
scd_node, = bottom.read_outgoing_elements(scd_root, "ActionCode")
|
scd_node = actioncode_type
|
||||||
scd_link, = bottom.read_outgoing_elements(scd_root, "Element_constraint")
|
scd_link, = bottom.read_outgoing_elements(scd_root, "Element_constraint")
|
||||||
bottom.create_edge(constraint_node, scd_node, "Morphism")
|
bottom.create_edge(constraint_node, scd_node, "Morphism")
|
||||||
bottom.create_edge(constraint_link, scd_link, "Morphism")
|
bottom.create_edge(constraint_link, scd_link, "Morphism")
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_type_type(scd_root: UUID, model_root: UUID, state: State):
|
# def bootstrap_type_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
bootstrap_type("Type", "tuple", scd_root, model_root, state)
|
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_boolean_type(scd_root: UUID, model_root: UUID, state: State):
|
# def bootstrap_boolean_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
bootstrap_type("Boolean", "bool", scd_root, model_root, state)
|
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_integer_type(scd_root: UUID, model_root: UUID, state: State):
|
# def bootstrap_integer_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
bootstrap_type("Integer", "int", scd_root, model_root, state)
|
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_float_type(scd_root: UUID, model_root: UUID, state: State):
|
# def bootstrap_float_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
bootstrap_type("Float", "float", scd_root, model_root, state)
|
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_string_type(scd_root: UUID, model_root: UUID, state: State):
|
# def bootstrap_string_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
bootstrap_type("String", "str", scd_root, model_root, state)
|
|
||||||
|
# def bootstrap_actioncode_type(scd_root: UUID, model_root: UUID, integer_type: UUID, actioncode_type: UUID, state: State):
|
||||||
|
# # we store action code as Python string:
|
||||||
|
|
||||||
|
def bootstrap_primitive_types(scd_root, state, integer_type, boolean_type, float_type, string_type, type_type, actioncode_type):
|
||||||
|
# Order is important: Integer must come first
|
||||||
|
class_integer = bootstrap_type("Integer", scd_root, integer_type, integer_type, state)
|
||||||
|
class_type = bootstrap_type("Type", scd_root, type_type, integer_type, state)
|
||||||
|
class_boolean = bootstrap_type("Boolean", scd_root, boolean_type, integer_type, state)
|
||||||
|
class_float = bootstrap_type("Float", scd_root, float_type, integer_type, state)
|
||||||
|
class_string = bootstrap_type("String", scd_root, string_type, integer_type, state)
|
||||||
|
class_actioncode = bootstrap_type("ActionCode", scd_root, actioncode_type, integer_type, state)
|
||||||
|
|
||||||
|
# Can only create constraints after ActionCode type has been created:
|
||||||
|
bootstrap_constraint(class_integer, "Integer", "int", scd_root, integer_type, actioncode_type, state)
|
||||||
|
bootstrap_constraint(class_type, "Type", "tuple", scd_root, type_type, actioncode_type, state)
|
||||||
|
bootstrap_constraint(class_boolean, "Boolean", "bool", scd_root, boolean_type, actioncode_type, state)
|
||||||
|
bootstrap_constraint(class_float, "Float", "float", scd_root, float_type, actioncode_type, state)
|
||||||
|
bootstrap_constraint(class_string, "String", "str", scd_root, string_type, actioncode_type, state)
|
||||||
|
bootstrap_constraint(class_actioncode, "ActionCode", "str", scd_root, actioncode_type, actioncode_type, state)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@ from services.bottom.V0 import Bottom
|
||||||
from services.primitives.boolean_type import Boolean
|
from services.primitives.boolean_type import Boolean
|
||||||
from services.primitives.string_type import String
|
from services.primitives.string_type import String
|
||||||
from bootstrap.primitive import (
|
from bootstrap.primitive import (
|
||||||
bootstrap_boolean_type,
|
bootstrap_primitive_types
|
||||||
bootstrap_float_type,
|
# bootstrap_boolean_type,
|
||||||
bootstrap_integer_type,
|
# bootstrap_float_type,
|
||||||
bootstrap_string_type,
|
# bootstrap_integer_type,
|
||||||
bootstrap_type_type
|
# bootstrap_string_type,
|
||||||
|
# bootstrap_type_type,
|
||||||
|
# bootstrap_actioncode_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,6 +31,7 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
string_type_root = create_model_root(bottom, "String")
|
string_type_root = create_model_root(bottom, "String")
|
||||||
float_type_root = create_model_root(bottom, "Float")
|
float_type_root = create_model_root(bottom, "Float")
|
||||||
type_type_root = create_model_root(bottom, "Type")
|
type_type_root = create_model_root(bottom, "Type")
|
||||||
|
actioncode_type_root = create_model_root(bottom, "ActionCode")
|
||||||
|
|
||||||
# create MCL, without morphism links
|
# create MCL, without morphism links
|
||||||
|
|
||||||
|
|
@ -91,7 +94,7 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
|
|
||||||
# # ATTRIBUTES, i.e. elements typed by Attribute
|
# # ATTRIBUTES, i.e. elements typed by Attribute
|
||||||
# # Action Code # TODO: Update to ModelRef when action code is explicitly modelled
|
# # Action Code # TODO: Update to ModelRef when action code is explicitly modelled
|
||||||
action_code_node = add_node_element("ActionCode")
|
# action_code_node = add_node_element("ActionCode")
|
||||||
|
|
||||||
# # MODELREFS, i.e. elements typed by ModelRef
|
# # MODELREFS, i.e. elements typed by ModelRef
|
||||||
# # Integer
|
# # Integer
|
||||||
|
|
@ -100,6 +103,8 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
string_node = add_node_element("String", str(string_type_root))
|
string_node = add_node_element("String", str(string_type_root))
|
||||||
# # Boolean
|
# # Boolean
|
||||||
boolean_node = add_node_element("Boolean", str(boolean_type_root))
|
boolean_node = add_node_element("Boolean", str(boolean_type_root))
|
||||||
|
# # ActionCode
|
||||||
|
actioncode_node = add_node_element("ActionCode", str(actioncode_type_root))
|
||||||
|
|
||||||
# # ATTRIBUTE LINKS, i.e. elements typed by AttributeLink
|
# # ATTRIBUTE LINKS, i.e. elements typed by AttributeLink
|
||||||
# # name attribute of AttributeLink
|
# # name attribute of AttributeLink
|
||||||
|
|
@ -107,7 +112,7 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
# # optional attribute of AttributeLink
|
# # optional attribute of AttributeLink
|
||||||
attr_opt_edge = add_edge_element("AttributeLink_optional", attr_link_edge, boolean_node)
|
attr_opt_edge = add_edge_element("AttributeLink_optional", attr_link_edge, boolean_node)
|
||||||
# # constraint attribute of Element
|
# # constraint attribute of Element
|
||||||
elem_constr_edge = add_edge_element("Element_constraint", element_node, action_code_node)
|
elem_constr_edge = add_edge_element("Element_constraint", element_node, actioncode_node)
|
||||||
# # abstract attribute of Class
|
# # abstract attribute of Class
|
||||||
class_abs_edge = add_edge_element("Class_abstract", class_node, boolean_node)
|
class_abs_edge = add_edge_element("Class_abstract", class_node, boolean_node)
|
||||||
# # multiplicity attributes of Class
|
# # multiplicity attributes of Class
|
||||||
|
|
@ -120,12 +125,19 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
assoc_t_u_c_edge = add_edge_element("Association_target_upper_cardinality", assoc_edge, integer_node)
|
assoc_t_u_c_edge = add_edge_element("Association_target_upper_cardinality", assoc_edge, integer_node)
|
||||||
|
|
||||||
# # bootstrap primitive types
|
# # bootstrap primitive types
|
||||||
# # order is important, integer must be first
|
bootstrap_primitive_types(mcl_root, state,
|
||||||
bootstrap_integer_type(mcl_root, integer_type_root, state)
|
integer_type_root,
|
||||||
bootstrap_boolean_type(mcl_root, boolean_type_root, state)
|
boolean_type_root,
|
||||||
bootstrap_float_type(mcl_root, float_type_root, state)
|
float_type_root,
|
||||||
bootstrap_string_type(mcl_root, string_type_root, state)
|
string_type_root,
|
||||||
bootstrap_type_type(mcl_root, type_type_root, state)
|
type_type_root,
|
||||||
|
actioncode_type_root)
|
||||||
|
# bootstrap_integer_type(mcl_root, integer_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
# bootstrap_boolean_type(mcl_root, boolean_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
# bootstrap_float_type(mcl_root, float_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
# bootstrap_string_type(mcl_root, string_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
# bootstrap_type_type(mcl_root, type_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
# bootstrap_actioncode_type(mcl_root, actioncode_type_root, integer_type_root, actioncode_type_root, state)
|
||||||
|
|
||||||
# # ATTRIBUTE ATTRIBUTES, assign 'name' and 'optional' attributes to all AttributeLinks
|
# # ATTRIBUTE ATTRIBUTES, assign 'name' and 'optional' attributes to all AttributeLinks
|
||||||
# # AttributeLink_name
|
# # AttributeLink_name
|
||||||
|
|
@ -203,11 +215,12 @@ def bootstrap_scd(state: State) -> UUID:
|
||||||
add_mcl_morphism("attr_link_inh_element", "Inheritance")
|
add_mcl_morphism("attr_link_inh_element", "Inheritance")
|
||||||
add_mcl_morphism("model_ref_inh_attr", "Inheritance")
|
add_mcl_morphism("model_ref_inh_attr", "Inheritance")
|
||||||
# Attribute
|
# Attribute
|
||||||
add_mcl_morphism("ActionCode", "Attribute")
|
# add_mcl_morphism("ActionCode", "Attribute")
|
||||||
# ModelRef
|
# ModelRef
|
||||||
add_mcl_morphism("Integer", "ModelRef")
|
add_mcl_morphism("Integer", "ModelRef")
|
||||||
add_mcl_morphism("String", "ModelRef")
|
add_mcl_morphism("String", "ModelRef")
|
||||||
add_mcl_morphism("Boolean", "ModelRef")
|
add_mcl_morphism("Boolean", "ModelRef")
|
||||||
|
add_mcl_morphism("ActionCode", "ModelRef")
|
||||||
# AttributeLink
|
# AttributeLink
|
||||||
add_mcl_morphism("AttributeLink_name", "AttributeLink")
|
add_mcl_morphism("AttributeLink_name", "AttributeLink")
|
||||||
add_mcl_morphism("AttributeLink_optional", "AttributeLink")
|
add_mcl_morphism("AttributeLink_optional", "AttributeLink")
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ def render_class_diagram(state, model, prefix_ids=""):
|
||||||
is_abstract = False
|
is_abstract = False
|
||||||
slot = model_od.get_slot(class_node, "abstract")
|
slot = model_od.get_slot(class_node, "abstract")
|
||||||
if slot != None:
|
if slot != None:
|
||||||
is_abstract = od.read_primitive_value(bottom, slot, model_od.type_model)
|
is_abstract, _ = od.read_primitive_value(bottom, slot, model_od.type_model)
|
||||||
|
|
||||||
if is_abstract:
|
if is_abstract:
|
||||||
output += f"\nabstract class \"{name}\" as {make_id(class_node)}"
|
output += f"\nabstract class \"{name}\" as {make_id(class_node)}"
|
||||||
|
|
@ -97,7 +97,7 @@ def render_object_diagram(state, m, mm, render_attributes=True, prefix_ids=""):
|
||||||
for attr_name, attr_edge in attributes:
|
for attr_name, attr_edge in attributes:
|
||||||
slot = m_od.get_slot(obj_node, attr_name)
|
slot = m_od.get_slot(obj_node, attr_name)
|
||||||
if slot != None:
|
if slot != None:
|
||||||
output += f"\n{attr_name} => {json.dumps(od.read_primitive_value(bottom, slot, mm))}"
|
output += f"\n{attr_name} => {json.dumps(od.read_primitive_value(bottom, slot, mm)[0])}"
|
||||||
output += '\n}'
|
output += '\n}'
|
||||||
|
|
||||||
output += '\n'
|
output += '\n'
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@ _NL: /(\r?\n[\t ]*)+/
|
||||||
literal: INT
|
literal: INT
|
||||||
| STR
|
| STR
|
||||||
| BOOL
|
| BOOL
|
||||||
|
| CODE
|
||||||
|
|
||||||
INT: /[0-9]+/
|
INT: /[0-9]+/
|
||||||
STR: /"[^"]*"/
|
STR: /"[^"]*"/
|
||||||
| /'[^']*'/
|
| /'[^']*'/
|
||||||
BOOL: "True" | "False"
|
BOOL: "True" | "False"
|
||||||
|
CODE: /`[^`]*`/
|
||||||
|
|
||||||
object: [IDENTIFIER] ":" IDENTIFIER [link_spec] _NL [_INDENT slot+ _DEDENT]
|
object: [IDENTIFIER] ":" IDENTIFIER [link_spec] _NL [_INDENT slot+ _DEDENT]
|
||||||
link_spec: "(" IDENTIFIER "->" IDENTIFIER ")"
|
link_spec: "(" IDENTIFIER "->" IDENTIFIER ")"
|
||||||
|
|
@ -46,6 +48,12 @@ class TreeIndenter(Indenter):
|
||||||
|
|
||||||
parser = Lark(grammar, parser='lalr', postlex=TreeIndenter())
|
parser = Lark(grammar, parser='lalr', postlex=TreeIndenter())
|
||||||
|
|
||||||
|
# internal use only
|
||||||
|
# just a dumb wrapper to distinguish between code and string
|
||||||
|
class _Code:
|
||||||
|
def __init__(self, code):
|
||||||
|
self.code = code
|
||||||
|
|
||||||
# given a concrete syntax text string, and a meta-model, parses the CS
|
# given a concrete syntax text string, and a meta-model, parses the CS
|
||||||
def parse_od(state, cs_text, mm):
|
def parse_od(state, cs_text, mm):
|
||||||
tree = parser.parse(cs_text)
|
tree = parser.parse(cs_text)
|
||||||
|
|
@ -70,7 +78,10 @@ def parse_od(state, cs_text, mm):
|
||||||
return token == "True"
|
return token == "True"
|
||||||
|
|
||||||
def STR(self, token):
|
def STR(self, token):
|
||||||
return str(token[1:-1]) # strip the ""
|
return str(token[1:-1]) # strip the "" or ''
|
||||||
|
|
||||||
|
def CODE(self, token):
|
||||||
|
return _Code(str(token[1:-1])) # strip the ``
|
||||||
|
|
||||||
def literal(self, el):
|
def literal(self, el):
|
||||||
return el[0]
|
return el[0]
|
||||||
|
|
@ -111,9 +122,12 @@ def parse_od(state, cs_text, mm):
|
||||||
tgt = od.create_integer_value(value_name, value)
|
tgt = od.create_integer_value(value_name, value)
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
tgt = od.create_string_value(value_name, value)
|
tgt = od.create_string_value(value_name, value)
|
||||||
|
elif isinstance(value, _Code):
|
||||||
|
tgt = od.create_actioncode_value(value_name, value.code)
|
||||||
else:
|
else:
|
||||||
raise Exception("Unimplemented type "+value)
|
raise Exception("Unimplemented type "+value)
|
||||||
od.create_slot(attr_name, obj_name, tgt)
|
od.create_slot(attr_name, obj_name, tgt)
|
||||||
|
|
||||||
return obj_name
|
return obj_name
|
||||||
|
|
||||||
t = T(visit_tokens=True).transform(tree)
|
t = T(visit_tokens=True).transform(tree)
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,15 @@ from services import od
|
||||||
from services.bottom.V0 import Bottom
|
from services.bottom.V0 import Bottom
|
||||||
import json
|
import json
|
||||||
|
|
||||||
def display_value(val: any):
|
def display_value(val: any, type_name: str):
|
||||||
if isinstance(val, str):
|
if type_name == "ActionCode":
|
||||||
|
return '`'+val+'`'
|
||||||
|
elif type_name == "String":
|
||||||
return '"'+val+'"'
|
return '"'+val+'"'
|
||||||
elif isinstance(val, int) or isinstance(val, bool):
|
elif type_name == "Integer" or type_name == "Boolean":
|
||||||
return str(val)
|
return str(val)
|
||||||
else:
|
else:
|
||||||
raise Exception("don't know how to display value" + str(val))
|
raise Exception("don't know how to display value" + type_name)
|
||||||
|
|
||||||
def render_od(state, m_id, mm_id, hide_names=True):
|
def render_od(state, m_id, mm_id, hide_names=True):
|
||||||
bottom = Bottom(state)
|
bottom = Bottom(state)
|
||||||
|
|
@ -25,8 +27,8 @@ def render_od(state, m_id, mm_id, hide_names=True):
|
||||||
def write_attributes(object_node):
|
def write_attributes(object_node):
|
||||||
o = ""
|
o = ""
|
||||||
for attr_name, slot_node in m_od.get_slots(object_node):
|
for attr_name, slot_node in m_od.get_slots(object_node):
|
||||||
value = m_od.read_slot(slot_node)
|
value, type_name = m_od.read_slot(slot_node)
|
||||||
o += f" {attr_name} = {display_value(value)}\n"
|
o += f" {attr_name} = {display_value(value, type_name)}\n"
|
||||||
return o
|
return o
|
||||||
|
|
||||||
for class_name, objects in m_od.get_all_objects().items():
|
for class_name, objects in m_od.get_all_objects().items():
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ def main():
|
||||||
|
|
||||||
conf = Conformance(state, scd_mm_id, scd_mm_id)
|
conf = Conformance(state, scd_mm_id, scd_mm_id)
|
||||||
print("Conformance SCD_MM -> SCD_MM?", conf.check_nominal(log=True))
|
print("Conformance SCD_MM -> SCD_MM?", conf.check_nominal(log=True))
|
||||||
# print("--------------------------------------")
|
print("--------------------------------------")
|
||||||
# print(renderer.render_od(state, scd_mm_id, scd_mm_id, hide_names=False))
|
print(renderer.render_od(state, scd_mm_id, scd_mm_id, hide_names=False))
|
||||||
# print("--------------------------------------")
|
print("--------------------------------------")
|
||||||
|
|
||||||
def create_dsl_mm_api():
|
def create_dsl_mm_api():
|
||||||
# Create DSL MM with SCD API
|
# Create DSL MM with SCD API
|
||||||
|
|
@ -54,6 +54,7 @@ def main():
|
||||||
tgt_min_c=1,
|
tgt_min_c=1,
|
||||||
tgt_max_c=None,
|
tgt_max_c=None,
|
||||||
)
|
)
|
||||||
|
dsl_mm_scd.add_constraint("Man", "read_value(element) < 100")
|
||||||
return dsl_mm_id
|
return dsl_mm_id
|
||||||
|
|
||||||
def create_dsl_mm_parser():
|
def create_dsl_mm_parser():
|
||||||
|
|
@ -66,13 +67,17 @@ Animal:Class
|
||||||
Man:Class
|
Man:Class
|
||||||
lower_cardinality = 1
|
lower_cardinality = 1
|
||||||
upper_cardinality = 2
|
upper_cardinality = 2
|
||||||
|
# constraint = `get_value(get_slot(element, "weight")) < 100`
|
||||||
Man_weight:AttributeLink (Man -> Integer)
|
Man_weight:AttributeLink (Man -> Integer)
|
||||||
name = "weight"
|
name = "weight"
|
||||||
optional = False
|
optional = False
|
||||||
|
constraint = `get_value(get_target(element)) < 100`
|
||||||
afraidOf:Association (Man -> Animal)
|
afraidOf:Association (Man -> Animal)
|
||||||
target_lower_cardinality = 1
|
target_lower_cardinality = 1
|
||||||
Man_inh_Animal:Inheritance (Man -> Animal)
|
Man_inh_Animal:Inheritance (Man -> Animal)
|
||||||
Bear_inh_Animal:Inheritance (Bear -> Animal)
|
Bear_inh_Animal:Inheritance (Bear -> Animal)
|
||||||
|
sum_of_weights:GlobalConstraint
|
||||||
|
constraint = `len(get_all_instances("afraidOf")) <= 1`
|
||||||
"""
|
"""
|
||||||
dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mm_id)
|
dsl_mm_id = parser.parse_od(state, dsl_mm_cs, mm=scd_mm_id)
|
||||||
return dsl_mm_id
|
return dsl_mm_id
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from services.bottom.V0 import Bottom
|
from services.bottom.V0 import Bottom
|
||||||
|
from services import od
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from state.base import State
|
from state.base import State
|
||||||
from typing import Dict, Tuple, Set, Any, List
|
from typing import Dict, Tuple, Set, Any, List
|
||||||
|
|
@ -99,7 +101,7 @@ class Conformance:
|
||||||
model = self.model
|
model = self.model
|
||||||
try:
|
try:
|
||||||
attr_elem, = self.bottom.read_outgoing_elements(model, f"{element_name}.{attr_name}")
|
attr_elem, = self.bottom.read_outgoing_elements(model, f"{element_name}.{attr_name}")
|
||||||
return self.primitive_values.get(attr_elem, self.bottom.read_value(attr_elem))
|
return self.primitive_values.get(attr_elem, self.bottom.read_value(UUID(self.bottom.read_value(attr_elem))))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -357,42 +359,82 @@ class Conformance:
|
||||||
"""
|
"""
|
||||||
Evaluate constraint code (Python code)
|
Evaluate constraint code (Python code)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
funcs = {
|
funcs = {
|
||||||
'read_value': self.state.read_value
|
'read_value': self.state.read_value,
|
||||||
|
'get_value': lambda el: od.read_primitive_value(self.bottom, el, self.type_model)[0],
|
||||||
|
'get_target': lambda el: self.bottom.read_edge_target(el),
|
||||||
|
'get_slot': od.OD(self.type_model, self.model, self.state).get_slot,
|
||||||
|
'get_all_instances': self.get_all_instances
|
||||||
}
|
}
|
||||||
return eval(
|
# print("evaluating constraint ...", code)
|
||||||
|
result = eval(
|
||||||
code,
|
code,
|
||||||
{'__builtins__': {'isinstance': isinstance, 'print': print,
|
{'__builtins__': {'isinstance': isinstance, 'print': print,
|
||||||
'int': int, 'float': float, 'bool': bool, 'str': str, 'tuple': tuple}
|
'int': int, 'float': float, 'bool': bool, 'str': str, 'tuple': tuple, 'len': len}
|
||||||
}, # globals
|
}, # globals
|
||||||
{**kwargs, **funcs} # locals
|
{**kwargs, **funcs} # locals
|
||||||
)
|
)
|
||||||
|
# print('result =', result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_all_instances(self, type_name: str, include_subtypes=True):
|
||||||
|
result = [e_name for e_name, t_name in self.type_mapping.items() if t_name == type_name]
|
||||||
|
if include_subtypes:
|
||||||
|
for subtype_name in self.sub_types[type_name]:
|
||||||
|
# print(subtype_name, 'is subtype of ')
|
||||||
|
result += [e_name for e_name, t_name in self.type_mapping.items() if t_name == subtype_name]
|
||||||
|
return result
|
||||||
|
|
||||||
def check_constraints(self):
|
def check_constraints(self):
|
||||||
"""
|
"""
|
||||||
Check whether all constraints defined for a model are respected
|
Check whether all constraints defined for a model are respected
|
||||||
"""
|
"""
|
||||||
# local constraints
|
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
|
def get_code(tm_name):
|
||||||
|
constraints = self.bottom.read_outgoing_elements(self.type_model, f"{tm_name}.constraint")
|
||||||
|
if len(constraints) == 1:
|
||||||
|
constraint = constraints[0]
|
||||||
|
code = ActionCode(UUID(self.bottom.read_value(constraint)), self.bottom.state).read()
|
||||||
|
return code
|
||||||
|
|
||||||
|
def check_result(result, local_or_global, tm_name, el_name=None):
|
||||||
|
suffix = f"in '{el_name}'" if local_or_global == "Local" else ""
|
||||||
|
if not isinstance(result, bool):
|
||||||
|
errors.append(f"{local_or_global} constraint `{code}` of '{tm_name}'{suffix} did not return boolean, instead got {type(result)} (value = {str(result)}).")
|
||||||
|
elif not result:
|
||||||
|
errors.append(f"{local_or_global} constraint `{code}` of '{tm_name}'{suffix} not satisfied.")
|
||||||
|
|
||||||
|
# local constraints
|
||||||
for m_name, tm_name in self.type_mapping.items():
|
for m_name, tm_name in self.type_mapping.items():
|
||||||
if tm_name != "GlobalConstraint":
|
code = get_code(tm_name)
|
||||||
tm_element, = self.bottom.read_outgoing_elements(self.type_model, tm_name)
|
|
||||||
code = self.read_attribute(tm_element, "constraint")
|
|
||||||
if code != None:
|
if code != None:
|
||||||
|
tm_element, = self.bottom.read_outgoing_elements(self.type_model, tm_name)
|
||||||
morphisms = self.bottom.read_incoming_elements(tm_element, "Morphism")
|
morphisms = self.bottom.read_incoming_elements(tm_element, "Morphism")
|
||||||
morphisms = [m for m in morphisms if m in self.model_names]
|
morphisms = [m for m in morphisms if m in self.model_names]
|
||||||
for m_element in morphisms:
|
for m_element in morphisms:
|
||||||
if not self.evaluate_constraint(code, element=m_element):
|
result = self.evaluate_constraint(code, element=m_element, type_name=tm_name)
|
||||||
errors.append(f"Local constraint of {tm_name} not satisfied in {m_name}.")
|
check_result(result, "Local", tm_name, m_name)
|
||||||
|
|
||||||
# global constraints
|
# global constraints
|
||||||
for m_name, tm_name in self.type_mapping.items():
|
glob_constraints = []
|
||||||
if tm_name == "GlobalConstraint":
|
# find global constraints...
|
||||||
tm_element, = self.bottom.read_outgoing_elements(self.type_model, tm_name)
|
glob_constraint_type, = self.bottom.read_outgoing_elements(self.scd_model, "GlobalConstraint")
|
||||||
code = self.read_attribute(tm_element, "constraint")
|
for tm_name in self.bottom.read_keys(self.type_model):
|
||||||
|
tm_node, = self.bottom.read_outgoing_elements(self.type_model, tm_name)
|
||||||
|
# print(key, node)
|
||||||
|
for type_of_node in self.bottom.read_outgoing_elements(tm_node, "Morphism"):
|
||||||
|
if type_of_node == glob_constraint_type:
|
||||||
|
# node is GlobalConstraint
|
||||||
|
glob_constraints.append(tm_name)
|
||||||
|
# evaluate them
|
||||||
|
for tm_name in glob_constraints:
|
||||||
|
code = get_code(tm_name)
|
||||||
if code != None:
|
if code != None:
|
||||||
if not self.evaluate_constraint(code, model=self.model):
|
# print('glob constr:', code)
|
||||||
errors.append(f"Global constraint {tm_name} not satisfied.")
|
result = self.evaluate_constraint(code, model=self.model)
|
||||||
|
check_result(result, "Global", tm_name)
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
def precompute_structures(self):
|
def precompute_structures(self):
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ from services.bottom.V0 import Bottom
|
||||||
from services.primitives.integer_type import Integer
|
from services.primitives.integer_type import Integer
|
||||||
from services.primitives.string_type import String
|
from services.primitives.string_type import String
|
||||||
from services.primitives.boolean_type import Boolean
|
from services.primitives.boolean_type import Boolean
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
|
from framework.conformance import Conformance
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
def get_attr_link_name(class_name: str, attr_name: str):
|
def get_slot_link_name(obj_name: str, attr_name: str):
|
||||||
return f"{class_name}_{attr_name}"
|
return f"{obj_name}_{attr_name}"
|
||||||
|
|
||||||
# Object Diagrams service
|
# Object Diagrams service
|
||||||
|
|
||||||
|
|
@ -42,7 +44,7 @@ class OD:
|
||||||
|
|
||||||
slot = mm_od.get_slot(class_node, "abstract")
|
slot = mm_od.get_slot(class_node, "abstract")
|
||||||
if slot != None:
|
if slot != None:
|
||||||
is_abstract = read_primitive_value(self.bottom, slot, self.type_model)
|
is_abstract, _ = read_primitive_value(self.bottom, slot, self.type_model)
|
||||||
if is_abstract:
|
if is_abstract:
|
||||||
raise Exception("Cannot instantiate abstract class!")
|
raise Exception("Cannot instantiate abstract class!")
|
||||||
|
|
||||||
|
|
@ -66,17 +68,17 @@ class OD:
|
||||||
|
|
||||||
def create_slot(self, attr_name: str, object_name: str, target_name: str):
|
def create_slot(self, attr_name: str, object_name: str, target_name: str):
|
||||||
class_name = self.get_class_of_object(object_name)
|
class_name = self.get_class_of_object(object_name)
|
||||||
attr_link_name = get_attr_link_name(class_name, attr_name)
|
attr_link_name = self.get_attr_link_name(class_name, attr_name)
|
||||||
# An attribute-link is indistinguishable from an ordinary link:
|
# An attribute-link is indistinguishable from an ordinary link:
|
||||||
slot_id = self.create_link(
|
slot_id = self.create_link(
|
||||||
get_attr_link_name(object_name, attr_name),
|
get_slot_link_name(object_name, attr_name),
|
||||||
attr_link_name, object_name, target_name)
|
attr_link_name, object_name, target_name)
|
||||||
return slot_id
|
return slot_id
|
||||||
|
|
||||||
def get_slot(self, object_node: UUID, attr_name: str):
|
def get_slot(self, object_node: UUID, attr_name: str):
|
||||||
# I really don't like how complex and inefficient it is to read an attribute of an object...
|
# I really don't like how complex and inefficient it is to read an attribute of an object...
|
||||||
class_name = self._get_class_of_object(object_node)
|
class_name = self._get_class_of_object(object_node)
|
||||||
attr_link_name = get_attr_link_name(class_name, attr_name)
|
attr_link_name = self.get_attr_link_name(class_name, attr_name)
|
||||||
type_edge, = self.bottom.read_outgoing_elements(self.type_model, attr_link_name)
|
type_edge, = self.bottom.read_outgoing_elements(self.type_model, attr_link_name)
|
||||||
for outgoing_edge in self.bottom.read_outgoing_edges(object_node):
|
for outgoing_edge in self.bottom.read_outgoing_edges(object_node):
|
||||||
if type_edge in self.bottom.read_outgoing_elements(outgoing_edge, "Morphism"):
|
if type_edge in self.bottom.read_outgoing_elements(outgoing_edge, "Morphism"):
|
||||||
|
|
@ -130,6 +132,16 @@ class OD:
|
||||||
self.create_model_ref(name, "String", string_node)
|
self.create_model_ref(name, "String", string_node)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
def create_actioncode_value(self, name: str, value: str):
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
|
actioncode_node = self.bottom.create_node()
|
||||||
|
actioncode_t = ActionCode(actioncode_node, self.bottom.state)
|
||||||
|
actioncode_t.create(value)
|
||||||
|
# name = 'str-'+value # name of the ref to the created integer
|
||||||
|
# By convention, the type model must have a ModelRef named "Integer"
|
||||||
|
self.create_model_ref(name, "ActionCode", actioncode_node)
|
||||||
|
return name
|
||||||
|
|
||||||
# Identical to the same SCD method:
|
# Identical to the same SCD method:
|
||||||
def create_model_ref(self, name: str, type_name: str, model: UUID):
|
def create_model_ref(self, name: str, type_name: str, model: UUID):
|
||||||
# create element + morphism links
|
# create element + morphism links
|
||||||
|
|
@ -137,7 +149,24 @@ class OD:
|
||||||
self.bottom.create_edge(self.model, element_node, name) # attach to model
|
self.bottom.create_edge(self.model, element_node, name) # attach to model
|
||||||
type_node, = self.bottom.read_outgoing_elements(self.type_model, type_name) # retrieve type
|
type_node, = self.bottom.read_outgoing_elements(self.type_model, type_name) # retrieve type
|
||||||
self.bottom.create_edge(element_node, type_node, "Morphism") # create morphism link
|
self.bottom.create_edge(element_node, type_node, "Morphism") # create morphism link
|
||||||
|
# print('model ref:', name, type_name, element_node, model)
|
||||||
|
return element_node
|
||||||
|
|
||||||
|
# The edge connecting an object to the value of a slot must be named `{object_name}_{attr_name}`
|
||||||
|
def get_attr_link_name(self, class_name, attr_name):
|
||||||
|
assoc_name = f"{class_name}_{attr_name}"
|
||||||
|
type_edges = self.bottom.read_outgoing_elements(self.type_model, assoc_name)
|
||||||
|
if len(type_edges) == 1:
|
||||||
|
return assoc_name
|
||||||
|
else:
|
||||||
|
# look for attribute in the super-types
|
||||||
|
conf = Conformance(self.bottom.state, self.type_model, get_scd_mm(self.bottom))
|
||||||
|
conf.precompute_sub_types() # only need to know about subtypes
|
||||||
|
super_types = (s for s in conf.sub_types if class_name in conf.sub_types[s])
|
||||||
|
for s in super_types:
|
||||||
|
assoc_name = f"{s}_{attr_name}"
|
||||||
|
if len(self.bottom.read_outgoing_elements(self.type_model, assoc_name)) == 1:
|
||||||
|
return assoc_name
|
||||||
|
|
||||||
def create_link(self, link_name: Optional[str], assoc_name: str, src_obj_name: str, tgt_obj_name: str):
|
def create_link(self, link_name: Optional[str], assoc_name: str, src_obj_name: str, tgt_obj_name: str):
|
||||||
src_obj_node, = self.bottom.read_outgoing_elements(self.model, src_obj_name)
|
src_obj_node, = self.bottom.read_outgoing_elements(self.model, src_obj_name)
|
||||||
|
|
@ -246,6 +275,9 @@ def get_scd_mm_assoc_node(bottom: Bottom):
|
||||||
def get_scd_mm_modelref_node(bottom: Bottom):
|
def get_scd_mm_modelref_node(bottom: Bottom):
|
||||||
return get_scd_mm_node(bottom, "ModelRef")
|
return get_scd_mm_node(bottom, "ModelRef")
|
||||||
|
|
||||||
|
def get_scd_mm_actioncode_node(bottom: Bottom):
|
||||||
|
return get_scd_mm_node(bottom, "ActionCode")
|
||||||
|
|
||||||
def get_scd_mm_node(bottom: Bottom, node_name: str):
|
def get_scd_mm_node(bottom: Bottom, node_name: str):
|
||||||
scd_metamodel = get_scd_mm(bottom)
|
scd_metamodel = get_scd_mm(bottom)
|
||||||
node, = bottom.read_outgoing_elements(scd_metamodel, node_name)
|
node, = bottom.read_outgoing_elements(scd_metamodel, node_name)
|
||||||
|
|
@ -323,15 +355,17 @@ def get_attr_name(bottom, attr_edge: UUID):
|
||||||
def read_primitive_value(bottom, modelref: UUID, mm: UUID):
|
def read_primitive_value(bottom, modelref: UUID, mm: UUID):
|
||||||
typ = get_type(bottom, modelref)
|
typ = get_type(bottom, modelref)
|
||||||
if not is_typed_by(bottom, typ, get_scd_mm_modelref_node(bottom)):
|
if not is_typed_by(bottom, typ, get_scd_mm_modelref_node(bottom)):
|
||||||
raise Exception("Assertion failed: argument must be typed by ModelRef")
|
raise Exception("Assertion failed: argument must be typed by ModelRef", typ)
|
||||||
referred_model = UUID(bottom.read_value(modelref))
|
referred_model = UUID(bottom.read_value(modelref))
|
||||||
typ_name = get_object_name(bottom, mm, typ)
|
typ_name = get_object_name(bottom, mm, typ)
|
||||||
if typ_name == "Integer":
|
if typ_name == "Integer":
|
||||||
return Integer(referred_model, bottom.state).read()
|
return Integer(referred_model, bottom.state).read(), typ_name
|
||||||
elif typ_name == "String":
|
elif typ_name == "String":
|
||||||
return String(referred_model, bottom.state).read()
|
return String(referred_model, bottom.state).read(), typ_name
|
||||||
elif typ_name == "Boolean":
|
elif typ_name == "Boolean":
|
||||||
return Boolean(referred_model, bottom.state).read()
|
return Boolean(referred_model, bottom.state).read(), typ_name
|
||||||
|
elif typ_name == "ActionCode":
|
||||||
|
return ActionCode(referred_model, bottom.state).read(), typ_name
|
||||||
else:
|
else:
|
||||||
raise Exception("Unimplemented type:", typ_name)
|
raise Exception("Unimplemented type:", typ_name)
|
||||||
|
|
||||||
|
|
|
||||||
24
services/primitives/actioncode_type.py
Normal file
24
services/primitives/actioncode_type.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
from uuid import UUID
|
||||||
|
from state.base import State
|
||||||
|
from services.bottom.V0 import Bottom
|
||||||
|
|
||||||
|
|
||||||
|
class ActionCode:
|
||||||
|
def __init__(self, model: UUID, state: State):
|
||||||
|
self.model = model
|
||||||
|
self.bottom = Bottom(state)
|
||||||
|
type_model_id_node, = self.bottom.read_outgoing_elements(state.read_root(), "ActionCode")
|
||||||
|
self.type_model = UUID(self.bottom.read_value(type_model_id_node))
|
||||||
|
|
||||||
|
def create(self, value: str):
|
||||||
|
if "code" in self.bottom.read_keys(self.model):
|
||||||
|
instance, = self.bottom.read_outgoing_elements(self.model, "code")
|
||||||
|
self.bottom.delete_element(instance)
|
||||||
|
_instance = self.bottom.create_node(value)
|
||||||
|
self.bottom.create_edge(self.model, _instance, "code")
|
||||||
|
_type, = self.bottom.read_outgoing_elements(self.type_model, "ActionCode")
|
||||||
|
self.bottom.create_edge(_instance, _type, "Morphism")
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
instance, = self.bottom.read_outgoing_elements(self.model, "code")
|
||||||
|
return self.bottom.read_value(instance)
|
||||||
|
|
@ -4,6 +4,7 @@ from services.bottom.V0 import Bottom
|
||||||
from services.primitives.boolean_type import Boolean
|
from services.primitives.boolean_type import Boolean
|
||||||
from services.primitives.integer_type import Integer
|
from services.primitives.integer_type import Integer
|
||||||
from services.primitives.string_type import String
|
from services.primitives.string_type import String
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
from services import od
|
from services import od
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
@ -274,15 +275,28 @@ class SCD:
|
||||||
Nothing.
|
Nothing.
|
||||||
"""
|
"""
|
||||||
element_node, = self.bottom.read_outgoing_elements(self.model, element) # retrieve element
|
element_node, = self.bottom.read_outgoing_elements(self.model, element) # retrieve element
|
||||||
# code attribute
|
# # code attribute
|
||||||
code_node = self.bottom.create_node(code)
|
# code_node = self.bottom.create_node(code)
|
||||||
self.bottom.create_edge(self.model, code_node, f"{element}.constraint")
|
# self.bottom.create_edge(self.model, code_node, f"{element}.constraint")
|
||||||
code_link = self.bottom.create_edge(element_node, code_node)
|
# code_link = self.bottom.create_edge(element_node, code_node)
|
||||||
self.bottom.create_edge(self.model, code_link, f"{element}_constraint")
|
# self.bottom.create_edge(self.model, code_link, f"{element}_constraint")
|
||||||
scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "ActionCode")
|
# scd_node, = self.bottom.read_outgoing_elements(self.scd_model, "ActionCode")
|
||||||
scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "Element_constraint")
|
# scd_link, = self.bottom.read_outgoing_elements(self.scd_model, "Element_constraint")
|
||||||
self.bottom.create_edge(code_node, scd_node, "Morphism")
|
# self.bottom.create_edge(code_node, scd_node, "Morphism")
|
||||||
self.bottom.create_edge(code_link, scd_link, "Morphism")
|
# self.bottom.create_edge(code_link, scd_link, "Morphism")
|
||||||
|
|
||||||
|
|
||||||
|
constraint_model = self.bottom.create_node()
|
||||||
|
ActionCode(constraint_model, self.bottom.state).create(code)
|
||||||
|
constraint_node = self.bottom.create_node(str(constraint_model))
|
||||||
|
self.bottom.create_edge(self.model, constraint_node, f"{element}.constraint")
|
||||||
|
constraint_link = self.bottom.create_edge(element_node, constraint_node)
|
||||||
|
self.bottom.create_edge(self.model, constraint_link, f"{element}_constraint")
|
||||||
|
type_node, = self.bottom.read_outgoing_elements(self.scd_model, "ActionCode")
|
||||||
|
type_link, = self.bottom.read_outgoing_elements(self.scd_model, "Element_constraint")
|
||||||
|
self.bottom.create_edge(constraint_node, type_node, "Morphism")
|
||||||
|
self.bottom.create_edge(constraint_link, type_link, "Morphism")
|
||||||
|
|
||||||
|
|
||||||
def list_elements(self):
|
def list_elements(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -143,9 +143,9 @@ def rewrite(state, lhs_m: UUID, rhs_m: UUID, pattern_mm: UUID, name_mapping: dic
|
||||||
pass
|
pass
|
||||||
elif od.is_typed_by(bottom, host_type, modelref_type):
|
elif od.is_typed_by(bottom, host_type, modelref_type):
|
||||||
# print(' -> is modelref')
|
# print(' -> is modelref')
|
||||||
old_value = od.read_primitive_value(bottom, model_el, mm)
|
old_value, _ = od.read_primitive_value(bottom, model_el, mm)
|
||||||
rhs_el, = bottom.read_outgoing_elements(rhs_m, pattern_el_name)
|
rhs_el, = bottom.read_outgoing_elements(rhs_m, pattern_el_name)
|
||||||
expr = od.read_primitive_value(bottom, rhs_el, pattern_mm)
|
expr, _ = od.read_primitive_value(bottom, rhs_el, pattern_mm)
|
||||||
result = eval(expr, {}, {'v': old_value})
|
result = eval(expr, {}, {'v': old_value})
|
||||||
# print('eval result=', result)
|
# print('eval result=', result)
|
||||||
if isinstance(result, int):
|
if isinstance(result, int):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue