93 lines
3.7 KiB
Python
93 lines
3.7 KiB
Python
import os.path
|
|
from framework.conformance import Conformance, render_conformance_check_result
|
|
from concrete_syntax.textual_od import parser
|
|
from concrete_syntax.common import indent
|
|
from transformation.rule import Rule
|
|
|
|
# parse model and check conformance
|
|
def parse_and_check(state, m_cs, mm, descr: str, check_conformance=True, type_transform=lambda type_name: type_name, name_generator=parser.DefaultNameGenerator()):
|
|
try:
|
|
m = parser.parse_od(
|
|
state,
|
|
m_text=m_cs,
|
|
mm=mm,
|
|
type_transform=type_transform,
|
|
name_generator=name_generator,
|
|
)
|
|
except Exception as e:
|
|
e.add_note("While parsing model " + descr)
|
|
raise
|
|
try:
|
|
if check_conformance:
|
|
conf = Conformance(state, m, mm)
|
|
errors = conf.check_nominal()
|
|
if len(errors) > 0:
|
|
print(render_conformance_check_result(errors))
|
|
print(" model: " + descr)
|
|
except Exception as e:
|
|
e.add_note("In model " + descr)
|
|
raise
|
|
return m
|
|
|
|
# get file contents as string
|
|
def read_file(filename):
|
|
with open(filename) as file:
|
|
return file.read()
|
|
|
|
KINDS = ["nac", "lhs", "rhs"]
|
|
|
|
# Phony name generator that raises an error if you try to use it :)
|
|
class LHSNameGenerator:
|
|
def __call__(self, type_name):
|
|
raise Exception(f"Error: Object or link of type '{type_name}' does not have a name.\nAnonymous objects/links are not allowed in the LHS of a rule, because they can have unintended consequences. Please give all of the elements in the LHS explicit names.")
|
|
|
|
# load model transformation rules
|
|
def load_rules(state, get_filename, rt_mm_ramified, rule_names, check_conformance=True):
|
|
rules = {}
|
|
|
|
files_read = []
|
|
|
|
for rule_name in rule_names:
|
|
rule = {}
|
|
|
|
def parse(kind):
|
|
filename = get_filename(rule_name, kind)
|
|
descr = "'"+filename+"'"
|
|
if kind == "nac":
|
|
suffix = ""
|
|
nacs = []
|
|
try:
|
|
while True:
|
|
base, ext = os.path.splitext(filename)
|
|
processed_filename = base+suffix+ext
|
|
nac = parse_and_check(state, read_file(processed_filename), rt_mm_ramified, descr, check_conformance)
|
|
nacs.append(nac)
|
|
suffix = "2" if suffix == "" else str(int(suffix)+1)
|
|
files_read.append(processed_filename)
|
|
except FileNotFoundError:
|
|
if suffix == "":
|
|
print(f"Warning: rule {rule_name} has no NAC ({filename} not found)")
|
|
return nacs
|
|
else:
|
|
try:
|
|
if kind == "lhs":
|
|
m = parse_and_check(state, read_file(filename), rt_mm_ramified, descr, check_conformance, name_generator=LHSNameGenerator())
|
|
elif kind == "rhs":
|
|
m = parse_and_check(state, read_file(filename), rt_mm_ramified, descr, check_conformance)
|
|
files_read.append(filename)
|
|
return m
|
|
except FileNotFoundError as e:
|
|
print(f"Warning: using empty {kind} ({filename} not found)")
|
|
# Use empty model as fill-in:
|
|
return parse_and_check(
|
|
state,
|
|
"",
|
|
rt_mm_ramified,
|
|
descr="'"+filename+"'",
|
|
check_conformance=check_conformance)
|
|
|
|
rules[rule_name] = Rule(*(parse(kind) for kind in KINDS))
|
|
|
|
print("Rules loaded:\n" + indent('\n'.join(files_read), 4))
|
|
|
|
return rules
|