loader.py 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import os.path
  2. from framework.conformance import Conformance, render_conformance_check_result
  3. from concrete_syntax.textual_od import parser
  4. from concrete_syntax.common import indent
  5. from transformation.rule import Rule
  6. # parse model and check conformance
  7. def parse_and_check(state, m_cs, mm, descr: str, check_conformance=True, type_transform=lambda type_name: type_name, name_generator=parser.DefaultNameGenerator()):
  8. try:
  9. m = parser.parse_od(
  10. state,
  11. m_text=m_cs,
  12. mm=mm,
  13. type_transform=type_transform,
  14. name_generator=name_generator,
  15. )
  16. except Exception as e:
  17. e.add_note("While parsing model " + descr)
  18. raise
  19. try:
  20. if check_conformance:
  21. conf = Conformance(state, m, mm)
  22. errors = conf.check_nominal()
  23. if len(errors) > 0:
  24. print(render_conformance_check_result(errors))
  25. print(" model: " + descr)
  26. except Exception as e:
  27. e.add_note("In model " + descr)
  28. raise
  29. return m
  30. # get file contents as string
  31. def read_file(filename):
  32. with open(filename) as file:
  33. return file.read()
  34. KINDS = ["nac", "lhs", "rhs"]
  35. # Phony name generator that raises an error if you try to use it :)
  36. class LHSNameGenerator:
  37. def __call__(self, type_name):
  38. if type_name == "GlobalCondition":
  39. return parser.DefaultNameGenerator()(type_name)
  40. 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.")
  41. # load model transformation rules
  42. def load_rules(state, get_filename, rt_mm_ramified, rule_names, check_conformance=True):
  43. rules = {}
  44. files_read = []
  45. for rule_name in rule_names:
  46. rule = {}
  47. def parse(kind):
  48. filename = get_filename(rule_name, kind)
  49. descr = "'"+filename+"'"
  50. if kind == "nac":
  51. suffix = ""
  52. nacs = []
  53. try:
  54. while True:
  55. base, ext = os.path.splitext(filename)
  56. processed_filename = base+suffix+ext
  57. nac = parse_and_check(state, read_file(processed_filename), rt_mm_ramified, descr, check_conformance)
  58. nacs.append(nac)
  59. suffix = "2" if suffix == "" else str(int(suffix)+1)
  60. files_read.append(processed_filename)
  61. except FileNotFoundError:
  62. if suffix == "":
  63. print(f"Warning: rule {rule_name} has no NAC ({filename} not found)")
  64. return nacs
  65. else:
  66. try:
  67. if kind == "lhs":
  68. m = parse_and_check(state, read_file(filename), rt_mm_ramified, descr, check_conformance, name_generator=LHSNameGenerator())
  69. elif kind == "rhs":
  70. m = parse_and_check(state, read_file(filename), rt_mm_ramified, descr, check_conformance)
  71. files_read.append(filename)
  72. return m
  73. except FileNotFoundError as e:
  74. print(f"Warning: using empty {kind} ({filename} not found)")
  75. # Use empty model as fill-in:
  76. return parse_and_check(
  77. state,
  78. "",
  79. rt_mm_ramified,
  80. descr="'"+filename+"'",
  81. check_conformance=check_conformance)
  82. rules[rule_name] = Rule(*(parse(kind) for kind in KINDS))
  83. print("Rules loaded:\n" + indent('\n'.join(files_read), 4))
  84. return rules