Fixed some TODOs
[fur] / normalization.py
1 import collections
2
3 import parsing
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 NormalNegationExpression = collections.namedtuple(
35     'NormalNegationExpression',
36     [
37         'internal_expression',
38     ],
39 )
40
41 NormalInfixExpression = collections.namedtuple(
42     'NormalInfixExpression',
43     [
44         'order',
45         'operator',
46         'left',
47         'right',
48     ],
49 )
50
51 NormalFunctionCallExpression = collections.namedtuple(
52     'NormalFunctionCallExpression',
53     [
54         'function',
55         'argument_count',
56         'argument_items',
57     ],
58 )
59
60 NormalArrayVariableInitializationStatement = collections.namedtuple(
61     'NormalArrayVariableInitializationStatement',
62     [
63         'variable',
64         'items',
65     ],
66 )
67
68 NormalVariableInitializationStatement = collections.namedtuple(
69     'NormalVariableInitializationStatement',
70     [
71         'variable',
72         'expression',
73     ],
74 )
75
76 NormalVariableReassignmentStatement = collections.namedtuple(
77     'NormalVariableReassignmentStatement',
78     [
79         'variable',
80         'expression',
81     ],
82 )
83
84 NormalExpressionStatement = collections.namedtuple(
85     'NormalExpressionStatement',
86     [
87         'expression',
88     ],
89 )
90
91 NormalAssignmentStatement = collections.namedtuple(
92     'NormalAssignmentStatement',
93     [
94         'target',
95         'expression',
96     ],
97 )
98
99 NormalIfElseStatement = collections.namedtuple(
100     'NormalIfElseStatement',
101     [
102         'condition_expression',
103         'if_statements',
104         'else_statements',
105     ],
106 )
107
108 NormalFunctionDefinitionStatement = collections.namedtuple(
109     'NormalFunctionDefinitionStatement',
110     [
111         'name',
112         'argument_name_list',
113         'statement_list',
114     ],
115 )
116
117 NormalProgram = collections.namedtuple(
118     'NormalProgram',
119     [
120         'statement_list',
121     ],
122 )
123
124 def fake_normalization(counter, thing):
125     return (counter, (), thing)
126
127 def normalize_integer_literal_expression(counter, expression):
128     # TODO Store this in a C variable
129     return (
130         counter,
131         (),
132         NormalIntegerLiteralExpression(integer=expression.integer),
133     )
134
135 def normalize_string_literal_expression(counter, expression):
136     # TODO Store this in a C variable
137     return (
138         counter,
139         (),
140         NormalStringLiteralExpression(string=expression.string),
141     )
142
143 def normalize_symbol_expression(counter, expression):
144     # TODO Store this in a C variable
145     return (
146         counter,
147         (),
148         NormalSymbolExpression(symbol=expression.symbol),
149     )
150
151 def normalize_function_call_expression(counter, expression):
152     assert isinstance(expression, parsing.FurFunctionCallExpression)
153
154     prestatements = []
155     arguments = []
156
157     for argument in expression.arguments:
158         counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
159
160         for s in argument_prestatements:
161             prestatements.append(s)
162
163         variable = '${}'.format(counter)
164         prestatements.append(NormalVariableInitializationStatement(
165             variable=variable,
166             expression=normalized_argument,
167         ))
168         arguments.append(NormalVariableExpression(
169             variable=variable,
170         ))
171         counter += 1
172
173     arguments_variable = '${}'.format(counter)
174     counter += 1
175
176     prestatements.append(NormalArrayVariableInitializationStatement(
177         variable=arguments_variable,
178         items=tuple(arguments),
179     ))
180
181     counter, function_prestatements, function_expression = normalize_expression(
182         counter,
183         expression.function,
184     )
185
186     for ps in function_prestatements:
187         prestatements.append(ps)
188
189     return (
190         counter,
191         tuple(prestatements),
192         NormalFunctionCallExpression(
193             function=function_expression,
194             argument_count=len(arguments),
195             argument_items=NormalVariableExpression(variable=arguments_variable),
196         ),
197     )
198
199 def normalize_basic_infix_operation(counter, expression):
200     counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
201     counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
202
203     left_variable = '${}'.format(counter)
204     counter += 1
205     right_variable = '${}'.format(counter)
206     counter += 1
207
208     root_prestatements = (
209         NormalVariableInitializationStatement(
210             variable=left_variable,
211             expression=left_expression,
212         ),
213         NormalVariableInitializationStatement(
214             variable=right_variable,
215             expression=right_expression,
216         ),
217     )
218
219     return (
220         counter,
221         left_prestatements + right_prestatements + root_prestatements,
222         NormalInfixExpression(
223             order=expression.order,
224             operator=expression.operator,
225             left=NormalVariableExpression(variable=left_variable),
226             right=NormalVariableExpression(variable=right_variable),
227         ),
228     )
229
230 def normalize_comparison_expression(counter, expression):
231     stack = []
232
233     while isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level':
234         stack.append((expression.operator, expression.order, expression.right))
235         expression = expression.left
236
237     counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
238     counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
239
240     left_variable = '${}'.format(counter)
241     counter += 1
242     right_variable = '${}'.format(counter)
243     counter += 1
244
245     root_prestatements = (
246         NormalVariableInitializationStatement(
247             variable=left_variable,
248             expression=left_expression,
249         ),
250         NormalVariableInitializationStatement(
251             variable=right_variable,
252             expression=right_expression,
253         ),
254     )
255
256     counter, result_prestatements, result_expression = (
257         counter,
258         left_prestatements + right_prestatements + root_prestatements,
259         NormalInfixExpression(
260             order=expression.order,
261             operator=expression.operator,
262             left=NormalVariableExpression(variable=left_variable),
263             right=NormalVariableExpression(variable=right_variable),
264         ),
265     )
266
267     while len(stack) > 0:
268         right_operator, right_order, right_expression = stack.pop()
269         and_right_expression = parsing.FurInfixExpression(
270             operator=right_operator,
271             order=right_order,
272             left=NormalVariableExpression(variable=right_variable),
273             right=right_expression,
274         )
275
276         and_expression = parsing.FurInfixExpression(
277             operator='and',
278             order='and_level',
279             left=result_expression,
280             right=and_right_expression,
281         )
282
283         counter, and_prestatements, result_expression = normalize_boolean_expression(
284             counter,
285             and_expression,
286         )
287
288         result_prestatements = result_prestatements + and_prestatements
289
290     return (counter, result_prestatements, result_expression)
291
292 def normalize_boolean_expression(counter, expression):
293     counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
294     counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
295
296     result_variable = '${}'.format(counter)
297     if_else_prestatment = NormalVariableInitializationStatement(variable=result_variable, expression=left_expression)
298     counter += 1
299
300     condition_expression=NormalVariableExpression(variable=result_variable)
301     short_circuited_statements = right_prestatements + (NormalVariableReassignmentStatement(variable=result_variable, expression=right_expression),)
302
303     if expression.operator == 'and':
304         if_else_statement = NormalIfElseStatement(
305             condition_expression=condition_expression,
306             if_statements=short_circuited_statements,
307             else_statements=(),
308         )
309
310     elif expression.operator == 'or':
311         if_else_statement = NormalIfElseStatement(
312             condition_expression=condition_expression,
313             if_statements=(),
314             else_statements=short_circuited_statements,
315         )
316
317     else:
318         raise Exception('Unable to handle operator "{}"'.format(expression.operator))
319
320     return (
321         counter,
322         left_prestatements + (if_else_prestatment, if_else_statement),
323         NormalVariableExpression(variable=result_variable),
324     )
325
326
327 def normalize_infix_expression(counter, expression):
328     return {
329         'multiplication_level': normalize_basic_infix_operation,
330         'addition_level': normalize_basic_infix_operation,
331         'comparison_level': normalize_comparison_expression,
332         'and_level': normalize_boolean_expression,
333         'or_level': normalize_boolean_expression,
334     }[expression.order](counter, expression)
335
336 def normalize_negation_expression(counter, expression):
337     counter, prestatements, internal_expression = normalize_expression(counter, expression.value)
338
339     internal_variable = '${}'.format(counter)
340     counter += 1
341
342     return (
343         counter,
344         prestatements + (NormalVariableInitializationStatement(variable=internal_variable, expression=internal_expression),),
345         NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)),
346     )
347
348 def normalize_expression(counter, expression):
349     return {
350         NormalInfixExpression: fake_normalization,
351         NormalVariableExpression: fake_normalization,
352         parsing.FurFunctionCallExpression: normalize_function_call_expression,
353         parsing.FurInfixExpression: normalize_infix_expression,
354         parsing.FurIntegerLiteralExpression: normalize_integer_literal_expression,
355         parsing.FurNegationExpression: normalize_negation_expression,
356         parsing.FurStringLiteralExpression: normalize_string_literal_expression,
357         parsing.FurSymbolExpression: normalize_symbol_expression,
358     }[type(expression)](counter, expression)
359
360 def normalize_expression_statement(counter, statement):
361     counter, prestatements, normalized = normalize_expression(counter, statement.expression)
362
363     return (
364         counter,
365         prestatements,
366         NormalExpressionStatement(expression=normalized),
367     )
368
369 def normalize_function_definition_statement(counter, statement):
370     return (
371         counter,
372         (),
373         NormalFunctionDefinitionStatement(
374             name=statement.name,
375             argument_name_list=statement.argument_name_list,
376             statement_list=normalize_statement_list(statement.statement_list),
377         ),
378     )
379
380 def normalize_assignment_statement(counter, statement):
381     counter, prestatements, normalized_expression = normalize_expression(counter, statement.expression)
382     return (
383         counter,
384         prestatements,
385         NormalAssignmentStatement(
386             target=statement.target,
387             expression=normalized_expression,
388         ),
389     )
390
391 def normalize_statement(counter, statement):
392     return {
393         parsing.FurAssignmentStatement: normalize_assignment_statement,
394         parsing.FurExpressionStatement: normalize_expression_statement,
395         parsing.FurFunctionDefinitionStatement: normalize_function_definition_statement,
396     }[type(statement)](counter, statement)
397
398 @util.force_generator(tuple)
399 def normalize_statement_list(statement_list):
400     counter = 0
401
402     for statement in statement_list:
403         counter, prestatements, normalized = normalize_statement(counter, statement)
404         for s in prestatements:
405             yield s
406         yield normalized
407
408 def normalize(program):
409
410     return NormalProgram(
411         statement_list=normalize_statement_list(program.statement_list),
412     )