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