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