Concrete syntax no longer indentation-based (nightmare to parse). Add indented multi-line code terminals.
This commit is contained in:
parent
59de61d0a3
commit
e875821e70
8 changed files with 119 additions and 73 deletions
16
concrete_syntax/common.py
Normal file
16
concrete_syntax/common.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
def indent(multiline_string, how_much):
|
||||||
|
lines = multiline_string.split('\n')
|
||||||
|
return '\n'.join([' '*how_much+l for l in lines])
|
||||||
|
|
||||||
|
def display_value(val: any, type_name: str, indentation=0):
|
||||||
|
if type_name == "ActionCode":
|
||||||
|
if '\n' in val:
|
||||||
|
return '```\n'+indent(val, indentation+4)+'\n'+' '*indentation+'```'
|
||||||
|
else:
|
||||||
|
return '`'+val+'`'
|
||||||
|
elif type_name == "String":
|
||||||
|
return '"'+val+'"'
|
||||||
|
elif type_name == "Integer" or type_name == "Boolean":
|
||||||
|
return str(val)
|
||||||
|
else:
|
||||||
|
raise Exception("don't know how to display value" + type_name)
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
from services import scd, od
|
from services import scd, od
|
||||||
from services.bottom.V0 import Bottom
|
from services.bottom.V0 import Bottom
|
||||||
from transformation import ramify
|
from transformation import ramify
|
||||||
import json
|
from concrete_syntax.common import display_value
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
def render_class_diagram(state, model, prefix_ids=""):
|
def render_class_diagram(state, model, prefix_ids=""):
|
||||||
|
|
@ -97,7 +97,8 @@ 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)[0])}"
|
val, type_name = od.read_primitive_value(bottom, slot, mm)
|
||||||
|
output += f"\n{attr_name} => {display_value(val, type_name)}"
|
||||||
output += '\n}'
|
output += '\n}'
|
||||||
|
|
||||||
output += '\n'
|
output += '\n'
|
||||||
|
|
|
||||||
|
|
@ -7,46 +7,34 @@ from services.scd import SCD
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
grammar = r"""
|
grammar = r"""
|
||||||
%import common.WS_INLINE
|
%import common.WS
|
||||||
%ignore WS_INLINE
|
%ignore WS
|
||||||
%ignore COMMENT
|
%ignore COMMENT
|
||||||
|
|
||||||
%declare _INDENT _DEDENT
|
?start: object*
|
||||||
|
|
||||||
?start: (_NL | object )*
|
|
||||||
|
|
||||||
IDENTIFIER: /[A-Za-z_][A-Za-z_0-9]*/
|
IDENTIFIER: /[A-Za-z_][A-Za-z_0-9]*/
|
||||||
COMMENT: /#.*/
|
COMMENT: /#[^\n]*\n/
|
||||||
|
|
||||||
# newline
|
|
||||||
_NL: /(\r?\n[\t ]*)+/
|
|
||||||
|
|
||||||
literal: INT
|
literal: INT
|
||||||
| STR
|
| STR
|
||||||
| BOOL
|
| BOOL
|
||||||
| CODE
|
| CODE
|
||||||
|
| INDENTED_CODE
|
||||||
|
|
||||||
INT: /[0-9]+/
|
INT: /[0-9]+/
|
||||||
STR: /"[^"]*"/
|
STR: /"[^"]*"/
|
||||||
| /'[^']*'/
|
| /'[^']*'/
|
||||||
BOOL: "True" | "False"
|
BOOL: "True" | "False"
|
||||||
CODE: /`[^`]*`/
|
CODE: /`[^`]*`/
|
||||||
|
INDENTED_CODE: /```[^`]*```/
|
||||||
|
|
||||||
object: [IDENTIFIER] ":" IDENTIFIER [link_spec] _NL [_INDENT slot+ _DEDENT]
|
object: [IDENTIFIER] ":" IDENTIFIER [link_spec] ["{" slot* "}"]
|
||||||
link_spec: "(" IDENTIFIER "->" IDENTIFIER ")"
|
link_spec: "(" IDENTIFIER "->" IDENTIFIER ")"
|
||||||
slot: IDENTIFIER "=" literal _NL
|
slot: IDENTIFIER "=" literal ";"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
parser = Lark(grammar, parser='lalr')
|
||||||
class TreeIndenter(Indenter):
|
|
||||||
NL_type = '_NL'
|
|
||||||
OPEN_PAREN_types = []
|
|
||||||
CLOSE_PAREN_types = []
|
|
||||||
INDENT_type = '_INDENT'
|
|
||||||
DEDENT_type = '_DEDENT'
|
|
||||||
tab_len = 4
|
|
||||||
|
|
||||||
parser = Lark(grammar, parser='lalr', postlex=TreeIndenter())
|
|
||||||
|
|
||||||
# internal use only
|
# internal use only
|
||||||
# just a dumb wrapper to distinguish between code and string
|
# just a dumb wrapper to distinguish between code and string
|
||||||
|
|
@ -83,6 +71,18 @@ def parse_od(state, cs_text, mm):
|
||||||
def CODE(self, token):
|
def CODE(self, token):
|
||||||
return _Code(str(token[1:-1])) # strip the ``
|
return _Code(str(token[1:-1])) # strip the ``
|
||||||
|
|
||||||
|
def INDENTED_CODE(self, token):
|
||||||
|
skip = 4 # strip the ``` and the following newline character
|
||||||
|
space_count = 0
|
||||||
|
while token[skip+space_count] == " ":
|
||||||
|
space_count += 1
|
||||||
|
lines = token.split('\n')[1:-1]
|
||||||
|
for line in lines:
|
||||||
|
if line[0:space_count] != ' '*space_count:
|
||||||
|
raise Exception("wrong indentation of INDENTED_CODE")
|
||||||
|
unindented_lines = [l[space_count:] for l in lines]
|
||||||
|
return _Code('\n'.join(unindented_lines))
|
||||||
|
|
||||||
def literal(self, el):
|
def literal(self, el):
|
||||||
return el[0]
|
return el[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,8 @@
|
||||||
|
|
||||||
from services import od
|
from services import od
|
||||||
from services.bottom.V0 import Bottom
|
from services.bottom.V0 import Bottom
|
||||||
import json
|
from concrete_syntax.common import display_value
|
||||||
|
|
||||||
def display_value(val: any, type_name: str):
|
|
||||||
if type_name == "ActionCode":
|
|
||||||
return '`'+val+'`'
|
|
||||||
elif type_name == "String":
|
|
||||||
return '"'+val+'"'
|
|
||||||
elif type_name == "Integer" or type_name == "Boolean":
|
|
||||||
return str(val)
|
|
||||||
else:
|
|
||||||
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)
|
||||||
|
|
@ -26,19 +17,23 @@ 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):
|
slots = m_od.get_slots(object_node)
|
||||||
|
if len(slots) > 0:
|
||||||
|
o += " {"
|
||||||
|
for attr_name, slot_node in slots:
|
||||||
value, type_name = m_od.read_slot(slot_node)
|
value, type_name = m_od.read_slot(slot_node)
|
||||||
o += f" {attr_name} = {display_value(value, type_name)}\n"
|
o += f"\n {attr_name} = {display_value(value, type_name, indentation=4)};"
|
||||||
|
o += "\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():
|
||||||
for object_name, object_node in objects.items():
|
for object_name, object_node in objects.items():
|
||||||
output += f"{display_name(object_name)}:{class_name}\n"
|
output += f"\n{display_name(object_name)}:{class_name}"
|
||||||
output += write_attributes(object_node)
|
output += write_attributes(object_node)
|
||||||
|
|
||||||
for assoc_name, links in m_od.get_all_links().items():
|
for assoc_name, links in m_od.get_all_links().items():
|
||||||
for link_name, (link_edge, src_name, tgt_name) in links.items():
|
for link_name, (link_edge, src_name, tgt_name) in links.items():
|
||||||
output += f"{display_name(link_name)}:{assoc_name} ({src_name} -> {tgt_name})\n"
|
output += f"\n{display_name(link_name)}:{assoc_name} ({src_name} -> {tgt_name})"
|
||||||
# links can also have slots:
|
# links can also have slots:
|
||||||
output += write_attributes(link_edge)
|
output += write_attributes(link_edge)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,22 +62,37 @@ def main():
|
||||||
dsl_mm_cs = """
|
dsl_mm_cs = """
|
||||||
# Integer:ModelRef
|
# Integer:ModelRef
|
||||||
Bear:Class
|
Bear:Class
|
||||||
Animal:Class
|
Animal:Class {
|
||||||
abstract = True
|
abstract = True;
|
||||||
Man:Class
|
}
|
||||||
lower_cardinality = 1
|
Man:Class {
|
||||||
upper_cardinality = 2
|
lower_cardinality = 1;
|
||||||
# constraint = `get_value(get_slot(element, "weight")) < 100`
|
upper_cardinality = 2;
|
||||||
Man_weight:AttributeLink (Man -> Integer)
|
constraint = `get_value(get_slot(element, "weight")) < 20`;
|
||||||
name = "weight"
|
}
|
||||||
optional = False
|
Man_weight:AttributeLink (Man -> Integer) {
|
||||||
constraint = `get_value(get_target(element)) < 100`
|
name = "weight";
|
||||||
afraidOf:Association (Man -> Animal)
|
optional = False;
|
||||||
target_lower_cardinality = 1
|
constraint = ```
|
||||||
|
node = get_target(element)
|
||||||
|
get_value(node) < 20
|
||||||
|
```;
|
||||||
|
}
|
||||||
|
afraidOf:Association (Man -> Animal) {
|
||||||
|
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`
|
not_too_fat:GlobalConstraint {
|
||||||
|
constraint = ```
|
||||||
|
# total weight of all men low enough
|
||||||
|
total_weight = 0
|
||||||
|
for man_name, man_id in get_all_instances("Man"):
|
||||||
|
total_weight += get_value(get_slot(man_id, "weight"))
|
||||||
|
total_weight < 50
|
||||||
|
```;
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
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
|
||||||
|
|
@ -98,8 +113,9 @@ sum_of_weights:GlobalConstraint
|
||||||
def create_dsl_m_parser():
|
def create_dsl_m_parser():
|
||||||
# Create DSL M with parser
|
# Create DSL M with parser
|
||||||
dsl_m_cs = """
|
dsl_m_cs = """
|
||||||
george :Man
|
george :Man {
|
||||||
weight = 80
|
weight = 80;
|
||||||
|
}
|
||||||
bear1:Bear
|
bear1:Bear
|
||||||
bear2:Bear
|
bear2:Bear
|
||||||
:afraidOf (george -> bear1)
|
:afraidOf (george -> bear1)
|
||||||
|
|
@ -139,7 +155,7 @@ bear2:Bear
|
||||||
lhs_id = state.create_node()
|
lhs_id = state.create_node()
|
||||||
lhs_od = OD(ramified_mm_id, lhs_id, state)
|
lhs_od = OD(ramified_mm_id, lhs_id, state)
|
||||||
lhs_od.create_object("man", prefix+"Man")
|
lhs_od.create_object("man", prefix+"Man")
|
||||||
lhs_od.create_slot(prefix+"weight", "man", lhs_od.create_string_value(f"man.{prefix}weight", 'v < 99'))
|
lhs_od.create_slot(prefix+"weight", "man", lhs_od.create_actioncode_value(f"man.{prefix}weight", 'v < 99'))
|
||||||
lhs_od.create_object("scaryAnimal", prefix+"Animal")
|
lhs_od.create_object("scaryAnimal", prefix+"Animal")
|
||||||
lhs_od.create_link("manAfraidOfAnimal", prefix+"afraidOf", "man", "scaryAnimal")
|
lhs_od.create_link("manAfraidOfAnimal", prefix+"afraidOf", "man", "scaryAnimal")
|
||||||
|
|
||||||
|
|
@ -150,9 +166,9 @@ bear2:Bear
|
||||||
rhs_id = state.create_node()
|
rhs_id = state.create_node()
|
||||||
rhs_od = OD(ramified_mm_id, rhs_id, state)
|
rhs_od = OD(ramified_mm_id, rhs_id, state)
|
||||||
rhs_od.create_object("man", prefix+"Man")
|
rhs_od.create_object("man", prefix+"Man")
|
||||||
rhs_od.create_slot(prefix+"weight", "man", rhs_od.create_string_value(f"man.{prefix}weight", 'v + 5'))
|
rhs_od.create_slot(prefix+"weight", "man", rhs_od.create_actioncode_value(f"man.{prefix}weight", 'v + 5'))
|
||||||
rhs_od.create_object("bill", prefix+"Man")
|
rhs_od.create_object("bill", prefix+"Man")
|
||||||
rhs_od.create_slot(prefix+"weight", "bill", rhs_od.create_string_value(f"bill.{prefix}weight", '100'))
|
rhs_od.create_slot(prefix+"weight", "bill", rhs_od.create_actioncode_value(f"bill.{prefix}weight", '100'))
|
||||||
|
|
||||||
rhs_od.create_link("billAfraidOfMan", prefix+"afraidOf", "bill", "man")
|
rhs_od.create_link("billAfraidOfMan", prefix+"afraidOf", "bill", "man")
|
||||||
|
|
||||||
|
|
@ -229,7 +245,7 @@ bear2:Bear
|
||||||
# plantuml_str = render_rewrite()
|
# plantuml_str = render_rewrite()
|
||||||
|
|
||||||
# print()
|
# print()
|
||||||
# print("==============================================")
|
print("==============================================")
|
||||||
|
|
||||||
# print(plantuml_str)
|
# print(plantuml_str)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,17 @@ from pprint import pprint
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
|
|
||||||
|
# based on https://stackoverflow.com/a/39381428
|
||||||
|
# Parses and executes a block of Python code, and returns the eval result of the last statement
|
||||||
|
import ast
|
||||||
|
def exec_then_eval(code, _globals, _locals):
|
||||||
|
block = ast.parse(code, mode='exec')
|
||||||
|
# assumes last node is an expression
|
||||||
|
last = ast.Expression(block.body.pop().value)
|
||||||
|
exec(compile(block, '<string>', mode='exec'), _globals, _locals)
|
||||||
|
return eval(compile(last, '<string>', mode='eval'), _globals, _locals)
|
||||||
|
|
||||||
|
|
||||||
class Conformance:
|
class Conformance:
|
||||||
def __init__(self, state: State, model: UUID, type_model: UUID):
|
def __init__(self, state: State, model: UUID, type_model: UUID):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
@ -368,12 +379,13 @@ class Conformance:
|
||||||
'get_all_instances': self.get_all_instances
|
'get_all_instances': self.get_all_instances
|
||||||
}
|
}
|
||||||
# print("evaluating constraint ...", code)
|
# print("evaluating constraint ...", code)
|
||||||
result = eval(
|
loc = {**kwargs, **funcs}
|
||||||
|
result = exec_then_eval(
|
||||||
code,
|
code,
|
||||||
{'__builtins__': {'isinstance': isinstance, 'print': print,
|
{'__builtins__': {'isinstance': isinstance, 'print': print,
|
||||||
'int': int, 'float': float, 'bool': bool, 'str': str, 'tuple': tuple, 'len': len}
|
'int': int, 'float': float, 'bool': bool, 'str': str, 'tuple': tuple, 'len': len}
|
||||||
}, # globals
|
}, # globals
|
||||||
{**kwargs, **funcs} # locals
|
loc # locals
|
||||||
)
|
)
|
||||||
# print('result =', result)
|
# print('result =', result)
|
||||||
return result
|
return result
|
||||||
|
|
@ -384,7 +396,8 @@ class Conformance:
|
||||||
for subtype_name in self.sub_types[type_name]:
|
for subtype_name in self.sub_types[type_name]:
|
||||||
# print(subtype_name, 'is subtype of ')
|
# print(subtype_name, 'is subtype of ')
|
||||||
result += [e_name for e_name, t_name in self.type_mapping.items() if t_name == subtype_name]
|
result += [e_name for e_name, t_name in self.type_mapping.items() if t_name == subtype_name]
|
||||||
return result
|
result_with_ids = [ (e_name, self.bottom.read_outgoing_elements(self.model, e_name)[0]) for e_name in result]
|
||||||
|
return result_with_ids
|
||||||
|
|
||||||
def check_constraints(self):
|
def check_constraints(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -399,12 +412,11 @@ class Conformance:
|
||||||
code = ActionCode(UUID(self.bottom.read_value(constraint)), self.bottom.state).read()
|
code = ActionCode(UUID(self.bottom.read_value(constraint)), self.bottom.state).read()
|
||||||
return code
|
return code
|
||||||
|
|
||||||
def check_result(result, local_or_global, tm_name, el_name=None):
|
def check_result(result, description):
|
||||||
suffix = f"in '{el_name}'" if local_or_global == "Local" else ""
|
|
||||||
if not isinstance(result, bool):
|
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)}).")
|
raise Exception(f"{description} evaluation result is not boolean! Instead got {result}")
|
||||||
elif not result:
|
if not result:
|
||||||
errors.append(f"{local_or_global} constraint `{code}` of '{tm_name}'{suffix} not satisfied.")
|
errors.append(f"{description} not satisfied.")
|
||||||
|
|
||||||
# local constraints
|
# local constraints
|
||||||
for m_name, tm_name in self.type_mapping.items():
|
for m_name, tm_name in self.type_mapping.items():
|
||||||
|
|
@ -415,7 +427,8 @@ class Conformance:
|
||||||
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:
|
||||||
result = self.evaluate_constraint(code, element=m_element, type_name=tm_name)
|
result = self.evaluate_constraint(code, element=m_element, type_name=tm_name)
|
||||||
check_result(result, "Local", tm_name, m_name)
|
description = f"Local constraint of \"{tm_name}\" in \"{m_name}\""
|
||||||
|
check_result(result, description)
|
||||||
|
|
||||||
# global constraints
|
# global constraints
|
||||||
glob_constraints = []
|
glob_constraints = []
|
||||||
|
|
@ -432,9 +445,9 @@ class Conformance:
|
||||||
for tm_name in glob_constraints:
|
for tm_name in glob_constraints:
|
||||||
code = get_code(tm_name)
|
code = get_code(tm_name)
|
||||||
if code != None:
|
if code != None:
|
||||||
# print('glob constr:', code)
|
|
||||||
result = self.evaluate_constraint(code, model=self.model)
|
result = self.evaluate_constraint(code, model=self.model)
|
||||||
check_result(result, "Global", tm_name)
|
description = f"Global constraint \"{tm_name}\""
|
||||||
|
check_result(result, description)
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
def precompute_structures(self):
|
def precompute_structures(self):
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,16 @@ def ramify(state: State, model: UUID, prefix = "RAM_") -> UUID:
|
||||||
string_type_id = state.read_dict(state.read_root(), "String")
|
string_type_id = state.read_dict(state.read_root(), "String")
|
||||||
string_type = UUID(state.read_value(string_type_id))
|
string_type = UUID(state.read_value(string_type_id))
|
||||||
|
|
||||||
|
actioncode_type_id = state.read_dict(state.read_root(), "ActionCode")
|
||||||
|
actioncode_type = UUID(state.read_value(actioncode_type_id))
|
||||||
|
|
||||||
m_scd = scd.SCD(model, state)
|
m_scd = scd.SCD(model, state)
|
||||||
|
|
||||||
ramified = state.create_node()
|
ramified = state.create_node()
|
||||||
ramified_scd = scd.SCD(ramified, state)
|
ramified_scd = scd.SCD(ramified, state)
|
||||||
|
|
||||||
string_modelref = ramified_scd.create_model_ref("String", string_type)
|
string_modelref = ramified_scd.create_model_ref("String", string_type)
|
||||||
|
actioncode_modelref = ramified_scd.create_model_ref("ActionCode", actioncode_type)
|
||||||
|
|
||||||
classes = m_scd.get_classes()
|
classes = m_scd.get_classes()
|
||||||
for class_name, class_node in classes.items():
|
for class_name, class_node in classes.items():
|
||||||
|
|
@ -44,7 +48,7 @@ def ramify(state: State, model: UUID, prefix = "RAM_") -> UUID:
|
||||||
# print(' creating attribute', attr_name, "with type String")
|
# print(' creating attribute', attr_name, "with type String")
|
||||||
# Every attribute becomes 'string' type
|
# Every attribute becomes 'string' type
|
||||||
# The string will be a Python expression
|
# The string will be a Python expression
|
||||||
ramified_attr_link = ramified_scd._create_attribute_link(prefix+class_name, string_modelref, prefix+attr_name, optional=True)
|
ramified_attr_link = ramified_scd._create_attribute_link(prefix+class_name, actioncode_modelref, prefix+attr_name, optional=True)
|
||||||
# traceability link
|
# traceability link
|
||||||
bottom.create_edge(ramified_attr_link, attr_edge, RAMIFIES_LABEL)
|
bottom.create_edge(ramified_attr_link, attr_edge, RAMIFIES_LABEL)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ from services.bottom.V0 import Bottom
|
||||||
from transformation import ramify
|
from transformation import ramify
|
||||||
from services import od
|
from services import od
|
||||||
from services.primitives.string_type import String
|
from services.primitives.string_type import String
|
||||||
|
from services.primitives.actioncode_type import ActionCode
|
||||||
from services.primitives.integer_type import Integer
|
from services.primitives.integer_type import Integer
|
||||||
|
|
||||||
def process_rule(state, lhs: UUID, rhs: UUID):
|
def process_rule(state, lhs: UUID, rhs: UUID):
|
||||||
|
|
@ -90,9 +91,9 @@ def rewrite(state, lhs_m: UUID, rhs_m: UUID, pattern_mm: UUID, name_mapping: dic
|
||||||
# assume the type of the object is already the original type
|
# assume the type of the object is already the original type
|
||||||
# this is because primitive types (e.g., Integer) are not RAMified
|
# this is because primitive types (e.g., Integer) are not RAMified
|
||||||
type_name = od.get_object_name(bottom, pattern_mm, rhs_type)
|
type_name = od.get_object_name(bottom, pattern_mm, rhs_type)
|
||||||
if type_name == "String":
|
if type_name == "ActionCode":
|
||||||
# Assume the string is a Python expression to evaluate
|
# Assume the string is a Python expression to evaluate
|
||||||
python_expr = String(UUID(bottom.read_value(rhs_el_to_create)), bottom.state).read()
|
python_expr = ActionCode(UUID(bottom.read_value(rhs_el_to_create)), bottom.state).read()
|
||||||
result = eval(python_expr, {}, {})
|
result = eval(python_expr, {}, {})
|
||||||
# Write the result into the host model.
|
# Write the result into the host model.
|
||||||
# This will be the *value* of an attribute. The attribute-link (connecting an object to the attribute) will be created as an edge later.
|
# This will be the *value* of an attribute. The attribute-link (connecting an object to the attribute) will be created as an edge later.
|
||||||
|
|
@ -102,7 +103,7 @@ def rewrite(state, lhs_m: UUID, rhs_m: UUID, pattern_mm: UUID, name_mapping: dic
|
||||||
m_od.create_string_value(model_el_name_to_create, result)
|
m_od.create_string_value(model_el_name_to_create, result)
|
||||||
name_mapping[pattern_name_to_create] = model_el_name_to_create
|
name_mapping[pattern_name_to_create] = model_el_name_to_create
|
||||||
else:
|
else:
|
||||||
raise Exception(f"RHS element '{pattern_name_to_create}' needs to be created in host, but has no un-RAMified type, and I don't know what to do with it. It's type is", type_name)
|
raise Exception(f"RHS element '{pattern_name_to_create}' needs to be created in host, but has no un-RAMified type, and I don't know what to do with it. It's type is '{type_name}'")
|
||||||
|
|
||||||
# print("create edges....")
|
# print("create edges....")
|
||||||
for pattern_name_to_create, rhs_el_to_create, original_type, original_type_name, model_el_name_to_create in edges_to_create:
|
for pattern_name_to_create, rhs_el_to_create, original_type, original_type_name, model_el_name_to_create in edges_to_create:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue