diff --git a/ast_parser/python_unparser.py b/ast_parser/python_unparser.py
index d9dd415..ce6b182 100644
--- a/ast_parser/python_unparser.py
+++ b/ast_parser/python_unparser.py
@@ -1,19 +1,74 @@
+import warnings
from xml.etree import ElementTree as ET
+from ast_parser.gaz_unparser import GazUnparser
from ast_parser.general_unparser import GeneralUnparser
from constants import *
-class PythonUnparser(GeneralUnparser):
+def to_python_type(ty):
+ if ty == GAZ_INT_KEY:
+ return "int"
+ elif ty == GAZ_BOOL_KEY:
+ return "bool"
+ elif ty == GAZ_FLOAT_KEY:
+ return "float"
+ elif ty == GAZ_CHAR_KEY:
+ return "str"
+ elif ty == GAZ_STRING_KEY:
+ return "str"
+ else:
+ raise Exception("Unknown type: " + ty)
- def unparse_xhs(self, element_in: ET.Element):
- pass
+
+def to_python_op(param):
+ if param == "negation" or param == "subtraction":
+ return "-"
+ elif param == "addition":
+ return "+"
+ elif param == "multiplication":
+ return "*"
+ elif param == "division":
+ return "/"
+ elif param == "modulus":
+ return "%"
+ elif param == "power":
+ return "**"
+ elif param == "equality":
+ return "=="
+ elif param == "inequality":
+ return "!="
+ elif param == "less-than":
+ return "<"
+ elif param == "less-than-or-equal":
+ return "<="
+ elif param == "greater-than":
+ return ">"
+ elif param == "greater-than-or-equal":
+ return ">="
+ else:
+ warnings.warn("Warning, unknown operator: " + param)
+ return param
+
+
+class PythonUnparser(GazUnparser):
+ def __init__(self, ast: ET.Element, debug=False):
+ super().__init__(ast, debug)
def unparse_top_block(self, element_in: ET.Element):
pass
- def unparse_block(self, element_in: ET.Element):
- pass
+ def unparse_block(self, node: ET.Element):
+ 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 unparse_routine(self, element_in: ET.Element):
pass
@@ -28,17 +83,34 @@ class PythonUnparser(GeneralUnparser):
pass
def unparse_declaration(self, element_in: ET.Element):
- pass
+ variable = element_in.find(GAZ_VAR_TAG)
+ rhs = element_in.find(GAZ_RHS_TAG)
+ self.unparse_variable(variable, True)
+ self.source += " = "
+ self.unparse_node(rhs)
+ self.source += "\n"
def unparse_operator(self, element_in: ET.Element):
- pass
+ self.unparse_xhs(element_in.find(GAZ_LHS_TAG))
+ self.source += " {} ".format(to_python_op(element_in.get("op")))
+ self.unparse_xhs(element_in.find(GAZ_RHS_TAG))
+
+ def unparse_instream(self, node):
+ for child in node:
+ self.unparse_node(child)
+
+ self.source += "input()\n".format(GAZ_IN_STREAM)
+
+ def unparse_outstream(self, node):
+ self.source += "print("
+ for child in node:
+ self.unparse_node(child)
+
+ self.source += ", end='')\n".format(GAZ_OUT_STREAM)
def unparse_unary(self, element_in: ET.Element):
pass
- def unparse_stream(self, element_in: ET.Element):
- pass
-
def unparse_assignment(self, element_in: ET.Element):
pass
@@ -52,11 +124,17 @@ class PythonUnparser(GeneralUnparser):
pass
def unparse_return(self, element_in: ET.Element):
- pass
+ self.source += "return "
+ for child in element_in:
+ self.unparse_node(child)
+ self.source += "\n"
- def unparse_literal(self, element_in: ET.Element):
- pass
+ def unparse_variable(self, element_in: ET.Element, is_declaration=False):
+ if is_declaration:
+ ty = to_python_type(element_in.get(GAZ_TY_KEY))
+ name = element_in.get(GAZ_NAME_KEY)
- def unparse_variable(self, element_in: ET.Element):
- pass
+ self.source += f"{name}: {ty}"
+ else:
+ super().unparse_variable(element_in)
diff --git a/ast_parser/test/test_python_unparse.py b/ast_parser/test/test_python_unparse.py
new file mode 100644
index 0000000..f9ce0c0
--- /dev/null
+++ b/ast_parser/test/test_python_unparse.py
@@ -0,0 +1,158 @@
+import unittest
+
+import xml.etree.ElementTree as ET
+
+from ast_parser.python_unparser import PythonUnparser
+
+
+class TestPythonUnparseCode(unittest.TestCase):
+
+ def test_unparse_variable_regular(self):
+ input = ''
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("a", parser.source)
+
+ def test_unparse_variable_declaration(self):
+ input = ''
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_variable(parser.xml, True)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("a: int", parser.source)
+
+
+ def test_unparse_rhs_single(self):
+ input = ''
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("1", parser.source)
+
+ def test_unparse_declaration(self):
+ input = ''
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("a: int = 1\n", parser.source)
+
+ def test_unparse_stream(self):
+ input = ' '
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("print(a * 42, end='')\n", parser.source)
+
+ def test_unparse_block(self):
+ input = ' '
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("\n a: int = 1\n print(a * 42, end='')\n return 0\n\n\n", parser.source)
+
+ def test_unparse_assignment(self):
+ with open("xml/assignment.xml", "r") as f:
+ input = f.read()
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("C = 30;\n", parser.source)
+
+ def test_unparse_conditional(self): # TODO test the else-if statements
+ with open("xml/conditional.xml", "r") as f:
+ input = f.read()
+
+ with open("xml/conditional.out", "r") as f:
+ output = f.read()
+
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+
+ parser.unparse_node(parser.xml)
+
+ self.assertIsNotNone(parser.source)
+ self.assertEqual(output, parser.source)
+
+ def test_unparse_loop(self):
+ with open("xml/loop.xml", "r") as f:
+ input = f.read()
+
+ with open("xml/loop.out", "r") as f:
+ output = f.read()
+
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual(output, parser.source)
+
+ def test_unparse_operation_single(self):
+ input = ' '
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("a * 42", parser.source)
+
+ def test_unparse_return(self):
+ input = ' '
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual("return 0\n", parser.source)
+
+ def test_unparse_unary(self):
+ with open("xml/unary.xml", "r") as f:
+ input = f.read()
+
+ with open("xml/unary.out", "r") as f:
+ output = f.read()
+
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual(output, parser.source)
+
+ def test_unparse_routine(self):
+ input = ''
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ i = ' ' * parser.indentation
+ self.assertEqual("procedure main() returns integer {\n var integer a = 1;\n a * 42 -> std_output;\n return 0;\n}\n\n", parser.source)
+
+ def test_unparse_args(self):
+ with open("xml/many_args.xml", 'r') as f:
+ input = f.read()
+ with open("xml/many_args.out", 'r') as f:
+ output = f.read()
+ parser = PythonUnparser(ET.fromstring(input), True)
+ parser.source = ""
+ parser.unparse_node(parser.xml)
+ self.assertIsNotNone(parser.source)
+ self.assertEqual(output, parser.source)
+
+
+ def test_unparse_code(self):
+ with open("xml/test.xml", "r") as input:
+ parser = PythonUnparser(ET.fromstring(input.read()), True)
+ parser.unparse()
+ self.assertIsNotNone(parser.source)
+
+ with open("input.in", "r") as input:
+ i = input.read()
+ self.assertEqual(i, parser.source)
+
+
+if __name__ == "__main__":
+ unittest.main()
\ No newline at end of file