From 64a92871d9ae1364490b88ebf2f8ad0b80722f5e Mon Sep 17 00:00:00 2001 From: ayrton Date: Sun, 19 Nov 2023 14:40:57 -0700 Subject: [PATCH] Extracted the unparser logic to a superclass Took 1 hour 1 minute --- ast_parser/gaz_unparser.py | 223 +++--------------------- ast_parser/general_unparser.py | 304 +++++++++++++++++++++++++++------ 2 files changed, 275 insertions(+), 252 deletions(-) diff --git a/ast_parser/gaz_unparser.py b/ast_parser/gaz_unparser.py index 9be45d1..c149c24 100644 --- a/ast_parser/gaz_unparser.py +++ b/ast_parser/gaz_unparser.py @@ -64,212 +64,37 @@ def to_gaz_op(param): class GazUnparser(GeneralUnparser): - def __init__(self, input: str or ET.Element, from_xml: bool = False): - self.indentation = 0 - if from_xml: - self.xml = input - self.source = None + def __init__(self, input_ast, from_xml: bool = False): + super().__init__( input=input_ast, from_xml=from_xml, + endline=";\n", + instream_end_delimiter=" <- std_input", + outstream_end_delimiter=" -> std_output",) + + def format_variable(self, mut, ty, name, declaration: bool = False): + if declaration: + return "{} {} {}".format(mut, ty, name) else: - self.source = input - self.xml = None + return "{}".format(name) - 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 - - 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) + def translate_value(self, val): + if val in ["True", "False"]: + return val.lower() else: - raise Exception("Unknown tag: " + node.tag) + return str(val) - def unparse_block(self, node): - self.source += "{\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 += "}\n\n" - elif node.get(GAZ_TY_KEY) in [GAZ_TRUE_BLOCK_TAG, GAZ_FALSE_BLOCK_TAG]: - self.source += "}" + def translate_op(self, param): + return to_gaz_op(param) - def unparse_declaration(self, node): - variable = node.find(GAZ_VAR_TAG) - rhs = node.find(GAZ_RHS_TAG) - self.unparse_variable(variable, True) - self.source += " = " - self.unparse_node(rhs) - self.source += ";\n" + def translate_type(self, ty): + return to_gazprea_type(ty) - def unparse_variable(self, node, is_declaration = False): - if is_declaration: - mut = node.get(GAZ_QUALIFIER_KEY) - type = to_gazprea_type(node.get(GAZ_TY_KEY)) - name = node.get(GAZ_NAME_KEY) - - self.source += "{} {} {}".format(mut, type, name) - else: - self.source += "{}".format(node.get(GAZ_NAME_KEY)) - - 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): - for child in node: - self.unparse_node(child) - - self.source += "<- {};\n".format(GAZ_IN_STREAM) - - def unparse_outstream(self, node): - for child in node: - self.unparse_node(child) - - self.source += " -> {};\n".format(GAZ_OUT_STREAM) - - def unparse_literal(self, node): - self.source += "{}".format(to_gaz_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(to_gaz_op(node.get("op"))) - self.unparse_xhs(node.find(GAZ_RHS_TAG)) - - def unparse_return(self, node): - self.source += "return " - for child in node: - self.unparse_node(child) - self.source += ";\n" - - def unparse_routine(self, node): - return_type = "" - if node.get(GAZ_RETURN_KEY) not in [None, GAZ_VOID_TYPE, ""]: - return_type = "returns " + to_gazprea_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) - - self.source += "{} {}{} {} ".format( - node.tag, - node.get(GAZ_NAME_KEY), + def function_declaration(self, xml_tag, args, name, return_type): + return "{} {}{} {} ".format( + xml_tag, + name, args, 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 unparse_argument(self, nodes): - if len(nodes) == 0: - return "()" - args = "(" - for i in range(len(nodes)): - args += _unparse_arg(nodes[i]) - if i < len(nodes) - 1: - args += ", " - - args += ")" - return args - - def unparse_assignment(self, element_in: ET.Element): - self.unparse_variable(element_in.find(GAZ_VAR_TAG), False) - self.source += " = " - self.unparse_node(element_in.find(GAZ_RHS_TAG)) - self.source += ";\n" - - def unparse_conditional(self, element_in: ET.Element): - self.source += "if (" - i = 0 - for node in element_in: - if node.tag == GAZ_IF_TAG: - self.source += " else " - self.unparse_conditional(node) - elif node.tag != GAZ_BLOCK_TAG: - self.unparse_node(node) - self.source += ") " - elif node.tag == GAZ_BLOCK_TAG: - if node.get(GAZ_TY_KEY) == GAZ_TRUE_BLOCK_TAG: - self.unparse_node(node) - elif node.get(GAZ_TY_KEY) == GAZ_FALSE_BLOCK_TAG: - self.source += " else " - self.unparse_node(node) - else: - self.unparse_node(node) - i += 1 - - def unparse_loop(self, element_in: ET.Element): - self.source += "loop (" - i = 0 - for node in element_in: - if node.tag != GAZ_BLOCK_TAG: - self.unparse_node(node) - self.source += ") " - elif node.tag == GAZ_BLOCK_TAG: - self.unparse_node(node) - i += 1 - - 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_unary(self, element_in: ET.Element): - self.source += " {}".format(to_gaz_op(element_in.get("op"))) - self.unparse_xhs(element_in.find(GAZ_RHS_TAG)) - - def unparse_expression(self, element_in: ET.Element): - pass + def format_single_arg(self, ty, name): + return "{} {}".format(ty, name) diff --git a/ast_parser/general_unparser.py b/ast_parser/general_unparser.py index 1c7af75..a1e37db 100644 --- a/ast_parser/general_unparser.py +++ b/ast_parser/general_unparser.py @@ -4,85 +4,283 @@ from abc import ABC, abstractmethod from constants import * -class GeneralUnparser(ABC): - @abstractmethod - def unparse(self, element_in: ET.Element): - pass +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 = "}", + ): + self.endline = endline + self.indentation_character = indentation_character + self.indentation = 0 - @abstractmethod - def unparse_node(self, element_in: ET.Element): - pass + self.stream_delimiters = { + "instream_begin": instream_begin_delimiter, + "instream_end": instream_end_delimiter, + "outstream_begin": outstream_begin_delimiter, + "outstream_end": outstream_end_delimiter + } - @abstractmethod - def unparse_top_block(self, element_in: ET.Element): - pass + 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) - @abstractmethod - def unparse_block(self, element_in: ET.Element): - pass + 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) - @abstractmethod - def unparse_routine(self, element_in: ET.Element): - pass + if from_xml: + self.xml = input + self.source = None + else: + self.source = input + self.xml = None - @abstractmethod - def unparse_argument(self, element_in: ET.Element): - pass + def unparse(self): + """ + @brief unparses the xml into valid gazprea code - @abstractmethod - def unparse_statement(self, element_in: ET.Element): - pass + :return: a string of valid gazprea code + """ + self.source = "" + for node in self.xml: + self.unparse_node(node) - @abstractmethod - def unparse_expression(self, element_in: ET.Element): - pass + 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 - @abstractmethod - def unparse_declaration(self, element_in: ET.Element): - pass + 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) - @abstractmethod - def unparse_operator(self, element_in: ET.Element): - pass + def unparse_block(self, node): + self.source += f"{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.block_delimiters[1]}\n\n" + elif node.get(GAZ_TY_KEY) in [GAZ_TRUE_BLOCK_TAG, GAZ_FALSE_BLOCK_TAG]: + self.source += f"{self.block_delimiters[1]}" - @abstractmethod - def unparse_unary(self, element_in: ET.Element): - pass + 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 - @abstractmethod - def unparse_stream(self, element_in: ET.Element): - pass + def unparse_variable(self, node, is_declaration: bool = False): + 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 - @abstractmethod def unparse_assignment(self, element_in: ET.Element): - pass + 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 - @abstractmethod def unparse_conditional(self, element_in: ET.Element): - pass + self.source += self.conditional_delimiters[0] + i = 0 + for node in element_in: + if node.tag == GAZ_IF_TAG: + self.source += self.conditional_delimiters[2] # TODO this does wrong + self.unparse_conditional(node) + elif node.tag != GAZ_BLOCK_TAG: + self.unparse_node(node) + self.source += self.conditional_delimiters[1] + " " + elif node.tag == GAZ_BLOCK_TAG: + if node.get(GAZ_TY_KEY) == GAZ_TRUE_BLOCK_TAG: + self.unparse_node(node) + elif node.get(GAZ_TY_KEY) == GAZ_FALSE_BLOCK_TAG: + self.source += " " + self.conditional_delimiters[3] + " " + self.unparse_node(node) + else: + self.unparse_node(node) + i += 1 - @abstractmethod def unparse_loop(self, element_in: ET.Element): - pass + self.source += self.loop_delimiters[0] + i = 0 + for node in element_in: + if node.tag != GAZ_BLOCK_TAG: + self.unparse_node(node) + 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)) - @abstractmethod def unparse_routine_call(self, element_in: ET.Element): pass - @abstractmethod - def unparse_return(self, element_in: ET.Element): + def unparse_statement(self, element_in: ET.Element): pass - @abstractmethod - def unparse_literal(self, element_in: ET.Element): + def unparse_top_block(self, element_in: ET.Element): pass - @abstractmethod - def unparse_variable(self, element_in: ET.Element): + def unparse_expression(self, element_in: ET.Element): pass - @abstractmethod - def unparse_xhs(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