9725b5b54e70fa84b5ff6fb290c748a26788dc3e
[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         'argument_name_list',
24         'statement_list',
25     ),
26 )
27
28 NormalStringLiteralExpression = collections.namedtuple(
29     'NormalStringLiteralExpression',
30     [
31         'string',
32     ],
33 )
34
35 NormalSymbolExpression = collections.namedtuple(
36     'NormalSymbolExpression',
37     [
38         'symbol',
39     ],
40 )
41
42 NormalPushStatement = collections.namedtuple(
43     'NormalPushStatement',
44     (
45         'expression',
46     ),
47 )
48
49 NormalFunctionCallExpression = collections.namedtuple(
50     'NormalFunctionCallExpression',
51     [
52         'metadata',
53         'function_expression',
54         'argument_count',
55     ],
56 )
57
58 NormalArrayVariableInitializationStatement = collections.namedtuple(
59     'NormalArrayVariableInitializationStatement',
60     [
61         'variable',
62         'items',
63     ],
64 )
65
66 NormalSymbolArrayVariableInitializationStatement = collections.namedtuple(
67     'NormalSymbolArrayVariableInitializationStatement',
68     [
69         'variable',
70         'symbol_list',
71     ],
72 )
73
74 NormalVariableInitializationStatement = collections.namedtuple(
75     'NormalVariableInitializationStatement',
76     [
77         'variable',
78         'expression',
79     ],
80 )
81
82 NormalVariableReassignmentStatement = collections.namedtuple(
83     'NormalVariableReassignmentStatement',
84     [
85         'variable',
86         'expression',
87     ],
88 )
89
90 NormalExpressionStatement = collections.namedtuple(
91     'NormalExpressionStatement',
92     [
93         'expression',
94     ],
95 )
96
97 NormalAssignmentStatement = collections.namedtuple(
98     'NormalAssignmentStatement',
99     [
100         'target',
101         'expression',
102     ],
103 )
104
105 NormalIfElseStatement = collections.namedtuple(
106     'NormalIfElseStatement',
107     [
108         'condition_expression',
109         'if_statement_list',
110         'else_statement_list',
111     ],
112 )
113
114 NormalFunctionDefinitionStatement = collections.namedtuple(
115     'NormalFunctionDefinitionStatement',
116     [
117         'name',
118         'argument_name_list',
119         'statement_list',
120     ],
121 )
122
123 NormalProgram = collections.namedtuple(
124     'NormalProgram',
125     [
126         'statement_list',
127     ],
128 )
129
130 def normalize_integer_literal_expression(counter, expression):
131     variable = '${}'.format(counter)
132     return (
133         counter + 1,
134         (
135             NormalVariableInitializationStatement(
136                 variable=variable,
137                 expression=NormalIntegerLiteralExpression(integer=expression.integer),
138             ),
139         ),
140         NormalVariableExpression(variable=variable),
141     )
142
143 def normalize_lambda_expression(counter, expression):
144     variable = '${}'.format(counter)
145
146     _, statement_list = normalize_statement_list(
147         0,
148         expression.statement_list,
149         assign_result_to='result',
150     )
151
152     return (
153         counter + 1,
154         (
155             NormalVariableInitializationStatement(
156                 variable=variable,
157                 expression=NormalLambdaExpression(
158                     argument_name_list=expression.argument_name_list,
159                     statement_list=statement_list,
160                 ),
161             ),
162         ),
163         NormalVariableExpression(variable=variable),
164     )
165
166 NormalListConstructExpression = collections.namedtuple(
167     'NormalListConstructExpression',
168     [
169         'allocate',
170     ],
171 )
172
173 NormalListAppendStatement = collections.namedtuple(
174     'NormalListAppendStatement',
175     [
176         'list_expression',
177         'item_expression',
178     ],
179 )
180
181 def normalize_list_literal_expression(counter, expression):
182     list_variable = '${}'.format(counter)
183     counter += 1
184
185     prestatements = [
186         NormalVariableInitializationStatement(
187             variable=list_variable,
188             expression=NormalListConstructExpression(allocate=len(expression.item_expression_list)),
189         ),
190     ]
191
192     list_expression = NormalVariableExpression(variable=list_variable)
193
194     for item_expression in expression.item_expression_list:
195         counter, item_expression_prestatements, normalized = normalize_expression(
196             counter,
197             item_expression,
198         )
199
200         for p in item_expression_prestatements:
201             prestatements.append(p)
202
203         prestatements.append(
204             NormalListAppendStatement(
205                 list_expression=list_expression,
206                 item_expression=normalized,
207             )
208         )
209
210     return (
211         counter,
212         tuple(prestatements),
213         list_expression,
214     )
215
216 def normalize_string_literal_expression(counter, expression):
217     variable = '${}'.format(counter)
218     return (
219         counter + 1,
220         (
221             NormalVariableInitializationStatement(
222                 variable=variable,
223                 expression=NormalStringLiteralExpression(string=expression.string),
224             ),
225         ),
226         NormalVariableExpression(variable=variable),
227     )
228
229 NormalStructureLiteralExpression = collections.namedtuple(
230     'NormalStructureLiteralExpression',
231     [
232         'field_count',
233         'symbol_list_variable',
234         'value_list_variable',
235     ],
236 )
237
238 def normalize_structure_literal_expression(counter, expression):
239     prestatements = []
240     field_symbol_array = []
241     field_value_array = []
242
243     for symbol_expression_pair in expression.fields:
244         counter, field_prestatements, field_expression = normalize_expression(
245             counter,
246             symbol_expression_pair.expression,
247         )
248
249         for p in field_prestatements:
250             prestatements.append(p)
251
252         field_symbol_array.append(symbol_expression_pair.symbol)
253         field_value_array.append(field_expression)
254
255     symbol_array_variable = '${}'.format(counter)
256     counter += 1
257
258     prestatements.append(
259         NormalSymbolArrayVariableInitializationStatement(
260             variable=symbol_array_variable,
261             symbol_list=tuple(field_symbol_array),
262         )
263     )
264
265     value_array_variable = '${}'.format(counter)
266     counter += 1
267
268     prestatements.append(
269         NormalArrayVariableInitializationStatement(
270             variable=value_array_variable,
271             items=tuple(field_value_array),
272         )
273     )
274
275     variable = '${}'.format(counter)
276
277     prestatements.append(
278         NormalVariableInitializationStatement(
279             variable=variable,
280             expression=NormalStructureLiteralExpression(
281                 field_count=len(expression.fields),
282                 symbol_list_variable=symbol_array_variable,
283                 value_list_variable=value_array_variable,
284             ),
285         )
286     )
287
288     return (
289         counter + 1,
290         tuple(prestatements),
291         NormalVariableExpression(variable=variable),
292     )
293
294
295 def normalize_symbol_expression(counter, expression):
296     variable = '${}'.format(counter)
297     return (
298         counter + 1,
299         (
300             NormalVariableInitializationStatement(
301                 variable=variable,
302                 expression=NormalSymbolExpression(symbol=expression.symbol),
303             ),
304         ),
305         NormalVariableExpression(variable=variable),
306     )
307
308 def normalize_function_call_expression(counter, expression):
309     prestatements = []
310
311     for argument in expression.argument_list:
312         counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
313
314         for s in argument_prestatements:
315             prestatements.append(s)
316
317         variable = '${}'.format(counter)
318         prestatements.append(
319             NormalVariableInitializationStatement(
320                 variable=variable,
321                 expression=normalized_argument,
322             )
323         )
324         prestatements.append(
325             NormalPushStatement(
326                 expression=NormalVariableExpression(
327                     variable=variable,
328                 ),
329             ),
330         )
331         counter += 1
332
333     counter, function_prestatements, function_expression = normalize_expression(
334         counter,
335         expression.function,
336     )
337
338     for ps in function_prestatements:
339         prestatements.append(ps)
340
341     if not isinstance(function_expression, NormalVariableExpression):
342         function_variable = '${}'.format(counter)
343
344         prestatements.append(
345             NormalVariableInitializationStatement(
346                 variable=function_variable,
347                 expression=function_expression,
348             )
349         )
350
351         function_expression = NormalVariableExpression(variable=function_variable)
352         counter += 1
353
354     result_variable = '${}'.format(counter)
355
356     prestatements.append(
357         NormalVariableInitializationStatement(
358             variable=result_variable,
359             expression=NormalFunctionCallExpression(
360                 metadata=expression.metadata,
361                 function_expression=function_expression,
362                 argument_count=len(expression.argument_list),
363             ),
364         )
365     )
366
367     return (
368         counter + 1,
369         tuple(prestatements),
370         NormalVariableExpression(variable=result_variable),
371     )
372
373 def normalize_if_expression(counter, expression):
374     counter, condition_prestatements, condition_expression = normalize_expression(
375         counter,
376         expression.condition_expression,
377     )
378
379     result_variable = '${}'.format(counter)
380     counter += 1
381
382     counter, if_statement_list = normalize_statement_list(
383         counter,
384         expression.if_statement_list,
385         assign_result_to=result_variable,
386     )
387     counter, else_statement_list = normalize_statement_list(
388         counter,
389         expression.else_statement_list,
390         assign_result_to=result_variable,
391     )
392
393     return (
394         counter,
395         condition_prestatements + (
396             NormalVariableInitializationStatement(
397                 variable=result_variable,
398                 expression=NormalVariableExpression(variable='builtin$nil'),
399             ),
400             NormalIfElseStatement(
401                 condition_expression=condition_expression,
402                 if_statement_list=if_statement_list,
403                 else_statement_list=else_statement_list,
404             ),
405         ),
406         NormalVariableExpression(variable=result_variable),
407     )
408
409 def normalize_expression(counter, expression):
410     return {
411         desugaring.DesugaredFunctionCallExpression: normalize_function_call_expression,
412         desugaring.DesugaredIfExpression: normalize_if_expression,
413         desugaring.DesugaredIntegerLiteralExpression: normalize_integer_literal_expression,
414         desugaring.DesugaredLambdaExpression: normalize_lambda_expression,
415         desugaring.DesugaredListLiteralExpression: normalize_list_literal_expression,
416         desugaring.DesugaredStringLiteralExpression: normalize_string_literal_expression,
417         desugaring.DesugaredStructureLiteralExpression: normalize_structure_literal_expression,
418         desugaring.DesugaredSymbolExpression: normalize_symbol_expression,
419     }[type(expression)](counter, expression)
420
421 def normalize_expression_statement(counter, statement):
422     # TODO Normalized will be a NormalVariableExpression, which will go unused
423     # for expression statements in every case except when it's a return
424     # statement. This cases warnings on C compilation. We should only generate
425     # this variable when it will be used on return.
426     counter, prestatements, normalized = normalize_expression(counter, statement.expression)
427
428     return (
429         counter,
430         prestatements,
431         NormalExpressionStatement(expression=normalized),
432     )
433
434 def normalize_function_definition_statement(counter, statement):
435     _, statement_list = normalize_statement_list(
436         0,
437         statement.statement_list,
438         assign_result_to='result',
439     )
440     return (
441         counter,
442         (),
443         NormalFunctionDefinitionStatement(
444             name=statement.name,
445             argument_name_list=statement.argument_name_list,
446             statement_list=statement_list,
447         ),
448     )
449
450 def normalize_assignment_statement(counter, statement):
451     counter, prestatements, normalized_expression = normalize_expression(counter, statement.expression)
452     return (
453         counter,
454         prestatements,
455         NormalAssignmentStatement(
456             target=statement.target,
457             expression=normalized_expression,
458         ),
459     )
460
461 def normalize_statement(counter, statement):
462     return {
463         desugaring.DesugaredAssignmentStatement: normalize_assignment_statement,
464         desugaring.DesugaredExpressionStatement: normalize_expression_statement,
465         desugaring.DesugaredFunctionDefinitionStatement: normalize_function_definition_statement,
466     }[type(statement)](counter, statement)
467
468 @util.force_generator(tuple)
469 def normalize_statement_list(counter, statement_list, **kwargs):
470     assign_result_to = kwargs.pop('assign_result_to', None)
471
472     assert len(kwargs) == 0
473
474     result_statement_list = []
475
476     for statement in statement_list:
477         counter, prestatements, normalized = normalize_statement(counter, statement)
478         for s in prestatements:
479             result_statement_list.append(s)
480         result_statement_list.append(normalized)
481
482     # TODO The way we fix the last statement is really confusing
483     last_statement = result_statement_list[-1]
484
485     if isinstance(last_statement, NormalExpressionStatement) and isinstance(last_statement.expression, NormalVariableExpression):
486         if assign_result_to is not None:
487             result_expression = result_statement_list.pop().expression
488             result_statement_list.append(
489                 NormalVariableReassignmentStatement(
490                     variable=assign_result_to,
491                     expression=result_expression,
492                 )
493             )
494
495     return (
496         counter,
497         result_statement_list,
498     )
499
500 def normalize(program):
501     _, statement_list = normalize_statement_list(0, program.statement_list)
502
503     return NormalProgram(
504         statement_list=statement_list,
505     )