model_visitor.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. from hutn_compiler.visitor import Visitor
  2. from hutn_compiler.compiler import main as do_compile
  3. from hutn_compiler.hutnparser import Tree
  4. import os
  5. def empty(s):
  6. return None
  7. class ModelVisitor(Visitor):
  8. def __init__(self, args):
  9. Visitor.__init__(self, args)
  10. self.constructors = []
  11. self.free_id = 0
  12. self.names = set()
  13. self.current_element = []
  14. self.includes = []
  15. def dump(self):
  16. return [len(self.constructors)] + self.constructors
  17. def __getattr__(self, attr):
  18. if attr.startswith("visit_"):
  19. return empty
  20. else:
  21. raise AttributeError()
  22. def visit_start(self, tree):
  23. for t in Tree.get_tail(tree):
  24. self.visit(t)
  25. def visit_include_files(self, tree):
  26. self.includes.append('include %s' % Tree.get_text(Tree.get_children(tree, "STRVALUE")[0]))
  27. def visit_model_element(self, tree):
  28. children = Tree.get_children(tree, "MODEL_ID")
  29. element_type = Tree.get_text(children[0])
  30. if len(children) == 2 or len(children) == 4:
  31. element_name = Tree.get_text(children[1])
  32. else:
  33. element_name = "__%s" % self.free_id
  34. self.free_id += 1
  35. if element_name in self.names:
  36. raise Exception("Redefinition of element %s" % element_name)
  37. if len(children) > 2:
  38. # So we have a source and target; but aren't sure which is which, because the name is optional!
  39. source_name = Tree.get_text(children[-2])
  40. target_name = Tree.get_text(children[-1])
  41. if source_name not in self.names:
  42. raise Exception("Source of link %s unknown: %s" % (element_name, source_name))
  43. if target_name not in self.names:
  44. raise Exception("Target of link %s unknown: %s" % (element_name, target_name))
  45. self.constructors.extend(["instantiate_link", element_type, element_name, source_name, target_name])
  46. else:
  47. self.constructors.extend(["instantiate_node", element_type, element_name])
  48. self.names.add(element_name)
  49. self.current_element.append(element_name)
  50. if Tree.get_children(tree, "inheritance"):
  51. self.visit(Tree.get_children(tree, "inheritance")[0])
  52. for attr in Tree.get_children(tree, "model_attribute"):
  53. self.visit(attr)
  54. self.current_element.pop()
  55. return element_name
  56. def visit_inheritance(self, tree):
  57. for token in Tree.get_children(tree, "MODEL_ID"):
  58. superclass = Tree.get_text(token)
  59. if superclass not in self.names:
  60. raise Exception("Superclass %s is undefined" % superclass)
  61. self.constructors.extend(["instantiate_link", "Inheritance", "%s_inherits_from_%s" % (self.current_element[-1], superclass), self.current_element[-1], superclass])
  62. self.names.add("%s_inherits_from_%s" % (self.current_element[-1], superclass))
  63. def visit_model_attribute(self, tree):
  64. children = Tree.get_children(tree, "MODEL_ID")
  65. is_definition = bool(Tree.get_children(tree, "COLON"))
  66. is_assign = bool(Tree.get_children(tree, "model_attr_instance"))
  67. is_nested = bool(Tree.get_children(tree, "model_element"))
  68. if is_definition:
  69. attr_name = Tree.get_text(children[0])
  70. attr_optional = len(Tree.get_children(tree, "OPTIONAL")) > 0
  71. attr_type = Tree.get_text(children[1])
  72. if attr_type not in self.names:
  73. raise Exception("Unknown Attribute type!")
  74. self.constructors.extend(["model_define_attribute", self.current_element[-1], attr_name, attr_optional, attr_type])
  75. full_attribute_name = self.current_element[-1] + "_" + attr_name
  76. if is_assign:
  77. # There are also some attributes to set!
  78. self.current_element.append(full_attribute_name)
  79. for f in Tree.get_children(tree, "model_attr_instance"):
  80. self.visit(f)
  81. self.current_element.pop()
  82. elif is_assign:
  83. self.visit(Tree.get_children(tree, "model_attr_instance")[0])
  84. elif is_nested:
  85. if Tree.get_children(tree, "MODEL_ID"):
  86. contains_link = Tree.get_text(Tree.get_children(tree, "MODEL_ID")[0])
  87. else:
  88. contains_link = ""
  89. entry = self.visit(Tree.get_children(tree, "model_element")[0])
  90. self.constructors.extend(["instantiate_link", contains_link, "__%s" % self.free_id, self.current_element[-1], entry])
  91. self.names.add("__%s" % self.free_id)
  92. self.free_id += 1
  93. def visit_model_attr_instance(self, tree):
  94. def constructors_compile(code):
  95. code_fragments = code.split("\n")
  96. code_fragments = [i for i in code_fragments if i.strip() != ""]
  97. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  98. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  99. code_fragments = self.includes + [i[initial_tabs:] for i in code_fragments]
  100. code = "\n".join(code_fragments)
  101. code += "\n"
  102. with open(".code.alc", 'w') as f:
  103. f.write(code)
  104. f.flush()
  105. directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0]
  106. compiled = do_compile(".code.alc", directory + "/../grammars/actionlanguage.g", "CS")
  107. return compiled + [code]
  108. children = Tree.get_children(tree, "MODEL_ID")
  109. attr_name = Tree.get_text(children[0])
  110. if Tree.get_children(tree, "value"):
  111. # Value attribute
  112. attr_value = Tree.get_tail(Tree.get_children(tree, "value")[0])[0]
  113. if attr_value['head'] == "STRVALUE":
  114. attr_value = Tree.get_text(attr_value)[1:-1]
  115. elif attr_value['head'] == "LONG_STR":
  116. attr_value = Tree.get_text(attr_value)[3:-3]
  117. elif attr_value['head'] == "TRUE":
  118. attr_value = True
  119. elif attr_value['head'] == "FALSE":
  120. attr_value = False
  121. elif attr_value['head'] == "DEC_NUMBER":
  122. attr_value = int(Tree.get_text(attr_value))
  123. elif attr_value['head'] == "FLOAT_NUMBER":
  124. attr_value = float(Tree.get_text(attr_value))
  125. else:
  126. raise Exception(attr_value['head'])
  127. self.constructors.extend(["instantiate_attribute", self.current_element[-1], attr_name, attr_value])
  128. elif Tree.get_children(tree, "DOLLAR"):
  129. # Coded attribute
  130. self.constructors.extend(["instantiate_attribute_code", self.current_element[-1], attr_name])
  131. self.constructors.extend(constructors_compile(Tree.get_text(Tree.get_children(tree, "ANYTHING_EXCEPT_DOLLAR")[0])))