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