Simplify list construction
[fur] / normalization.py
1 import collections
2
3 import desugaring
4 import util
5
6 NormalVariableExpression = collections.namedtuple(
7     'NormalVariableExpression',
8     [
9         'variable',
10     ],
11 )
12
13 NormalIntegerLiteralExpression = collections.namedtuple(
14     'NormalIntegerLiteralExpression',
15     [
16         'integer',
17     ],
18 )
19
20 NormalLambdaExpression = collections.namedtuple(
21     'NormalLambdaExpression',
22     (
23         'name',
24         'argument_name_list',
25         'statement_list',
26     ),
27 )
28
29 NormalStringLiteralExpression = collections.namedtuple(
30     'NormalStringLiteralExpression',
31     [
32         'string',
33     ],
34 )
35
36 NormalSymbolExpression = collections.namedtuple(
37     'NormalSymbolExpression',
38     [
39         'symbol',
40     ],
41 )
42
43 NormalPushStatement = collections.namedtuple(
44     'NormalPushStatement',
45     (
46         'expression',
47     ),
48 )
49
50 NormalFunctionCallExpression = collections.namedtuple(
51     'NormalFunctionCallExpression',
52     [
53         'metadata',
54         'function_expression',
55         'argument_count',
56     ],
57 )
58
59 NormalArrayVariableInitializationStatement = collections.namedtuple(
60     'NormalArrayVariableInitializationStatement',
61     [
62         'variable',
63         'items',
64     ],
65 )
66
67 NormalSymbolArrayVariableInitializationStatement = collections.namedtuple(
68     'NormalSymbolArrayVariableInitializationStatement',
69     [
70         'variable',
71         'symbol_list',
72     ],
73 )
74
75 NormalVariableInitializationStatement = collections.namedtuple(
76     'NormalVariableInitializationStatement',
77     [
78         'variable',
79         'expression',
80     ],
81 )
82
83 NormalExpressionStatement = collections.namedtuple(
84     'NormalExpressionStatement',
85     [
86         'expression',
87     ],
88 )
89
90 NormalAssignmentStatement = collections.namedtuple(
91     'NormalAssignmentStatement',
92     [
93         'target',
94         'expression',
95     ],
96 )
97
98 NormalIfElseExpression = collections.namedtuple(
99     'NormalIfElseExpression',
100     [
101         'condition_expression',
102         'if_statement_list',
103         'else_statement_list',
104     ],
105 )
106
107 NormalProgram = collections.namedtuple(
108     'NormalProgram',
109     [
110         'statement_list',
111     ],
112 )
113
114 def normalize_integer_literal_expression(counter, expression):
115     return (
116         counter,
117         (),
118         NormalIntegerLiteralExpression(integer=expression.integer),
119     )
120
121 def normalize_lambda_expression(counter, expression):
122     variable = '${}'.format(counter)
123
124     _, statement_list = normalize_statement_list(
125         0,
126         expression.statement_list,
127     )
128
129     return (
130         counter + 1,
131         (
132             NormalVariableInitializationStatement(
133                 variable=variable,
134                 expression=NormalLambdaExpression(
135                     name=expression.name,
136                     argument_name_list=expression.argument_name_list,
137                     statement_list=statement_list,
138                 ),
139             ),
140         ),
141         NormalVariableExpression(variable=variable),
142     )
143
144 NormalListConstructExpression = collections.namedtuple(
145     'NormalListConstructExpression',
146     [
147         'allocate',
148     ],
149 )
150
151 NormalListAppendStatement = collections.namedtuple(
152     'NormalListAppendStatement',
153     [
154         'list_expression',
155         'item_expression',
156     ],
157 )
158
159 def normalize_list_literal_expression(counter, expression):
160     list_variable = '${}'.format(counter)
161     counter += 1
162
163     prestatements = []
164
165     for item_expression in expression.item_expression_list:
166         counter, item_expression_prestatements, normalized = normalize_expression(
167             counter,
168             item_expression,
169         )
170
171         for p in item_expression_prestatements:
172             prestatements.append(p)
173
174         prestatements.append(
175             NormalPushStatement(
176                 expression=normalized,
177             )
178         )
179
180     return (
181         counter,
182         tuple(prestatements),
183         NormalListConstructExpression(allocate=len(expression.item_expression_list)),
184     )
185
186 def normalize_string_literal_expression(counter, expression):
187     return (
188         counter,
189         (),
190         NormalStringLiteralExpression(string=expression.string),
191     )
192
193 NormalStructureLiteralExpression = collections.namedtuple(
194     'NormalStructureLiteralExpression',
195     [
196         'field_count',
197         'symbol_list_variable',
198         'value_list_variable',
199     ],
200 )
201
202 def normalize_structure_literal_expression(counter, expression):
203     prestatements = []
204     field_symbol_array = []
205     field_value_array = []
206
207     for symbol_expression_pair in expression.fields:
208         counter, field_prestatements, field_expression = normalize_expression(
209             counter,
210             symbol_expression_pair.expression,
211         )
212
213         for p in field_prestatements:
214             prestatements.append(p)
215
216         field_symbol_array.append(symbol_expression_pair.symbol)
217         field_value_array.append(field_expression)
218
219     symbol_array_variable = '${}'.format(counter)
220     counter += 1
221
222     prestatements.append(
223         NormalSymbolArrayVariableInitializationStatement(
224             variable=symbol_array_variable,
225             symbol_list=tuple(field_symbol_array),
226         )
227     )
228
229     value_array_variable = '${}'.format(counter)
230     counter += 1
231
232     prestatements.append(
233         NormalArrayVariableInitializationStatement(
234             variable=value_array_variable,
235             items=tuple(field_value_array),
236         )
237     )
238
239     variable = '${}'.format(counter)
240
241     prestatements.append(
242         NormalVariableInitializationStatement(
243             variable=variable,
244             expression=NormalStructureLiteralExpression(
245                 field_count=len(expression.fields),
246                 symbol_list_variable=symbol_array_variable,
247                 value_list_variable=value_array_variable,
248             ),
249         )
250     )
251
252     return (
253         counter + 1,
254         tuple(prestatements),
255         NormalVariableExpression(variable=variable),
256     )
257
258
259 def normalize_symbol_expression(counter, expression):
260     return (
261         counter,
262         (),
263         NormalSymbolExpression(symbol=expression.symbol),
264     )
265
266 def normalize_function_call_expression(counter, expression):
267     prestatements = []
268
269     for argument in expression.argument_list:
270         counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
271
272         for s in argument_prestatements:
273             prestatements.append(s)
274
275         prestatements.append(
276             NormalPushStatement(
277                 expression=normalized_argument,
278             ),
279         )
280
281     counter, function_prestatements, function_expression = normalize_expression(
282         counter,
283         expression.function,
284     )
285
286     for ps in function_prestatements:
287         prestatements.append(ps)
288
289     result_variable = '${}'.format(counter)
290
291     prestatements.append(
292         NormalVariableInitializationStatement(
293             variable=result_variable,
294             expression=NormalFunctionCallExpression(
295                 metadata=expression.metadata,
296                 function_expression=function_expression,
297                 argument_count=len(expression.argument_list),
298             ),
299         )
300     )
301
302     return (
303         counter + 1,
304         tuple(prestatements),
305         NormalVariableExpression(variable=result_variable),
306     )
307
308 def normalize_if_expression(counter, expression):
309     counter, condition_prestatements, condition_expression = normalize_expression(
310         counter,
311         expression.condition_expression,
312     )
313
314     counter, if_statement_list = normalize_statement_list(
315         counter,
316         expression.if_statement_list,
317     )
318     counter, else_statement_list = normalize_statement_list(
319         counter,
320         expression.else_statement_list,
321     )
322
323     return (
324         counter,
325         condition_prestatements,
326         NormalIfElseExpression(
327             condition_expression=condition_expression,
328             if_statement_list=if_statement_list,
329             else_statement_list=else_statement_list,
330         ),
331     )
332
333 def normalize_expression(counter, expression):
334     return {
335         desugaring.DesugaredFunctionCallExpression: normalize_function_call_expression,
336         desugaring.DesugaredIfExpression: normalize_if_expression,
337         desugaring.DesugaredIntegerLiteralExpression: normalize_integer_literal_expression,
338         desugaring.DesugaredLambdaExpression: normalize_lambda_expression,
339         desugaring.DesugaredListLiteralExpression: normalize_list_literal_expression,
340         desugaring.DesugaredStringLiteralExpression: normalize_string_literal_expression,
341         desugaring.DesugaredStructureLiteralExpression: normalize_structure_literal_expression,
342         desugaring.DesugaredSymbolExpression: normalize_symbol_expression,
343     }[type(expression)](counter, expression)
344
345 def normalize_expression_statement(counter, statement):
346     # TODO Normalized will be a NormalVariableExpression, which will go unused
347     # for expression statements in every case except when it's a return
348     # statement. This cases warnings on C compilation. We should only generate
349     # this variable when it will be used on return.
350     counter, prestatements, normalized = normalize_expression(counter, statement.expression)
351
352     return (
353         counter,
354         prestatements,
355         NormalExpressionStatement(expression=normalized),
356     )
357
358 def normalize_assignment_statement(counter, statement):
359     counter, prestatements, normalized_expression = normalize_expression(counter, statement.expression)
360     return (
361         counter,
362         prestatements,
363         NormalAssignmentStatement(
364             target=statement.target,
365             expression=normalized_expression,
366         ),
367     )
368
369 def normalize_statement(counter, statement):
370     return {
371         desugaring.DesugaredAssignmentStatement: normalize_assignment_statement,
372         desugaring.DesugaredExpressionStatement: normalize_expression_statement,
373     }[type(statement)](counter, statement)
374
375 @util.force_generator(tuple)
376 def normalize_statement_list(counter, statement_list):
377     result_statement_list = []
378
379     for statement in statement_list:
380         counter, prestatements, normalized = normalize_statement(counter, statement)
381         for s in prestatements:
382             result_statement_list.append(s)
383         result_statement_list.append(normalized)
384
385     return (
386         counter,
387         result_statement_list,
388     )
389
390 def normalize(program):
391     _, statement_list = normalize_statement_list(0, program.statement_list)
392
393     return NormalProgram(
394         statement_list=statement_list,
395     )