| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- from state.base import State
- from uuid import UUID
- from services.bottom.V0 import Bottom
- from pattern_matching.matcher import Graph, Edge, Vertex
- import itertools
- import re
- from util.timer import Timer
- class _is_edge:
- def __repr__(self):
- return "EDGE"
- # just a unique symbol that is only equal to itself
- IS_EDGE = _is_edge()
- class IS_TYPE:
- def __init__(self, type):
- # mvs-node of the type
- self.type = type
- def __repr__(self):
- return f"TYPE({str(self.type)[-4:]})"
- # def __eq__(self, other):
- # if not isinstance(other, IS_TYPE):
- # return False
- # return other.type == self.type
- # def __hash__(self):
- # return self.type.__hash__()
- UUID_REGEX = re.compile(r"[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]-[0-9a-z][0-9a-z][0-9a-z][0-9a-z]-[0-9a-z][0-9a-z][0-9a-z][0-9a-z]-[0-9a-z][0-9a-z][0-9a-z][0-9a-z]-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]")
- # Converts an object/class diagram in MVS state to the pattern matcher graph type
- # ModelRefs are flattened
- def model_to_graph(state: State, model: UUID):
- with Timer("model_to_graph"):
- bottom = Bottom(state)
- graph = Graph()
- mvs_edges = []
- modelrefs = {}
- def extract_modelref(el):
- value = bottom.read_value(el)
- # If the value of the el is a ModelRef (only way to detect this is to match a regex - not very clean), then extract it. We'll create a link to the referred model later.
- if bottom.is_edge(el):
- mvs_edges.append(el)
- return IS_EDGE
- if isinstance(value, str):
- if UUID_REGEX.match(value) != None:
- # side-effect
- modelrefs[el] = UUID(value)
- return None
- return value
- # MVS-Nodes become vertices
- uuid_to_vtx = { node: Vertex(value=extract_modelref(node)) for node in bottom.read_outgoing_elements(model) }
- graph.vtxs = [ vtx for vtx in uuid_to_vtx.values() ]
- # For every MSV-Edge, two edges are created (for src and tgt)
- for mvs_edge in mvs_edges:
- mvs_src = bottom.read_edge_source(mvs_edge)
- if mvs_src in uuid_to_vtx:
- graph.edges.append(Edge(
- src=uuid_to_vtx[mvs_src],
- tgt=uuid_to_vtx[mvs_edge],
- label="outgoing"))
- mvs_tgt = bottom.read_edge_target(mvs_edge)
- if mvs_tgt in uuid_to_vtx:
- graph.edges.append(Edge(
- src=uuid_to_vtx[mvs_tgt],
- tgt=uuid_to_vtx[mvs_edge],
- label="tgt"))
- for node, ref in modelrefs.items():
- # Recursively convert ref'ed model to graph
- ref_model = model_to_graph(state, ref)
- # Flatten and create link to ref'ed model
- graph.vtxs += ref_model.vtxs
- graph.edges += ref_model.edges
- graph.edges.append(Edge(
- src=uuid_to_vtx[node],
- tgt=ref_model.vtxs[0], # which node to link to?? dirty
- label="modelref"))
- # # Add typing information
- # for i,node in enumerate(bottom.read_outgoing_elements(model)):
- # type_node, = bottom.read_outgoing_elements(node, "Morphism")
- # print('node', node, 'has type', type_node)
- # # We create a Vertex storing the type
- # type_vertex = Vertex(value=IS_TYPE(type_node))
- # graph.vtxs.append(type_vertex)
- # type_edge = Edge(
- # src=uuid_to_vtx[node],
- # tgt=type_vertex,
- # label="type")
- # print(type_edge)
- # graph.edges.append(type_edge)
- return graph
- # Function object for pattern matching. Decides whether to match host and guest vertices, where guest is a RAMified instance (e.g., the attributes are all strings with Python expressions), and the host is an instance (=object diagram) of the original model (=class diagram)
- class RAMCompare:
- def __init__(self, bottom):
- self.bottom = bottom
- type_model_id = bottom.state.read_dict(bottom.state.read_root(), "SCD")
- self.scd_model = UUID(bottom.state.read_value(type_model_id))
- def is_subtype_of(self, supposed_subtype: UUID, supposed_supertype: UUID):
- inheritance_node, = self.bottom.read_outgoing_elements(self.scd_model, "Inheritance")
- if supposed_subtype == supposed_supertype:
- # reflexive:
- return True
- for outgoing in self.bottom.read_outgoing_edges(supposed_subtype):
- if inheritance_node in self.bottom.read_outgoing_elements(outgoing, "Morphism"):
- # 'outgoing' is an inheritance link
- supertype = self.bottom.read_edge_target(outgoing)
- if supertype != supposed_subtype:
- if self.is_subtype_of(supertype, supposed_supertype):
- return True
- return False
- def __call__(self, g_val, h_val):
- if g_val == None:
- return h_val == None
- # mvs-edges (which are converted to vertices) only match with mvs-edges
- if g_val == IS_EDGE:
- return h_val == IS_EDGE
- if h_val == IS_EDGE:
- return False
- # types only match with their supertypes
- if isinstance(g_val, IS_TYPE):
- if not isinstance(h_val, IS_TYPE):
- return False
- g_val_original_type = self.bottom.read_outgoing_elements(g_val.type, "RAMifies")
- result = self.is_subtype_of(h_val.type, g_val_original_type)
- print("RESULT", result)
- return result
- if isinstance(h_val, IS_TYPE):
- return False
- # print(g_val, h_val)
- return eval(g_val, {}, {'v': h_val})
|