import xml.etree.ElementTree as ET from abc import ABC, abstractmethod from constants import * class GeneralUnparser: def __init__(self, input: str or ET.Element, from_xml: bool = False, indentation_character: str = " ", endline: str = "\n", instream_begin_delimiter: str = "", instream_end_delimiter: str = "", outstream_begin_delimiter: str = "", outstream_end_delimiter: str = "", return_string: str = "return", function_return_type_indicator_predicate: str = "returns", arg_start_delimiter: str = "(", arg_end_delimiter: str = ")", arg_separator: str = ",", loop_start_delimiter: str = "loop (", loop_end_delimiter: str = ")", assignment_character: str = '=', conditional_start_delimiter: str = "if (", conditional_end_delimiter: str = ")", conditional_case_delimiter: str = "else if (", conditional_else_delimiter: str = "else", block_start_delimiter: str = "{", block_end_delimiter: str = "}", strip_conditionals: bool = False, ): self.endline = endline self.indentation_character = indentation_character self.indentation = 0 self.stream_delimiters = { "instream_begin": instream_begin_delimiter, "instream_end": instream_end_delimiter, "outstream_begin": outstream_begin_delimiter, "outstream_end": outstream_end_delimiter } self.arg_delimiters = (arg_start_delimiter, arg_end_delimiter, arg_separator) self.loop_delimiters = (loop_start_delimiter, loop_end_delimiter) self.conditional_delimiters = (conditional_start_delimiter, conditional_end_delimiter, conditional_case_delimiter, conditional_else_delimiter) self.return_string = return_string self.return_indicator = function_return_type_indicator_predicate self.assignment_character = assignment_character self.block_delimiters = (block_start_delimiter, block_end_delimiter) self.strip_conditionals = strip_conditionals if from_xml: self.xml = input self.source = None else: self.source = input self.xml = None def unparse(self): """ @brief unparses the xml into valid gazprea code :return: a string of valid gazprea code """ self.source = "" for node in self.xml: self.unparse_node(node) def unparse_node(self, node): if node.tag not in [GAZ_VAR_TAG, GAZ_RHS_TAG, GAZ_LHS_TAG, GAZ_LIT_TAG, GAZ_OPERATOR_TAG]: self.source += self.indentation_character * self.indentation if node.tag == GAZ_BLOCK_TAG: self.unparse_block(node) elif node.tag == GAZ_DECLARATION_TAG: self.unparse_declaration(node) elif node.tag == GAZ_RETURN_TAG: self.unparse_return(node) elif node.tag == GAZ_OPERATOR_TAG: self.unparse_operator(node) elif node.tag == GAZ_UNARY_OPERATOR_TAG: self.unparse_unary(node) elif node.tag == GAZ_STREAM_TAG: self.unparse_stream(node) elif node.tag == GAZ_LIT_TAG: self.unparse_literal(node) elif node.tag == GAZ_PROCEDURE_TAG or node.tag == GAZ_FUNCTION_TAG: self.unparse_routine(node) elif node.tag == GAZ_VAR_TAG: self.unparse_variable(node) elif node.tag == GAZ_RHS_TAG or node.tag == GAZ_LHS_TAG: self.unparse_xhs(node) elif node.tag == GAZ_LIT_TAG: self.unparse_literal(node) elif node.tag == GAZ_ASSIGNMENT_TAG: self.unparse_assignment(node) elif node.tag == GAZ_IF_TAG: self.unparse_conditional(node) elif node.tag == GAZ_LOOP_TAG: self.unparse_loop(node) else: raise Exception("Unknown tag: " + node.tag) def unparse_block(self, node): self.source += f"{self.indentation * self.indentation_character}{self.block_delimiters[0]}\n" self.indentation += 4 for child in node: self.unparse_node(child) self.indentation -= 4 if node.get(GAZ_TY_KEY) is None: self.source += f"{self.indentation * self.indentation_character}{self.block_delimiters[1]}\n\n" elif node.get(GAZ_TY_KEY) in [GAZ_TRUE_BLOCK_TAG, GAZ_FALSE_BLOCK_TAG]: self.source += f"{self.indentation * self.indentation_character}{self.block_delimiters[1]}" def unparse_declaration(self, node, declaration_op: str = '='): variable = node.find(GAZ_VAR_TAG) rhs = node.find(GAZ_RHS_TAG) self.unparse_variable(variable, True) self.source += f" {declaration_op} " self.unparse_node(rhs) self.source += self.endline def unparse_variable(self, node, is_declaration: bool = False): if node is None: raise ValueError("Node is None") mut = node.get(GAZ_QUALIFIER_KEY) type = node.get(GAZ_TY_KEY) name = node.get(GAZ_NAME_KEY) self.source += self.format_variable(mut, self.translate_type(type), name, is_declaration) def unparse_stream(self, node): if node.get(GAZ_TY_KEY) == GAZ_OUT_STREAM: self.unparse_outstream(node) elif node.get(GAZ_TY_KEY) == GAZ_IN_STREAM: self.unparse_instream(node) def unparse_instream(self, node): self.source += self.stream_delimiters["instream_begin"] for child in node: self.unparse_node(child) self.source += self.stream_delimiters["instream_end"] self.source += self.endline def unparse_outstream(self, node): self.source += self.stream_delimiters["outstream_begin"] for child in node: self.unparse_node(child) self.source += self.stream_delimiters["outstream_end"] self.source += self.endline def unparse_literal(self, node): self.source += "{}".format(self.translate_value(node.get(GAZ_VAL_KEY))) def unparse_xhs(self, node): for child in node: self.unparse_node(child) def unparse_operator(self, node): self.unparse_xhs(node.find(GAZ_LHS_TAG)) self.source += " {} ".format(self.translate_op(node.get("op"))) self.unparse_xhs(node.find(GAZ_RHS_TAG)) def unparse_return(self, node): self.source += self.return_string + " " for child in node: self.unparse_node(child) self.source += self.endline def unparse_routine(self, node): return_type = "" if node.get(GAZ_RETURN_KEY) not in [None, GAZ_VOID_TYPE, ""]: return_type = self.return_indicator + " " + self.translate_type(node.get(GAZ_RETURN_KEY)) args = [] for child in node: if child.tag == GAZ_ARG_TAG: args.append(child) args = self.unparse_argument(args) name = node.get(GAZ_NAME_KEY) self.source += self.function_declaration(node.tag, args, name, return_type) for child in node: if child.tag == GAZ_ARG_TAG: continue self.unparse_node(child) # cls.source += "}\n\n" #blocks are already there def function_declaration(self, xml_tag, args, name, return_type): return "{} {}{} {} ".format( xml_tag, name, args, return_type, ) def unparse_argument(self, nodes): if len(nodes) == 0: return self.arg_delimiters[0] + self.arg_delimiters[1] args = self.arg_delimiters[0] for i in range(len(nodes)): args += self.unparse_single_arg(nodes[i]) if i < len(nodes) - 1: args += self.arg_delimiters[2] + " " args += self.arg_delimiters[1] return args def unparse_assignment(self, element_in: ET.Element): self.unparse_variable(element_in.find(GAZ_VAR_TAG), False) self.source += " {} ".format(self.assignment_character) self.unparse_node(element_in.find(GAZ_RHS_TAG)) self.source += self.endline def unparse_conditional(self, element_in: ET.Element): self.source += self.conditional_delimiters[0] i = 0 for node in element_in: if node.tag == GAZ_IF_TAG: if self.strip_conditionals: self.source += (self.conditional_delimiters[2] + " ").strip() else: self.source += (self.conditional_delimiters[2]) # TODO this does wrong self.unparse_conditional(node) elif node.tag != GAZ_BLOCK_TAG: self.unparse_node(node) if self.strip_conditionals: self.source += (self.conditional_delimiters[1] + " ").strip() else: self.source += (self.conditional_delimiters[1] + " ") elif node.tag == GAZ_BLOCK_TAG: self.source += self.indentation * self.indentation_character if node.get(GAZ_TY_KEY) == GAZ_TRUE_BLOCK_TAG: self.unparse_node(node) elif node.get(GAZ_TY_KEY) == GAZ_FALSE_BLOCK_TAG: if self.strip_conditionals: self.source += (self.conditional_delimiters[3] + " ").strip() else: self.source += (" " + self.conditional_delimiters[3] + " ") self.unparse_node(node) else: self.unparse_node(node) i += 1 def unparse_loop(self, element_in: ET.Element): self.source += self.loop_delimiters[0] i = 0 for node in element_in: if node.tag != GAZ_BLOCK_TAG: self.unparse_node(node) if self.strip_conditionals: self.source += (self.loop_delimiters[1] + " ").strip() else: self.source += (self.loop_delimiters[1] + " ") elif node.tag == GAZ_BLOCK_TAG: self.unparse_node(node) i += 1 def unparse_unary(self, element_in: ET.Element): self.source += "{}".format(self.translate_op(element_in.get("op"))) self.unparse_xhs(element_in.find(GAZ_RHS_TAG)) def unparse_single_arg(self, param): return self.format_single_arg(self.translate_type(param.get(GAZ_TY_KEY)), param.get(GAZ_NAME_KEY)) def unparse_routine_call(self, element_in: ET.Element): pass def unparse_statement(self, element_in: ET.Element): pass def unparse_top_block(self, element_in: ET.Element): pass def unparse_expression(self, element_in: ET.Element): pass def format_variable(self, mut, name, value, declaration: bool = False): raise NotImplementedError def translate_value(self, val): raise NotImplementedError def translate_op(self, param): raise NotImplementedError def translate_type(self, ty): raise NotImplementedError def format_single_arg(self, param, param1): raise NotImplementedError