diff --git a/ast_generator/ast_generator.py b/ast_generator/ast_generator.py
index 64e146a..80f5e97 100644
--- a/ast_generator/ast_generator.py
+++ b/ast_generator/ast_generator.py
@@ -4,7 +4,7 @@ import xml.etree.ElementTree as ET
from english_words import get_english_words_set
-from ast_generator.constants import *
+from constants import *
class AstGenerator:
diff --git a/ast_generator/gazprea_ast_grammar.py b/ast_generator/gazprea_ast_grammar.py
index d714e70..a35b590 100644
--- a/ast_generator/gazprea_ast_grammar.py
+++ b/ast_generator/gazprea_ast_grammar.py
@@ -1,4 +1,4 @@
-from ast_generator.constants import Grammar
+from constants import Grammar
GAZPREA_TOP_LEVEL: Grammar = {
# Top level elements
diff --git a/ast_parser/ast_parser.py b/ast_parser/ast_parser.py
deleted file mode 100644
index 9b700f0..0000000
--- a/ast_parser/ast_parser.py
+++ /dev/null
@@ -1,165 +0,0 @@
-import os
-import shutil
-import xml.etree.ElementTree as ET
-
-
-def to_gazprea_type(ty: str):
- if ty == "int":
- return "integer"
- elif ty == "bool":
- return "boolean"
- elif ty == "string":
- return "string"
- elif ty == 'void':
- return 'void'
- else:
- raise Exception("Unknown type: " + ty)
-
-
-class AstParser:
- def __init__(self, input: str or ET.Element, from_xml: bool = False):
- if from_xml:
- self.xml = input
- self.input = None
- else:
- self.input = input
- self.xml = None
-
- self.indentation = 0
-
-
- def parse(self):
- if os.path.isdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp"):
- os.system("rm -rf /home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
- os.mkdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
- else:
- os.mkdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
- with open("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/input.in", "x") as f:
- f.write(self.input)
- os.system("/home/stormblessed/.local/bin/gazc "
- "/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/input.in "
- "/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/output.out "
- "/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/xml.xml")
- self.xml = ET.parse(".tmp/xml.xml")
-
- def unparse(self):
- """
- @brief unparses the xml into valid gazprea code
-
- :return: a string of valid gazprea code
- """
- self.input = ""
- for node in self.xml:
- self._unparse_node(node)
-
- def _unparse_node(self, node):
- if node.tag not in ["variable", "rhs", "lhs", "literal", "operator"]:
- self.input += " " * self.indentation
-
- if node.tag == "block":
- self._block_unparse(node)
- elif node.tag == "declaration":
- self._declaration_unparse(node)
- elif node.tag == "return":
- self._return_unparse(node)
- elif node.tag == "operator":
- self._operator_unparse(node)
- elif node.tag == "stream":
- self._stream_unparse(node)
- elif node.tag == "literal":
- self._literal_unparse(node)
- elif node.tag == "procedure" or node.tag == "function":
- self._routine_unparse(node)
- elif node.tag == "variable":
- self._variable_unparse(node)
- elif node.tag == "rhs" or node.tag == "lhs":
- self._xhs_unparse(node)
- elif node.tag == "literal":
- self._literal_unparse(node)
- else:
- raise Exception("Unknown tag: " + node.tag)
-
- def _block_unparse(self, node):
- self.input += "{\n"
- self.indentation += 4
- for child in node:
- self._unparse_node(child)
- self.indentation -= 4
- self.input += "}\n\n"
-
- def _declaration_unparse(self, node):
- variable = node.find("variable")
- rhs = node.find("rhs")
- self._variable_unparse(variable, True)
- self.input += "="
- self._unparse_node(rhs)
- self.input += ";\n"
-
- def _variable_unparse(self, node, is_declaration = False):
- if is_declaration:
- mut = node.get("mut")
- type = to_gazprea_type(node.get("type"))
- name = node.get("name")
-
- self.input += "{} {} {} ".format(mut, type, name)
- else:
- self.input += " {} ".format(node.get("name"))
-
- def _stream_unparse(self, node):
- for child in node:
- self._unparse_node(child)
-
- self.input += "-> {};\n".format(node.get("type"))
-
- def _literal_unparse(self, node):
- self.input += " {} ".format(node.get("value"))
-
- def _xhs_unparse(self, node):
- for child in node:
- self._unparse_node(child)
-
- def _operator_unparse(self, node):
- self._xhs_unparse(node.find("lhs"))
- self.input += "{}".format(node.get("op"))
- self._xhs_unparse(node.find("rhs"))
-
- def _return_unparse(self, node):
- self.input += "return"
- for child in node:
- self._unparse_node(child)
- self.input += ";\n"
-
- def _routine_unparse(self, node):
- return_type = ""
- if node.get("return_type") != "":
- return_type = "returns " + to_gazprea_type(node.get("return_type"))
-
- self.input += "{} {}{} {} ".format(
- node.tag,
- node.get("name"),
- node.get("args"),
- return_type,
- )
-
- for child in node:
- self._unparse_node(child)
-
- # cls.input += "}\n\n" #blocks are already there
-
-
-if __name__ == '__main__':
- input = """
- function art() returns integer {
- return 3;
- }
- procedure main() returns integer {
- integer b = art();
- integer a = 1;
- a * 42 -> std_output;
- return 0;
- }
- """
-
- parser = AstParser(input)
- parser.parse()
-
diff --git a/ast_parser/gaz_unparser.py b/ast_parser/gaz_unparser.py
new file mode 100644
index 0000000..546b416
--- /dev/null
+++ b/ast_parser/gaz_unparser.py
@@ -0,0 +1,166 @@
+import os
+import shutil
+import xml.etree.ElementTree as ET
+
+from ast_parser.general_unparser import GeneralUnparser
+from constants import *
+
+
+def to_gazprea_type(ty: str): #TODO implement the compound types
+ if ty == GAZ_INT_KEY:
+ return "integer"
+ elif ty == GAZ_BOOL_KEY:
+ return "boolean"
+ elif ty == GAZ_FLOAT_KEY:
+ return "real"
+ elif ty == GAZ_CHAR_KEY:
+ return "character"
+ elif ty == GAZ_STRING_KEY:
+ return "string[*]"
+ else:
+ raise Exception("Unknown type: " + ty)
+
+
+class AstParser(GeneralUnparser):
+ def __init__(self, input: str or ET.Element, from_xml: bool = False):
+ if from_xml:
+ self.xml = input
+ self.input = None
+ else:
+ self.input = input
+ self.xml = None
+
+ self.indentation = 0
+
+ def unparse(self):
+ """
+ @brief unparses the xml into valid gazprea code
+
+ :return: a string of valid gazprea code
+ """
+ self.input = ""
+ 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.input += " " * 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_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._xhs_unparse(node)
+ elif node.tag == GAZ_LIT_TAG:
+ self.unparse_literal(node)
+ else:
+ raise Exception("Unknown tag: " + node.tag)
+
+ def unparse_block(self, node):
+ self.input += "{\n"
+ self.indentation += 4
+ for child in node:
+ self.unparse_node(child)
+ self.indentation -= 4
+ self.input += "}\n\n"
+
+ def unparse_declaration(self, node):
+ variable = node.find(GAZ_VAR_TAG)
+ rhs = node.find(GAZ_RHS_TAG)
+ self.unparse_variable(variable, True)
+ self.input += " = "
+ self.unparse_node(rhs)
+ self.input += ";\n"
+
+ 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.input += "{} {} {}".format(mut, type, name)
+ else:
+ self.input += "{}".format(node.get(GAZ_NAME_KEY))
+
+ def unparse_stream(self, node):
+ if node.tag == GAZ_OUT_STREAM:
+ self.unparse_outstream(node)
+ elif node.tag == GAZ_IN_STREAM:
+ self.unparse_instream(node)
+
+ def unparse_instream(self, node):
+ for child in node:
+ self.unparse_node(child)
+
+ self.input += "<- {};\n".format(GAZ_IN_STREAM)
+
+ def unparse_outstream(self, node):
+ for child in node:
+ self.unparse_node(child)
+
+ self.input += "-> {};\n".format(GAZ_OUT_STREAM)
+
+ def unparse_literal(self, node):
+ self.input += "{}".format(node.get(GAZ_VAL_KEY))
+
+ def _xhs_unparse(self, node):
+ for child in node:
+ self.unparse_node(child)
+
+ def unparse_operator(self, node):
+ self._xhs_unparse(node.find(GAZ_LHS_TAG))
+ self.input += " {} ".format(node.get("op"))
+ self._xhs_unparse(node.find(GAZ_RHS_TAG))
+
+ def unparse_return(self, node):
+ self.input += "return "
+ for child in node:
+ self.unparse_node(child)
+ self.input += ";\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 = self.unparse_argument(node.findall(GAZ_ARG_TAG))
+
+ self.input += "{} {}{} {} ".format(
+ node.tag,
+ node.get(GAZ_NAME_KEY),
+ args,
+ return_type,
+ )
+
+ for child in node:
+ self.unparse_node(child)
+
+ # cls.input += "}\n\n" #blocks are already there
+
+ def unparse_argument(self, nodes):
+ if len(nodes) == 0:
+ return "()"
+ args = "("
+ for i in range(len(nodes)):
+ args += self._unparse_arg(nodes[i])
+ if i < len(nodes) - 1:
+ args += ", "
+
+ args += ")"
+ return args
+
+ def _unparse_arg(self, node):
+ return "{} {}".format(to_gazprea_type(node.get(GAZ_TY_KEY)), node.get(GAZ_NAME_KEY))
diff --git a/ast_parser/general_unparser.py b/ast_parser/general_unparser.py
new file mode 100644
index 0000000..c57740f
--- /dev/null
+++ b/ast_parser/general_unparser.py
@@ -0,0 +1,82 @@
+import xml.etree.ElementTree as ET
+from abc import ABC, abstractmethod
+
+
+class GeneralUnparser(ABC):
+ @abstractmethod
+ def unparse(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_node(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_top_block(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_block(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_routine(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_argument(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_statement(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_expression(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_declaration(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_operator(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_unary(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_stream(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_assignment(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_conditional(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_loop(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_routine_call(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_return(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_literal(self, element_in: ET.Element):
+ pass
+
+ @abstractmethod
+ def unparse_variable(self, element_in: ET.Element):
+ pass
+
+
diff --git a/ast_parser/python_unparser.py b/ast_parser/python_unparser.py
new file mode 100644
index 0000000..e69de29
diff --git a/ast_parser/test/test_parse_code.py b/ast_parser/test/test_unparse.py
similarity index 83%
rename from ast_parser/test/test_parse_code.py
rename to ast_parser/test/test_unparse.py
index 0b90547..6ae7798 100644
--- a/ast_parser/test/test_parse_code.py
+++ b/ast_parser/test/test_unparse.py
@@ -1,36 +1,23 @@
import unittest
-from ast_parser.ast_parser import AstParser
+from ast_parser.gaz_unparser import AstParser
class TestParseCode(unittest.TestCase):
- def test_parse_code(self):
- input = """
- procedure main() returns integer {
- integer a = 1;
- a * 42 -> std_output;
- return 0;
- }
- """
-
- parser = AstParser(input)
- parser.parse()
- self.assertIsNotNone(parser.xml)
- self.assertEqual(parser.xml.getroot().tag, "block")
def test_unparse_variable_regular(self):
input = ''
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
- self.assertEqual(" a ", parser.input)
+ self.assertEqual("a", parser.input)
def test_unparse_variable_declaration(self):
input = ''
parser = AstParser(input, True)
parser.input = ""
- parser._variable_unparse(parser.xml, True)
+ parser.unparse_variable(parser.xml, True)
self.assertIsNotNone(parser.input)
self.assertEqual("var integer a ", parser.input)
@@ -39,7 +26,7 @@ class TestParseCode(unittest.TestCase):
input = ''
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual(" 1 ", parser.input)
@@ -47,7 +34,7 @@ class TestParseCode(unittest.TestCase):
input = ''
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual("var integer a = 1 ;\n", parser.input)
@@ -55,7 +42,7 @@ class TestParseCode(unittest.TestCase):
input = ' '
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual(" a * 42 -> std_output;\n", parser.input)
@@ -63,7 +50,7 @@ class TestParseCode(unittest.TestCase):
input = ' '
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual("{\n var integer a = 1 ;\n a * 42 -> std_output;\n return 0 ;\n}\n\n", parser.input)
@@ -71,7 +58,7 @@ class TestParseCode(unittest.TestCase):
input = ' '
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual(" a * 42 ", parser.input)
@@ -79,7 +66,7 @@ class TestParseCode(unittest.TestCase):
input = ' '
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
self.assertEqual("return 0 ;\n", parser.input)
@@ -87,7 +74,7 @@ class TestParseCode(unittest.TestCase):
input = ''
parser = AstParser(input, True)
parser.input = ""
- parser._unparse_node(parser.xml)
+ parser.unparse_node(parser.xml)
self.assertIsNotNone(parser.input)
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.input)
diff --git a/ast_generator/constants.py b/constants.py
similarity index 96%
rename from ast_generator/constants.py
rename to constants.py
index 72dd7e7..0937ba3 100644
--- a/ast_generator/constants.py
+++ b/constants.py
@@ -43,3 +43,5 @@ GAZ_LOOP_TAG = "loop"
GAZ_TRUE_BLOCK_TAG = "true"
GAZ_FALSE_BLOCK_TAG = "false"
GAZ_ARG_TAG = "argument"
+GAZ_STRING_KEY = "string"
+GAZ_CHAR_KEY = "char"
diff --git a/gazprea_fuzzer.py b/gazprea_fuzzer.py
index fd51e5c..7898d61 100644
--- a/gazprea_fuzzer.py
+++ b/gazprea_fuzzer.py
@@ -7,7 +7,7 @@ from isla.solver import ISLaSolver
import ast_generator.ast_generator
from ast_parser.ast_solver import AstSolver
-from ast_parser.ast_parser import AstParser
+from ast_parser.gaz_unparser import AstParser
from ast_generator import gazprea_ast_grammar
import xml.etree.ElementTree as ET
import xml.dom.minidom