Fixed anti-parsing errors in python

Took 1 hour 2 minutes
This commit is contained in:
ayrton 2023-11-19 20:49:25 -07:00
parent 4ee1770092
commit 04675a01d6
5 changed files with 243 additions and 1 deletions

View file

@ -240,6 +240,7 @@ class GeneralUnparser:
else: else:
self.source += (self.conditional_delimiters[1] + " ") self.source += (self.conditional_delimiters[1] + " ")
elif node.tag == GAZ_BLOCK_TAG: elif node.tag == GAZ_BLOCK_TAG:
self.source += self.indentation * self.indentation_character
if node.get(GAZ_TY_KEY) == GAZ_TRUE_BLOCK_TAG: if node.get(GAZ_TY_KEY) == GAZ_TRUE_BLOCK_TAG:
self.unparse_node(node) self.unparse_node(node)
elif node.get(GAZ_TY_KEY) == GAZ_FALSE_BLOCK_TAG: elif node.get(GAZ_TY_KEY) == GAZ_FALSE_BLOCK_TAG:
@ -267,7 +268,7 @@ class GeneralUnparser:
i += 1 i += 1
def unparse_unary(self, element_in: ET.Element): def unparse_unary(self, element_in: ET.Element):
self.source += " {}".format(self.translate_op(element_in.get("op"))) self.source += "{}".format(self.translate_op(element_in.get("op")))
self.unparse_xhs(element_in.find(GAZ_RHS_TAG)) self.unparse_xhs(element_in.find(GAZ_RHS_TAG))
def unparse_single_arg(self, param): def unparse_single_arg(self, param):

View file

@ -92,3 +92,16 @@ class PythonUnparser(GeneralUnparser):
def format_single_arg(self, ty, name): def format_single_arg(self, ty, name):
return "{}: {}".format(name, ty) return "{}: {}".format(name, ty)
def unparse_block(self, node):
super().unparse_block(node)
self.source += f"{self.block_delimiters[0]}\n"
self.indentation += 4
for child in node:
self.unparse_node(child)
self.source += self.indentation_character * self.indentation + "pass\n"
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]}"

0
fuzzer/ground_truth/ee Normal file
View file

94
test/config.yaml Normal file
View file

@ -0,0 +1,94 @@
# The default configuration for the Gazprea Fuzzer
---
generation-options:
max-nesting-depth: 5 # maximum nesting depth for statements
max-conditionals-loops: 5 # maximum number of loops/conditionals per routine
max-number-of-routines: 5 # maximum number of routines (main will always be generated)
generate-dead-code: True # generate dead code
properties:
max-range-length: 5 # maximum length of ranges, vectors and tuples, (AxA matrices can exist)
use-english-words: True # use english words instead of random names (this may limit the maximum number of names)
id-length: # length of identifiers
min: 1
max: 10
function-name-length: # length of function names
min: 1
max: 10
number-of-arguments: # number of arguments to a routine
min: 1
max: 10
generate-max-int: True # if False, generate integers between [-1000, 1000] else
expression-weights: # weights for expressions
# the higher a weight, the more likely (0, 10000), 0 to exclude, 10000 for only that
brackets: 10
arithmetic:
addition: 80
subtraction: 80
multiplication: 30
division: 10
modulo: 10
power: 5
comparison:
equality: 50
inequality: 50
less-than: 30
greater-than: 30
less-than-or-equal: 10
greater-than-or-equal: 10
logical:
and: 50
or: 50
xor: 10
vector-or-string:
generator: 20
range: 30
filter: 10
reverse: 10
concatenation: 50
unary:
noop: 10
negation: 20
not: 10
statement-weights: # set to 0 for any statements you wish to exclude
variable-declaration: 50
routine-call: 20
conditional: 30
loop: 20
assignment: 40
out-stream: 20
in-stream: 5
type-weights:
value-types:
integer: 50
real: 50
boolean: 50
character: 50
void: 10
composite-types:
vector: 20
tuple: 5
matrix: 10
string: 10
composite: 0 #TODO add support for composite types
atomic: 40
routine-weights:
procedure: 20
function: 50
misc-weights:
type-qualifier-weights:
const: 10
var: 60
block-termination-probability: 0.2 # probability for a block to terminate

134
test/test_correctness.py Normal file
View file

@ -0,0 +1,134 @@
import sys
import unittest
from contextlib import redirect_stdout
from io import StringIO
import yaml
import xml.etree.ElementTree as ET
import signal
from ast_generator.ast_generator import AstGenerator
from ast_parser.python_unparser import PythonUnparser
class MyTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
with open("config.yaml", 'r') as stream:
cls.props = yaml.safe_load(stream)
def setUp(cls):
cls.ast_gen = AstGenerator(cls.props)
cls.python_unparser = PythonUnparser(cls.ast_gen.ast, True)
def test_assignment(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_declaration()
self.ast_gen.generate_assignment()
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
self.fail(e)
def test_binary_operator(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_declaration()
self.ast_gen.generate_binary('addition', 'int')
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
self.fail(e)
def test_unary_operator(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_declaration()
self.ast_gen.generate_unary('negation', 'int')
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
print(self.python_unparser.source)
self.fail(e)
def test_output(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_out_stream()
output = StringIO()
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
with redirect_stdout(output):
exec(self.python_unparser.source)
try:
exec(output.getvalue())
except Exception as e:
self.fail(e)
outstring = output.getvalue()
self.assertNotEqual("", outstring, self.python_unparser.source)
def test_input(self): #FIXME this doesn't actually accept user input, I think I need to create a global dict
# to store the input and then access it from the python in some way...
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_in_stream()
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
self.fail(e)
def test_conditional(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_conditional()
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
print(self.python_unparser.source)
self.fail(e)
def test_loop(self):
self.ast_gen.ast = ET.Element("block")
self.ast_gen.current_ast_element = self.ast_gen.ast
self.ast_gen.generate_loop()
self.python_unparser.xml = self.ast_gen.ast
self.python_unparser.unparse()
try:
exec(self.python_unparser.source)
except Exception as e:
print(self.python_unparser.source)
self.fail(e)
if __name__ == '__main__':
unittest.main()