Fix several bugs to get Python scanner/parser basically working, processes ../tests...
[pilex.git] / generate_py.py
1 import os
2 import regex
3 import wrap_repr
4
5 def text_to_python(text, indent):
6   text_strip = text.strip()
7   if text_strip[:1] == '{' and text_strip[-1:] == '}':
8     text = text_strip[1:-1]
9   lines = text.rstrip().split('\n')
10   while len(lines) and len(lines[0].lstrip()) == 0:
11     lines = lines[1:]
12   while len(lines) and len(lines[-1].lstrip()) == 0:
13     lines = lines[:-1]
14   if len(lines) == 0:
15     return '' #{0:s}pass\n'.format(indent)
16   for j in range(len(lines[0])):
17     if lines[0][j] != '\t' and lines[0][j] != ' ':
18       break
19   else:
20     print(text)
21     assert False
22   #print('---')
23   #print(text)
24   prefix = lines[0][:j]
25   for j in range(len(lines)):
26     if len(lines[j]) == 0:
27       lines[j] = '\n'
28     else:
29       assert lines[j][:len(prefix)] == prefix
30       lines[j] = '{0:s}{1:s}\n'.format(indent, lines[j][len(prefix):])
31   return ''.join(lines)
32
33 # note: these routines are literally the same, but conceptually different,
34 # because ast.Text and regex.Text are different and unrelated base classes
35 def ast_text_to_python(ast_text, indent):
36   return text_to_python(ast_text.get_text(), indent)
37 def regex_text_to_python(regex_text, indent):
38   return text_to_python(regex_text.get_text(), indent)
39
40 def generate_py(_ast, _element, home_dir, skel_file, out_file):
41   # generate group action function names (ref_data) and body text
42   group_ref_data = []
43   group_rules_text = []
44   group_actions_text = []
45   for i in _ast.flex_rules:
46     group_ref_data.extend(
47       [
48         (
49           'yy_group{0:d}'.format(len(group_actions_text) + j),
50           (
51             'yy_group_end_element'
52           if isinstance(i.groups0[j], regex.RegexGroupElement) else
53             'yy_group_end'
54           )
55         )
56         for j in range(len(i.groups0))
57       ] +
58       [
59         (
60           'yy_rule_start',
61           'yy_rule{0:d}'.format(len(group_rules_text))
62         )
63       ] +
64       [
65         (
66           'yy_group{0:d}'.format(len(group_actions_text) + j),
67           (
68             'yy_group_end_element'
69           if isinstance(i.groups1[j], regex.RegexGroupElement) else
70             'yy_group_end'
71           )
72         )
73         for j in range(len(i.groups1))
74       ]
75     )
76     groups = i.groups0 + i.groups1
77     group_rules_text.append(
78       regex.Text(
79         text = '''global yy_groups, yy_groups_by_name, yy_action
80 yy_groups = [yy_group_text[:yy_group_stack[-1]]{0:s}]
81 yy_groups_by_name = {{}}
82 yy_action = yy_action{1:d}
83 '''.format(
84           ', None' * len(groups),
85           i.action
86         )
87       )
88     )
89     group_actions_text.extend(
90       [
91         (
92           groups[j][0]
93         if isinstance(groups[j], regex.RegexGroupAction) else
94           regex.Text(
95             text = '''_element = yy_group_element(
96   yy_group_stack[-1],
97   yy_group_stack[-2],
98   yy_element_stack.pop(),
99   {0:s}
100 )
101 yy_element_stack[-1].append(
102   (yy_group_stack[-1], yy_group_stack[-2], _element)
103 )
104 del yy_group_stack[-2:]
105 '''.format(
106               groups[j][0].get_text()
107             )
108           )
109         if isinstance(groups[j], regex.RegexGroupElement) else
110           regex.Text(
111             text = '''if yy_groups[{0:d}] is None:
112   yy_groups[{1:d}] = yy_group_text[yy_group_stack[-1]:yy_group_stack[-2]]
113   if '{2:s}' not in yy_groups_by_name:
114     yy_groups_by_name['{3:s}'] = yy_groups[{4:d}]
115 del yy_group_stack[-2:]
116 '''.format(
117               j + 1,
118               j + 1,
119               groups[j][0].get_text(),
120               groups[j][0].get_text(),
121               j + 1
122             )
123           )
124         if isinstance(groups[j], regex.RegexGroupName) else
125           regex.Text(
126             text = '''if yy_groups[{0:d}] is None:
127   yy_groups[{1:d}] = yy_group_text[yy_group_stack[-1]:yy_group_stack[-2]]
128 del yy_group_stack[-2:]
129 '''.format(
130               j + 1,
131               j + 1
132             )
133           )
134         )
135         for j in range(len(groups))
136       ]
137     )
138
139   # add group for default rule
140   group_ref_data.append(
141     (
142       'yy_rule_start',
143       'yy_rule{0:d}'.format(len(group_rules_text))
144     )
145   )
146   group_rules_text.append(
147     regex.Text(
148       text = '''global yy_groups, yy_groups_by_name, yy_action
149 yy_groups = [yy_group_text[:yy_group_stack[-1]]]
150 yy_groups_by_name = {{}}
151 yy_action = yy_action{0:d}
152 '''.format(
153         _ast.default_action
154       )
155     )
156   )
157
158   _dfa = _ast.to_nfa(group_ref_data).to_dfa()
159
160   if skel_file is None:
161     skel_file = os.path.join(
162       home_dir,
163       'skel/skel_py_element.py' if _element else 'skel/skel_py.py'
164     )
165   if out_file is None:
166     out_file = (
167       _ast[0].outfile
168     if len(_ast[0].outfile) else
169       'lex_{0:s}.py'.format(_ast[0].prefix)
170     )
171   with open(skel_file, 'r') as fin:
172     with open(out_file, 'w+') as fout:
173       line = fin.readline()
174       while len(line):
175         if line == '# GENERATE SECTION1\n':
176           fout.write(
177             '''# GENERATE SECTION1 BEGIN
178 {0:s}# GENERATE END
179 '''.format(
180               ''.join(
181                 [
182                   ast_text_to_python(i, '')
183                   for i in _ast[0].code_blocks_text
184                 ]
185               )
186             )
187           )
188         elif line == '# GENERATE STARTCONDDECL\n':
189           fout.write(
190             '''# GENERATE STARTCONDDECL BEGIN
191 {0:s}# GENERATE END
192 '''.format(
193               ''.join(
194                 [
195                   '{0:s} = {1:d}\n'.format(
196                     _ast.start_conditions[i].name,
197                     i
198                   )
199                   for i in range(len(_ast.start_conditions))
200                 ]
201               )
202             )
203           )
204         elif line == '# GENERATE SECTION2\n':
205           fout.write(
206             '''# GENERATE SECTION2 BEGIN
207 {0:s}{1:s}{2:s}{3:s}{4:s}{5:s}{6:s}yy_eof_actions = [{7:s}
208 ]
209 # GENERATE END
210 '''.format(
211               ''.join(
212                 [
213                   '''def yy_action{0:d}():
214 {1:s}  raise YYContinue()
215 '''.format(
216                     i,
217                     ast_text_to_python(_ast.actions_text[i], '  ')
218                   )
219                   for i in range(len(_ast.actions_text))
220                 ]
221               ),
222               ''.join(
223                 [
224                   '''def yy_rule{0:d}():
225 {1:s}'''.format(
226                     i,
227                     regex_text_to_python(group_rules_text[i], '  ')
228                   )
229                   for i in range(len(group_rules_text))
230                 ]
231               ),
232               ''.join(
233                 [
234                   '''def yy_group{0:d}():
235 {1:s}'''.format(
236                     i,
237                     regex_text_to_python(group_actions_text[i], '  ')
238                   )
239                   for i in range(len(group_actions_text))
240                 ]
241               ),
242               wrap_repr.wrap_repr(
243                 'yy_dfa_states = {0:s}'.format(repr(_dfa.states)),
244                 79
245               ),
246               wrap_repr.wrap_repr(
247                 'yy_dfa_actions = {0:s}'.format(
248                   repr(_dfa.actions).replace('\'', '')
249                 ),
250                 79
251               ),
252               wrap_repr.wrap_repr(
253                 'yy_dfa_start_action = {0:s}'.format(repr(_dfa.start_action)),
254                 79
255               ),
256               ''.join(
257                 [
258                   '''def yy_eof_action{0:d}():
259 {1:s}  return 0
260 '''.format(
261                     i,
262                     ast_text_to_python(_ast.eof_actions_text[i], '  ')
263                   )
264                   for i in range(len(_ast.eof_actions_text))
265                 ]
266               ),
267               ','.join(
268                 [
269                   '\n  yy_eof_action{0:d}'.format(i.eof_action)
270                   for i in _ast.start_conditions
271                 ]
272               )
273             )
274           )
275         elif line == '  # GENERATE SECTION2INITIAL\n':
276           fout.write(
277             '''  # GENERATE SECTION2INITIAL BEGIN
278 {0:s}  # GENERATE END
279 '''.format(
280               ''.join(
281                 [
282                   ast_text_to_python(i, '  ')
283                   for i in _ast[1].code_blocks_text
284                 ]
285               )
286             )
287           )
288         elif line == '# GENERATE SECTION3\n':
289           fout.write(
290             '''# GENERATE SECTION3 BEGIN
291 {0:s}# GENERATE END
292 '''.format(
293               '' if len(_ast) < 3 else ast_text_to_python(_ast[2], '')
294             )
295           )
296         else:
297           #if _ast[0].prefix != 'yy':
298           #  line = line.replace('yywrap', '{0:s}wrap'.format(_ast[0].prefix))
299           fout.write(line)
300         line = fin.readline()