Refactored ASTGenerator #3
|
@ -170,7 +170,7 @@ class AstGenerator:
|
||||||
if return_value is None:
|
if return_value is None:
|
||||||
self.generate_expression(return_type)
|
self.generate_expression(return_type)
|
||||||
else:
|
else:
|
||||||
self.current_ast_element.append(self.make_literal(return_type, return_value))
|
self.generate_literal(return_type, return_value)
|
||||||
|
|
||||||
# return to the parent
|
# return to the parent
|
||||||
self.current_ast_element = parent
|
self.current_ast_element = parent
|
||||||
|
@ -373,10 +373,17 @@ class AstGenerator:
|
||||||
|
|
||||||
self.current_ast_element = parent
|
self.current_ast_element = parent
|
||||||
|
|
||||||
def generate_routine_call(self): # we should generate a test case with arbitrary number of args
|
def generate_routine_call(self): # we should generate a test case with arbitrary number of args
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def generate_conditional(self):
|
def generate_conditional(self):
|
||||||
|
"""
|
||||||
|
@brief generate a conditional statement
|
||||||
|
|
||||||
|
@effects: modifies the current_ast_element
|
||||||
|
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
if self.current_control_flow_nesting_depth >= self.settings['generation-options']['max-nesting-depth']:
|
if self.current_control_flow_nesting_depth >= self.settings['generation-options']['max-nesting-depth']:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -384,24 +391,25 @@ class AstGenerator:
|
||||||
'block-termination-probability']:
|
'block-termination-probability']:
|
||||||
return
|
return
|
||||||
|
|
||||||
element = build_xml_element([], name=GAZ_IF_TAG)
|
|
||||||
self.current_ast_element.append(element)
|
|
||||||
parent = self.current_ast_element
|
parent = self.current_ast_element
|
||||||
self.current_ast_element = element
|
|
||||||
|
|
||||||
|
self.make_scoped_element(GAZ_IF_TAG, [])
|
||||||
self.current_control_flow_nesting_depth += 1
|
self.current_control_flow_nesting_depth += 1
|
||||||
|
|
||||||
self.push_scope()
|
|
||||||
|
|
||||||
self.generate_expression(GAZ_BOOL_KEY)
|
self.generate_expression(GAZ_BOOL_KEY)
|
||||||
|
|
||||||
self.generate_block(tag=[("type", GAZ_TRUE_BLOCK_TAG)])
|
self.generate_block(tag=[("type", GAZ_TRUE_BLOCK_TAG)]) # FIXME this inhibits elif blocks
|
||||||
self.generate_block(tag=[("type", GAZ_FALSE_BLOCK_TAG)])
|
self.generate_block(tag=[("type", GAZ_FALSE_BLOCK_TAG)])
|
||||||
|
|
||||||
self.pop_scope()
|
self.current_control_flow_nesting_depth -= 1
|
||||||
self.current_ast_element = parent
|
self.exit_scoped_element(parent)
|
||||||
|
|
||||||
def generate_loop(self): # fixme generation of infinite loops happens too often...
|
def generate_loop(self):
|
||||||
|
"""
|
||||||
|
@brief generate a loop
|
||||||
|
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
# FIXME make sure that loop conditions are evaluated at least once (assert true or make a config param)
|
# FIXME make sure that loop conditions are evaluated at least once (assert true or make a config param)
|
||||||
if self.current_control_flow_nesting_depth >= self.settings['generation-options']['max-nesting-depth']:
|
if self.current_control_flow_nesting_depth >= self.settings['generation-options']['max-nesting-depth']:
|
||||||
return
|
return
|
||||||
|
@ -412,35 +420,44 @@ class AstGenerator:
|
||||||
|
|
||||||
init_var = self.generate_zero_declaration()
|
init_var = self.generate_zero_declaration()
|
||||||
parent = self.current_ast_element
|
parent = self.current_ast_element
|
||||||
element = build_xml_element([], name=GAZ_LOOP_TAG)
|
|
||||||
self.current_ast_element.append(element)
|
|
||||||
self.current_ast_element = element
|
|
||||||
|
|
||||||
|
self.make_scoped_element(GAZ_LOOP_TAG, [])
|
||||||
self.current_control_flow_nesting_depth += 1
|
self.current_control_flow_nesting_depth += 1
|
||||||
self.push_scope()
|
|
||||||
self.generate_expression(GAZ_BOOL_KEY)
|
self.generate_expression(GAZ_BOOL_KEY) # the loop entry condition #TODO force true
|
||||||
self.generate_block(block_type=GAZ_LOOP_TAG,
|
self.generate_block(block_type=GAZ_LOOP_TAG,
|
||||||
loop_var=init_var) # append a variable increment and prepend a break statement if var is > max loop iterations
|
loop_var=init_var) # append a variable increment and prepend a break statement if var is > max loop iterations
|
||||||
self.pop_scope()
|
|
||||||
self.current_ast_element = parent
|
self.current_control_flow_nesting_depth -= 1
|
||||||
|
self.exit_scoped_element(parent)
|
||||||
|
|
||||||
def generate_zero_declaration(self):
|
def generate_zero_declaration(self):
|
||||||
|
"""
|
||||||
|
@brief generate a declaration int a = 0 for some a
|
||||||
|
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
parent = self.current_ast_element
|
parent = self.current_ast_element
|
||||||
element = build_xml_element([], name=GAZ_DECLARATION_TAG)
|
|
||||||
|
|
||||||
self.current_ast_element.append(element)
|
self.make_element(GAZ_DECLARATION_TAG, [])
|
||||||
self.current_ast_element = element
|
|
||||||
|
|
||||||
|
# Initialize variable
|
||||||
variable = self.generate_variable(GAZ_INT_KEY, 'var')
|
variable = self.generate_variable(GAZ_INT_KEY, 'var')
|
||||||
self.current_ast_element.append(variable.xml)
|
self.current_ast_element.append(variable.xml)
|
||||||
self.current_scope.append(variable.name, variable)
|
self.current_scope.append(variable.name, variable)
|
||||||
|
|
||||||
self.generate_xhs(GAZ_RHS_TAG, variable.type, is_zero=True)
|
self.generate_xhs(GAZ_RHS_TAG, variable.type, is_zero=True)
|
||||||
|
|
||||||
self.current_ast_element = parent
|
self.current_ast_element = parent
|
||||||
|
|
||||||
return variable
|
return variable
|
||||||
|
|
||||||
def generate_assignment(self):
|
def generate_assignment(self):
|
||||||
|
"""
|
||||||
|
@brief generate an assignment
|
||||||
|
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
possible_vars = self.current_scope.get_all_defined_mutable_vars()
|
possible_vars = self.current_scope.get_all_defined_mutable_vars()
|
||||||
if len(possible_vars) == 0:
|
if len(possible_vars) == 0:
|
||||||
raise ValueError("No possible variables to assign to!")
|
raise ValueError("No possible variables to assign to!")
|
||||||
|
@ -448,9 +465,7 @@ class AstGenerator:
|
||||||
# same structure as a declaration
|
# same structure as a declaration
|
||||||
parent = self.current_ast_element
|
parent = self.current_ast_element
|
||||||
|
|
||||||
element = build_xml_element([], name=GAZ_ASSIGNMENT_TAG)
|
self.make_element(GAZ_ASSIGNMENT_TAG, [])
|
||||||
self.current_ast_element.append(element)
|
|
||||||
self.current_ast_element = element
|
|
||||||
|
|
||||||
variable = random.choice(possible_vars)
|
variable = random.choice(possible_vars)
|
||||||
|
|
||||||
|
@ -466,29 +481,48 @@ class AstGenerator:
|
||||||
self.generate_stream(GAZ_IN_STREAM)
|
self.generate_stream(GAZ_IN_STREAM)
|
||||||
|
|
||||||
def generate_stream(self, stream_type):
|
def generate_stream(self, stream_type):
|
||||||
|
"""
|
||||||
|
@brief generate a stream statment from a stream type
|
||||||
|
|
||||||
|
@param stream_type: whether the stream is an input or output
|
||||||
|
@return:
|
||||||
|
"""
|
||||||
parent = self.current_ast_element
|
parent = self.current_ast_element
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
("type", stream_type),
|
("type", stream_type),
|
||||||
]
|
]
|
||||||
element = build_xml_element(args, name=GAZ_STREAM_TAG)
|
self.make_element(GAZ_STREAM_TAG, args)
|
||||||
self.current_ast_element.append(element)
|
|
||||||
self.current_ast_element = element
|
|
||||||
|
|
||||||
self.generate_expression(ANY_TYPE)
|
self.generate_expression(ANY_TYPE)
|
||||||
|
|
||||||
self.current_ast_element = parent
|
self.current_ast_element = parent
|
||||||
|
|
||||||
def generate_variable(self, var_type: str, mut=None):
|
def generate_variable(self, var_type: str, mut=None):
|
||||||
|
"""
|
||||||
|
@brief generate a variable
|
||||||
|
|
||||||
|
@param var_type: they type of the variable
|
||||||
|
@param mut: mutability of the variable
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
if mut is None:
|
if mut is None:
|
||||||
return Variable(self.get_name(GAZ_VAR_TAG), var_type, self.get_qualifier())
|
return Variable(self.get_name(GAZ_VAR_TAG), var_type, self.get_qualifier())
|
||||||
else:
|
else:
|
||||||
return Variable(self.get_name(GAZ_VAR_TAG), var_type, mut)
|
return Variable(self.get_name(GAZ_VAR_TAG), var_type, mut)
|
||||||
|
|
||||||
def generate_literal(self, var_type: str, value=None):
|
def generate_literal(self, var_type: str, value=None):
|
||||||
|
"""
|
||||||
|
@brief generate a literal
|
||||||
|
|
||||||
|
@param var_type: Type of the literal
|
||||||
|
@param value: optional value of the literal
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
if value is None:
|
if value is None:
|
||||||
value = self.get_value(var_type)
|
value = self.get_value(var_type)
|
||||||
else:
|
else:
|
||||||
value = value
|
value = value
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
("type", var_type),
|
("type", var_type),
|
||||||
("value", str(value)),
|
("value", str(value)),
|
||||||
|
@ -496,7 +530,7 @@ class AstGenerator:
|
||||||
element = build_xml_element(args, name=GAZ_LIT_TAG)
|
element = build_xml_element(args, name=GAZ_LIT_TAG)
|
||||||
self.current_ast_element.append(element)
|
self.current_ast_element.append(element)
|
||||||
|
|
||||||
def make_literal(self, type, value):
|
def make_literal(self, type, value): # TODO eliminate this function
|
||||||
args = [
|
args = [
|
||||||
("type", type),
|
("type", type),
|
||||||
("value", value),
|
("value", value),
|
||||||
|
@ -505,6 +539,11 @@ class AstGenerator:
|
||||||
return element
|
return element
|
||||||
|
|
||||||
def generate_global(self):
|
def generate_global(self):
|
||||||
|
"""
|
||||||
|
@brief generate a global const declaration
|
||||||
|
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
current_scope = self.current_scope
|
current_scope = self.current_scope
|
||||||
current_element = self.current_ast_element
|
current_element = self.current_ast_element
|
||||||
|
|
||||||
|
@ -517,6 +556,13 @@ class AstGenerator:
|
||||||
self.current_ast_element = current_element
|
self.current_ast_element = current_element
|
||||||
|
|
||||||
def generate_expression(self, expr_type: str, is_zero=False):
|
def generate_expression(self, expr_type: str, is_zero=False):
|
||||||
|
"""
|
||||||
|
@brief generate an expression
|
||||||
|
|
||||||
|
@param expr_type: the type of the expression
|
||||||
|
@param is_zero: if the expression should eval to 0
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
if is_zero:
|
if is_zero:
|
||||||
self.generate_literal(expr_type, value=0)
|
self.generate_literal(expr_type, value=0)
|
||||||
return
|
return
|
||||||
|
@ -530,11 +576,17 @@ class AstGenerator:
|
||||||
elif expr_type == GAZ_CHAR_KEY:
|
elif expr_type == GAZ_CHAR_KEY:
|
||||||
self.generate_char_expr()
|
self.generate_char_expr()
|
||||||
elif expr_type == ANY_TYPE: # TODO implement the choice of any type
|
elif expr_type == ANY_TYPE: # TODO implement the choice of any type
|
||||||
self.generate_int_expr()
|
ty = self.get_type(GAZ_RHS_TAG)
|
||||||
|
self.generate_expression(ty)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Expression type {expr_type} not implemented")
|
raise NotImplementedError(f"Expression type {expr_type} not implemented")
|
||||||
|
|
||||||
def generate_routine_args(self):
|
def generate_routine_args(self) -> list[Argument]:
|
||||||
|
"""
|
||||||
|
@brief generate a list of arguments for a routine
|
||||||
|
|
||||||
|
@return: a list of arguments
|
||||||
|
"""
|
||||||
number = random.randint(self.settings['properties']['number-of-arguments']['min'],
|
number = random.randint(self.settings['properties']['number-of-arguments']['min'],
|
||||||
self.settings['properties']['number-of-arguments']['max'])
|
self.settings['properties']['number-of-arguments']['max'])
|
||||||
args = []
|
args = []
|
||||||
|
@ -701,7 +753,7 @@ class AstGenerator:
|
||||||
# add the check 'if loop_var >= self.settings['generation_options']['max-loop-iterations']: break'
|
# add the check 'if loop_var >= self.settings['generation_options']['max-loop-iterations']: break'
|
||||||
operation = build_xml_element([("op", ">=")], name=GAZ_OPERATOR_TAG)
|
operation = build_xml_element([("op", ">=")], name=GAZ_OPERATOR_TAG)
|
||||||
rhs = self._loop_heloper(loop_var, operation)
|
rhs = self._loop_heloper(loop_var, operation)
|
||||||
rhs.append(
|
rhs.append( # TODO refactor this to use generate_literal instead of make_literal
|
||||||
self.make_literal(GAZ_INT_KEY, "'" + str(self.settings['generation-options']['max-loop-iterations']) + "'"))
|
self.make_literal(GAZ_INT_KEY, "'" + str(self.settings['generation-options']['max-loop-iterations']) + "'"))
|
||||||
|
|
||||||
true_block = build_xml_element([], name=GAZ_BLOCK_TAG)
|
true_block = build_xml_element([], name=GAZ_BLOCK_TAG)
|
||||||
|
@ -742,7 +794,7 @@ class AstGenerator:
|
||||||
|
|
||||||
operation = build_xml_element([("op", "+")], name=GAZ_OPERATOR_TAG)
|
operation = build_xml_element([("op", "+")], name=GAZ_OPERATOR_TAG)
|
||||||
rhs = self._loop_heloper(loop_var, operation)
|
rhs = self._loop_heloper(loop_var, operation)
|
||||||
rhs.append(self.make_literal(GAZ_INT_KEY, '1'))
|
rhs.append(self.make_literal(GAZ_INT_KEY, '1')) # TODO refactor this to use generate_literal instead of make_literal
|
||||||
|
|
||||||
# return everything to normalcy
|
# return everything to normalcy
|
||||||
self.current_ast_element = parent
|
self.current_ast_element = parent
|
||||||
|
@ -814,4 +866,3 @@ class AstGenerator:
|
||||||
self.generate_binary(op, random.choice([GAZ_INT_KEY, GAZ_FLOAT_KEY]))
|
self.generate_binary(op, random.choice([GAZ_INT_KEY, GAZ_FLOAT_KEY]))
|
||||||
else:
|
else:
|
||||||
self.generate_binary(op, random.choice(expr_type))
|
self.generate_binary(op, random.choice(expr_type))
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import redirect_stdout
|
from contextlib import redirect_stdout
|
||||||
|
|
||||||
|
@ -30,10 +31,11 @@ class Fuzzer():
|
||||||
os.mkdir("fuzzer")
|
os.mkdir("fuzzer")
|
||||||
os.mkdir("fuzzer/input")
|
os.mkdir("fuzzer/input")
|
||||||
os.mkdir("fuzzer/debug")
|
os.mkdir("fuzzer/debug")
|
||||||
os.mkdir("fuzzer/debug/ast")
|
os.mkdir("fuzzer/debug/ast_err")
|
||||||
os.mkdir("fuzzer/instream")
|
os.mkdir("fuzzer/instream")
|
||||||
os.mkdir("fuzzer/outputs")
|
os.mkdir("fuzzer/outputs")
|
||||||
os.mkdir("fuzzer/ground_truth")
|
os.mkdir("fuzzer/ground_truth")
|
||||||
|
os.system("cp tester_config.json fuzzer/tester_config.json")
|
||||||
for i in range(self.batch):
|
for i in range(self.batch):
|
||||||
try:
|
try:
|
||||||
self.fuzzer.fuzz()
|
self.fuzzer.fuzz()
|
||||||
|
@ -42,7 +44,7 @@ class Fuzzer():
|
||||||
warnings.warn("None Tag Exception encountered, writing stack trace and xml to debug/ast/{}.xml\n"
|
warnings.warn("None Tag Exception encountered, writing stack trace and xml to debug/ast/{}.xml\n"
|
||||||
"Look for a top-level <argument> tag or send it to Ayrton and I'll see what I can see"
|
"Look for a top-level <argument> tag or send it to Ayrton and I'll see what I can see"
|
||||||
"".format(r))
|
"".format(r))
|
||||||
with open("fuzzer/debug/ast/{}.xml".format(r), 'w') as f:
|
with open("fuzzer/debug/ast_err/{}.xml".format(r), 'w') as f:
|
||||||
f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml())
|
f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml())
|
||||||
continue
|
continue
|
||||||
dom = xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8'))
|
dom = xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8'))
|
||||||
|
@ -58,9 +60,16 @@ class Fuzzer():
|
||||||
except (OverflowError, ZeroDivisionError, ValueError):
|
except (OverflowError, ZeroDivisionError, ValueError):
|
||||||
os.system("rm -f fuzzer/ground_truth/{}_{}.py".format(self.file_name, i))
|
os.system("rm -f fuzzer/ground_truth/{}_{}.py".format(self.file_name, i))
|
||||||
continue
|
continue
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
r = random.randint(0, 1000000)
|
||||||
|
warnings.warn("Execution halted, result written to debug/ast/{}.xml\n"
|
||||||
|
"".format(r))
|
||||||
|
with open("fuzzer/debug/ast_err/{}.xml".format(r), 'w') as f:
|
||||||
|
f.write(xml.dom.minidom.parseString(ET.tostring(self.fuzzer.ast).decode('utf-8')).toprettyxml())
|
||||||
|
sys.exit(1)
|
||||||
with open("fuzzer/input/{}_{}.in".format(self.file_name, i), 'w') as f:
|
with open("fuzzer/input/{}_{}.in".format(self.file_name, i), 'w') as f:
|
||||||
f.write(self.fuzzer.source)
|
f.write(self.fuzzer.source)
|
||||||
with open("fuzzer/debug/{}_{}.out".format(self.file_name, i), 'w') as f:
|
with open("fuzzer/debug/{}_{}.xml".format(self.file_name, i), 'w') as f:
|
||||||
f.write(pretty)
|
f.write(pretty)
|
||||||
# y.write(self.fuzzer.out)
|
# y.write(self.fuzzer.out)
|
||||||
# with open("fuzzer/instream/{}.in".format(i), 'w') as f:
|
# with open("fuzzer/instream/{}.in".format(i), 'w') as f:
|
||||||
|
|
36
tester_config.json
Normal file
36
tester_config.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"inDir": "<inDir>",
|
||||||
|
"outDir": "<outDir>",
|
||||||
|
"inStrDir": "<inStrDir>",
|
||||||
|
"testedExecutablePaths": {
|
||||||
|
"<team id>": "<path_to_gazc_exe>"
|
||||||
|
},
|
||||||
|
"runtimes": {
|
||||||
|
"<team id>": "<path_to_libgazrt.so>"
|
||||||
|
},
|
||||||
|
"toolchains": {
|
||||||
|
"gazprea": [
|
||||||
|
{
|
||||||
|
"stepName": "gazc",
|
||||||
|
"executablePath": "$EXE",
|
||||||
|
"arguments": [
|
||||||
|
"$INPUT",
|
||||||
|
"$OUTPUT"
|
||||||
|
],
|
||||||
|
"output": "gazc.ll",
|
||||||
|
"allowError": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stepName": "lli",
|
||||||
|
"executablePath": "/cshome/cmput415/415-resources/llvm-project/build/bin/lli",
|
||||||
|
"arguments": [
|
||||||
|
"$INPUT"
|
||||||
|
],
|
||||||
|
"output": "-",
|
||||||
|
"usesRuntime": true,
|
||||||
|
"usesInStr": true,
|
||||||
|
"allowError": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue