model_bootstrap_visitor.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. from hutn_compiler.visitor import Visitor
  2. from hutn_compiler.hutnparser import Tree
  3. from hutn_compiler.compiler import main as do_compile
  4. import os
  5. import uuid
  6. def empty(s):
  7. return None
  8. class ModelBootstrapVisitor(Visitor):
  9. def __init__(self, args):
  10. Visitor.__init__(self, args)
  11. model_name = [arg.split(":", 1)[1] for arg in args if arg.startswith("--modelname:")][0]
  12. self.code = "Void function initialize_%s():\n" % model_name
  13. self.free_id = 0
  14. self.names = set()
  15. self.current_model = None
  16. self.current_element = []
  17. self.includes = []
  18. def dump(self):
  19. return self.code + "\treturn!"
  20. def __getattr__(self, attr):
  21. if attr.startswith("visit_"):
  22. return empty
  23. else:
  24. raise AttributeError()
  25. def visit_start(self, tree):
  26. for t in Tree.get_tail(tree):
  27. self.visit(t)
  28. self.code += '\tdict_overwrite(%s, "types", get_type_mapping(%s))\n' % (self.current_model, self.current_model)
  29. def visit_include_files(self, tree):
  30. self.includes.append('include %s' % Tree.get_text(Tree.get_children(tree, "STRVALUE")[0]))
  31. def visit_import(self, tree):
  32. url = Tree.get_children(tree, "MV_URL")[0]
  33. target = Tree.get_children(tree, "MODEL_ID")[0]
  34. #self.constructors.extend(["import_node", url.get_text(), target.get_text()])
  35. self.code += '\tElement %s\n' % Tree.get_text(target)
  36. self.code += '\t%s = import_node("%s")\n' % (Tree.get_text(target), Tree.get_text(url))
  37. def visit_export(self, tree):
  38. url = Tree.get_children(tree, "MV_URL")[0]
  39. target = Tree.get_children(tree, "MODEL_ID")[0]
  40. #self.constructors.extend(["export_node", target.get_text(), url.get_text()])
  41. self.code += '\texport_node("%s", %s)\n' % (Tree.get_text(url), Tree.get_text(target))
  42. def visit_model(self, tree):
  43. children = Tree.get_children(tree, "MODEL_ID")
  44. model_type = Tree.get_text(children[0])
  45. model_name = Tree.get_text(children[-1])
  46. #self.constructors.extend(["instantiate_model", model_type, model_name])
  47. self.code += "\tElement %s\n" % model_name
  48. self.code += '\t%s = instantiate_model(%s)\n' % (model_name, model_type)
  49. self.current_model = model_name
  50. self.names = set()
  51. for element in Tree.get_children(tree, "model_element"):
  52. self.visit(element)
  53. def visit_model_element(self, tree):
  54. children = Tree.get_children(tree, "MODEL_ID")
  55. element_type = Tree.get_text(children[0])
  56. if len(children) == 2 or len(children) == 4:
  57. element_name = Tree.get_text(children[1])
  58. else:
  59. element_name = "__%s" % self.free_id
  60. self.free_id += 1
  61. if element_name in self.names:
  62. raise Exception("Redefinition of element %s" % element_name)
  63. if len(children) > 2:
  64. # So we have a source and target; but aren't sure which is which, because the name is optional!
  65. source_name = Tree.get_text(children[-2])
  66. target_name = Tree.get_text(children[-1])
  67. if source_name not in self.names:
  68. raise Exception("Source of link %s unknown: %s" % (element_name, source_name))
  69. if target_name not in self.names:
  70. raise Exception("Target of link %s unknown: %s" % (element_name, target_name))
  71. #self.constructors.extend(["instantiate_link", self.current_model, element_type, element_name, source_name, target_name])
  72. self.code += '\tinstantiate_link(%s, "%s", "%s", "%s", "%s")\n' % (self.current_model, element_type, element_name, source_name, target_name)
  73. else:
  74. #self.constructors.extend(["instantiate_node", self.current_model, element_type, element_name])
  75. self.code += '\tinstantiate_node(%s, "%s", "%s")\n' % (self.current_model, element_type, element_name)
  76. self.names.add(element_name)
  77. self.current_element.append(element_name)
  78. if Tree.get_children(tree, "inheritance"):
  79. self.visit(Tree.get_children(tree, "inheritance")[0])
  80. for attr in Tree.get_children(tree, "model_attribute"):
  81. self.visit(attr)
  82. self.current_element.pop()
  83. return element_name
  84. def visit_inheritance(self, tree):
  85. for token in Tree.get_children(tree, "MODEL_ID"):
  86. superclass = Tree.get_text(token)
  87. if superclass not in self.names:
  88. raise Exception("Superclass %s is undefined" % superclass)
  89. #self.constructors.extend(["instantiate_link", self.current_model, "Inheritance", "%s_inherits_from_%s" % (self.current_element[-1], superclass), self.current_element[-1], superclass])
  90. self.code += '\tinstantiate_link(%s, "Inheritance", "%s_inherits_from_%s", "%s", "%s")\n' % (self.current_model, self.current_element[-1], superclass, self.current_element[-1], superclass)
  91. self.names.add("%s_inherits_from_%s" % (self.current_element[-1], superclass))
  92. def visit_model_attribute(self, tree):
  93. children = Tree.get_children(tree, "MODEL_ID")
  94. is_definition = bool(Tree.get_children(tree, "COLON"))
  95. is_assign = bool(Tree.get_children(tree, "model_attr_instance"))
  96. is_nested = bool(Tree.get_children(tree, "model_element"))
  97. if is_definition:
  98. attr_name = Tree.get_text(children[0])
  99. attr_optional = len(Tree.get_children(tree, "OPTIONAL")) > 0
  100. attr_type = Tree.get_text(children[1])
  101. #self.constructors.extend(["model_define_attribute", self.current_model, self.current_element[-1], attr_name, attr_optional, attr_type])
  102. self.code += '\tmodel_define_attribute(%s, "%s", "%s", %s, "%s")\n' % (self.current_model, self.current_element[-1], attr_name, attr_optional, attr_type)
  103. full_attribute_name = self.current_element[-1] + "_" + attr_name
  104. if is_assign:
  105. # There are also some attributes to set!
  106. self.current_element.append(full_attribute_name)
  107. for f in Tree.get_children(tree, "model_attr_instance"):
  108. self.visit(f)
  109. self.current_element.pop()
  110. elif is_assign:
  111. self.visit(Tree.get_children(tree, "model_attr_instance")[0])
  112. elif is_nested:
  113. if Tree.get_children(tree, "MODEL_ID"):
  114. contains_link = Tree.get_text(Tree.get_children(tree, "MODEL_ID")[0])
  115. else:
  116. contains_link = ""
  117. entry = self.visit(Tree.get_children(tree, "model_element")[0])
  118. #self.constructors.extend(["instantiate_link", self.current_model, contains_link, "__%s" % self.free_id, self.current_element[-1], entry])
  119. self.code += '\tinstantiate_link(%s, "%s", "__%s", "%s", "%s")\n' % (self.current_model, contains_link, self.free_id, self.current_element[-1], entry)
  120. self.names.add("__%s" % self.free_id)
  121. self.free_id += 1
  122. def visit_model_attr_instance(self, tree):
  123. def constructors_compile(code):
  124. code_fragments = code.split("\n")
  125. code_fragments = [i for i in code_fragments if i.strip() != ""]
  126. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  127. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  128. code_fragments = self.includes + [i[initial_tabs:] for i in code_fragments]
  129. code = "\n".join(code_fragments)
  130. code += "\n"
  131. with open(".code.alc", 'w') as f:
  132. f.write(code)
  133. f.flush()
  134. directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0]
  135. compiled = do_compile(".code.alc", directory + "/../grammars/actionlanguage.g", "CS")
  136. return compiled
  137. children = Tree.get_children(tree, "MODEL_ID")
  138. attr_name = Tree.get_text(children[0])
  139. if Tree.get_children(tree, "value"):
  140. # Value attribute
  141. attr_value = Tree.get_tail(Tree.get_children(tree, "value")[0])[0]
  142. if attr_value['head'] == "STRVALUE":
  143. attr_value = '"%s"' % Tree.get_text(attr_value)[1:-1]
  144. elif attr_value['head'] == "TRUE":
  145. attr_value = True
  146. elif attr_value['head'] == "FALSE":
  147. attr_value = False
  148. elif attr_value['head'] == "DEC_NUMBER":
  149. attr_value = int(Tree.get_text(attr_value))
  150. elif attr_value.head == "FLOAT_NUMBER":
  151. attr_value = float(Tree.get_text(attr_value))
  152. else:
  153. raise Exception(attr_value['head'])
  154. #self.constructors.extend(["instantiate_attribute", self.current_model, self.current_element[-1], attr_name, attr_value])
  155. self.code += '\tinstantiate_attribute(%s, "%s", "%s", %s)\n' % (self.current_model, self.current_element[-1], attr_name, attr_value)
  156. elif Tree.get_children(tree, "DOLLAR"):
  157. # Coded attribute
  158. raise Exception("Code is no longer allowed in bootstrap files, as the HUTN parser is not initialized yet")
  159. #self.constructors.extend(["instantiate_attribute_code", self.current_model, self.current_element[-1], attr_name])
  160. #self.constructors.extend(constructors_compile(tree.get_children("ANYTHING_EXCEPT_DOLLAR")[0].get_text()))
  161. code = Tree.get_text(Tree.get_children(tree, "ANYTHING_EXCEPT_DOLLAR")[0])
  162. code_fragments = code.split("\n")
  163. code_fragments = [i for i in code_fragments if i.strip() != ""]
  164. code_fragments = [i.replace(" ", "\t") for i in code_fragments]
  165. initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
  166. code_fragments = [i[initial_tabs:] for i in code_fragments]
  167. code_fragments.append("")
  168. code = "\n".join(code_fragments)
  169. func_name = "__code__%s" % abs(hash(code))
  170. self.code += '\tinstantiate_attribute_code(%s, "%s", "%s", %s)\n' % (self.current_model, self.current_element[-1], attr_name, func_name)
  171. # Rewrite the name of the function to func_name
  172. prepend = code
  173. before, after = prepend.split("function ", 1)
  174. before = before + "function "
  175. after = "(" + after.split("(", 1)[1]
  176. prepend = before + func_name + after + "\n"
  177. # And prepend the actual code block
  178. self.code = prepend + self.code