-
Notifications
You must be signed in to change notification settings - Fork 0
/
grammar_generating.py
executable file
·105 lines (99 loc) · 5.26 KB
/
grammar_generating.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/env python3
import random
import os
import random
# Local packages
import templates # Code templates
import arg_parser # Argument parser
from arg_parser import _constants # Constant and default values
# Class for generating grammar based generator
class GrammarGen():
file_to_write = os.path.join(os.path.dirname(__file__), "generator.py") # The generator to be generated
grammar_file = os.path.join(os.path.dirname(__file__), "singleExpression.g4") # Grammar file to generate generator
tab = " " * 4 # To show tabs as spaces in generated python script
special_keys = ["'('", "')'", "'++'", "'--'", "'+'", "'-'", "'~'", "'!'", "'*'", "'/'", "'%'", "'<<'", "'>>'",
"'>>>'", "'<'", "'>'", "'>='", "'<='", "'=='", "'!='", "'==='", "'!=='", "'&'", "'|'", "'^'", "'&&'", "'||'",
"'null'", "'undefined'", "'true'", "'false'"]
# Check if 2 arrays has a common element (utility function)
def common_data(self, list1, list2):
result = False
# traverse in the 1st list
for x in list1:
# traverse in the 2nd list
for y in list2:
# if one common
if x == y:
result = True
return result
return result
# Generate function declarations according to the grammar
def generate(self, quiet):
# Open grammar file
with open (self.grammar_file, "r") as grammar:
function_declaration = ""
if not quiet:
linecount = 0
# Iterate trough lines
for line in grammar:
if not quiet:
linecount += 1
print(linecount)
# Split the line into "words" and remove comments
array = []
for word in line.split():
if word != "///":
array.append(word)
else:
break
# See if we need to delcare a new function
if not self.common_data([":", "|", ";"], array) and array != []:
this_function_name = array[0]
function_declaration += "\n%sdepth_counter = 0" % (self.tab)
# Define a function
function_declaration += "\n%sdef %s(self):" % (self.tab, this_function_name)
# Debug information
if not quiet:
function_declaration += "\n%sself.depth_counter += 1" % (self.tab * 2)
function_declaration += "\n%sprint(self.depth_counter)" % (self.tab * 2)
# Declare an empty test case
function_declaration += "\n%stest_case = \"\"" % (self.tab * 2)
# If line is not empty after removing comments
elif array != []:
# If it's not the end of the function
if not self.common_data([";"], array):
# If the line contains more elements, it has less probability to be generated
# (to avoid reaching maximum recursion depth)
function_declaration += "\n%sif not random.randint(0, %d):\n%stest_case = \"\"" % (self.tab * 2,
(len(array) - 1) ** 4, self.tab * 3)
# Iterate trough "words"
for element in array:
if element not in ["|", ":", ";"]:
# If element is one of these, it needs to be added to the test case
if element in self.special_keys:
# If there is an or, we need one more tab
function_declaration += "\n%stest_case += %s" % (self.tab * 3, element)
# Else (if it is a function)
else:
function_declaration += "\n%stest_case += self.%s()" % (self.tab * 3, element)
# If we reached the end of the function
elif element == ";":
# If test_case is empty we try it again
function_declaration += "\n%sif test_case == \"\":" % (self.tab * 2)
function_declaration += "\n%sreturn self.%s()" %(self.tab * 3, this_function_name)
# Return statement at the end of the function
# If we reached the end of the function, we already put a return statement
if not self.common_data([";"], array):
function_declaration += "\n%sreturn test_case" % (self.tab * 3)
# Debug information
if not quiet:
print(function_declaration)
return function_declaration
if __name__ == '__main__':
args = arg_parser.parse_args()
gram = GrammarGen()
# Writing generator script
with open(gram.file_to_write, "w") as file:
# STARTER_FUNCTION defines which element of the grammar we want ot generate
file.write("%s" % templates.class_template.format(GENERATED_FUNCTIONS = gram.generate(args.q),
STARTER_FUNCTION = args.starter_element, TEST_COUNT = args.test_count, SEED = args.seed,
TEST_CASES_IN_A_FILE = _constants.test_cases_in_a_file))