Desugaring pass (#9)
[fur] / transformation.py
1 import collections
2
3 import normalization
4 import parsing # TODO Remove this import, as we should be normalizing everything before it gets here
5
6 CIntegerLiteral = collections.namedtuple(
7     'CIntegerLiteral',
8     [
9         'value',
10     ],
11 )
12
13 CStringLiteral = collections.namedtuple(
14     'CStringLiteral',
15     [
16         'index',
17         'value',
18     ],
19 )
20
21 CVariableExpression = collections.namedtuple(
22     'CVariableExpression',
23     [
24         'variable',
25     ],
26 )
27
28 CSymbolExpression = collections.namedtuple(
29     'CSymbolExpression',
30     [
31         'symbol',
32         'symbol_list_index',
33     ],
34 )
35
36 CStructureLiteralExpression = collections.namedtuple(
37     'CStructureLiteralExpression',
38     [
39         'field_count',
40         'symbol_list_variable',
41         'value_list_variable',
42     ],
43 )
44
45 CPushStatement = collections.namedtuple(
46     'CPushStatement',
47     (
48         'expression',
49     ),
50 )
51
52 CFunctionCallExpression = collections.namedtuple(
53     'CFunctionCallExpression',
54     (
55         'metadata',
56         'function_expression',
57         'argument_count',
58     ),
59 )
60
61 # TODO We are currently not changing variables, just preventing them from being accessed.
62 CSymbolAssignmentStatement = collections.namedtuple(
63     'CSymbolAssignmentStatement',
64     [
65         'target',
66         'target_symbol_list_index',
67         'expression',
68     ],
69 )
70
71 CArrayVariableInitializationStatement = collections.namedtuple(
72     'CArrayVariableInitializationStatement',
73     [
74         'variable',
75         'items',
76     ],
77 )
78
79 CSymbolArrayVariableInitializationStatement = collections.namedtuple(
80     'CSymbolArrayVariableInitializationStatement',
81     [
82         'variable',
83         'symbol_list',
84         'symbol_list_indices',
85     ],
86 )
87
88 CVariableInitializationStatement = collections.namedtuple(
89     'CVariableInitializationStatement',
90     [
91         'variable',
92         'expression',
93     ],
94 )
95
96 CVariableReassignmentStatement = collections.namedtuple(
97     'CVariableReassignmentStatement',
98     [
99         'variable',
100         'expression',
101     ],
102 )
103
104 CExpressionStatement = collections.namedtuple(
105     'CExpressionStatement',
106     [
107         'expression',
108     ],
109 )
110
111 CIfElseStatement = collections.namedtuple(
112     'CIfElseStatement',
113     [
114         'condition_expression',
115         'if_statement_list',
116         'else_statement_list',
117     ],
118 )
119
120 CFunctionDeclaration = collections.namedtuple(
121     'CFunctionDeclaration',
122     [
123         'name',
124     ],
125 )
126
127 # TODO If a function definition doesn't end with an expression, we have issues currently because we try to return statement.
128 # TODO Closures currently wrap entire defining environment, even symbols that are not used, which makes garbage collection ineffective.
129 CFunctionDefinition = collections.namedtuple(
130     'CFunctionDefinition',
131     [
132         'name',
133         'argument_name_list',
134         'statement_list',
135     ],
136 )
137
138 CProgram = collections.namedtuple(
139     'CProgram',
140     [
141         'builtin_set',
142         'function_definition_list',
143         'operator_declarations',
144         'statements',
145         'standard_libraries',
146         'string_literal_list',
147         'symbol_list',
148     ],
149 )
150
151 BUILTINS = {
152     'concatenate':      [],
153     'false':            [],
154     'pow':              ['math.h'],
155     'print':            ['stdio.h'],
156     'true':             [],
157 }
158
159 def transform_variable_expression(accumulators, expression):
160     assert isinstance(expression, normalization.NormalVariableExpression)
161     return CVariableExpression(variable=expression.variable)
162
163 def transform_string_literal_expression(accumulators, expression):
164     value = expression.string
165
166     try:
167         index = accumulators.string_literal_list.index(value)
168     except ValueError:
169         index = len(accumulators.string_literal_list)
170         accumulators.string_literal_list.append(value)
171
172     return CStringLiteral(index=index, value=value)
173
174 def transform_symbol_expression(accumulators, expression):
175     if expression.symbol in BUILTINS:
176         accumulators.builtin_set.add(expression.symbol)
177
178     try:
179         symbol_list_index = accumulators.symbol_list.index(expression.symbol)
180     except ValueError:
181         symbol_list_index = len(accumulators.symbol_list)
182         accumulators.symbol_list.append(expression.symbol)
183
184     return CSymbolExpression(
185         symbol=expression.symbol,
186         symbol_list_index=symbol_list_index,
187     )
188
189 def transform_integer_literal_expression(accumulators, expression):
190     return CIntegerLiteral(value=expression.integer)
191
192 CListConstructExpression = collections.namedtuple(
193     'CListConstructExpression',
194     [
195         'allocate',
196     ],
197 )
198
199 CListAppendStatement = collections.namedtuple(
200     'CListAppendStatement',
201     [
202         'list_expression',
203         'item_expression',
204     ],
205 )
206
207 CListGetExpression = collections.namedtuple(
208     'CListGetExpression',
209     [
210         'list_expression',
211         'index_expression',
212     ],
213 )
214
215 def transform_structure_literal_expression(accumulators, expression):
216     return CStructureLiteralExpression(
217         field_count=expression.field_count,
218         symbol_list_variable=expression.symbol_list_variable,
219         value_list_variable=expression.value_list_variable,
220     )
221
222 def transform_list_construct_expression(accumulators, expression):
223     return CListConstructExpression(allocate=expression.allocate)
224
225 def transform_list_get_expression(accumulators, expression):
226     return CListGetExpression(
227         list_expression=transform_expression(accumulators, expression.list_expression),
228         index_expression=transform_expression(accumulators, expression.index_expression),
229     )
230
231 def transform_list_append_statement(accumulators, expression):
232     return CListAppendStatement(
233         list_expression=transform_expression(accumulators, expression.list_expression),
234         item_expression=transform_expression(accumulators, expression.item_expression),
235     )
236
237 def transform_expression(accumulators, expression):
238     return {
239         normalization.NormalFunctionCallExpression: transform_function_call_expression,
240         normalization.NormalIntegerLiteralExpression: transform_integer_literal_expression,
241         normalization.NormalListConstructExpression: transform_list_construct_expression,
242         normalization.NormalListGetExpression: transform_list_get_expression,
243         normalization.NormalStructureLiteralExpression: transform_structure_literal_expression,
244         normalization.NormalStringLiteralExpression: transform_string_literal_expression,
245         normalization.NormalSymbolExpression: transform_symbol_expression,
246         normalization.NormalVariableExpression: transform_variable_expression,
247     }[type(expression)](accumulators, expression)
248
249 def transform_symbol_assignment_statement(accumulators, assignment_statement):
250     # TODO Check that target is not a builtin
251     try:
252         symbol_list_index = accumulators.symbol_list.index(assignment_statement.target)
253     except ValueError:
254         symbol_list_index = len(accumulators.symbol_list)
255         accumulators.symbol_list.append(assignment_statement.target)
256
257     return CSymbolAssignmentStatement(
258         target=assignment_statement.target,
259         target_symbol_list_index=symbol_list_index,
260         expression=transform_expression(
261             accumulators,
262             assignment_statement.expression,
263         ),
264     )
265
266 def transform_function_call_expression(accumulators, function_call):
267     # TODO Use the symbol from SYMBOL LIST
268     return CFunctionCallExpression(
269         metadata=function_call.metadata,
270         function_expression=transform_expression(accumulators, function_call.function_expression),
271         argument_count=function_call.argument_count,
272     )
273
274 def transform_expression_statement(accumulators, statement):
275     return CExpressionStatement(
276         expression=transform_expression(accumulators, statement.expression),
277     )
278
279 def transform_if_else_statement(accumulators, statement):
280     return CIfElseStatement(
281         condition_expression=transform_expression(accumulators, statement.condition_expression),
282         if_statement_list=tuple(transform_statement(accumulators, s) for s in statement.if_statement_list),
283         else_statement_list=tuple(transform_statement(accumulators, s) for s in statement.else_statement_list),
284     )
285
286 def transform_array_variable_initialization_statement(accumulators, statement):
287     return CArrayVariableInitializationStatement(
288         variable=statement.variable,
289         items=tuple(transform_expression(accumulators, i) for i in statement.items),
290     )
291
292 def transform_symbol_array_variable_initialization_statement(accumulators, statement):
293     symbol_list_indices = []
294
295     for symbol in statement.symbol_list:
296         try:
297             symbol_list_index = accumulators.symbol_list.index(symbol)
298         except ValueError:
299             symbol_list_index = len(accumulators.symbol_list)
300             accumulators.symbol_list.append(symbol)
301
302         symbol_list_indices.append(symbol_list_index)
303
304     return CSymbolArrayVariableInitializationStatement(
305         variable=statement.variable,
306         symbol_list=statement.symbol_list,
307         symbol_list_indices=tuple(symbol_list_indices),
308     )
309
310 def transform_variable_initialization_statement(accumulators, statement):
311     return CVariableInitializationStatement(
312         variable=statement.variable,
313         expression=transform_expression(accumulators, statement.expression),
314     )
315
316 def transform_variable_reassignment_statement(accumulators, statement):
317     return CVariableReassignmentStatement(
318         variable=statement.variable,
319         expression=transform_expression(accumulators, statement.expression),
320     )
321
322 def transform_function_definition_statement(accumulators, statement):
323     # TODO Allow defining the same function in different contexts
324     if any(fd.name == statement.name for fd in accumulators.function_definition_list):
325         raise Exception('A function with name "{}" already exists'.format(statement.name))
326
327     # TODO Add argument names to the symbol table
328     accumulators.function_definition_list.append(CFunctionDefinition(
329         name=statement.name,
330         argument_name_list=statement.argument_name_list,
331         statement_list=tuple(transform_statement(accumulators, s) for s in statement.statement_list)
332     ))
333
334     return CFunctionDeclaration(name=statement.name)
335
336 def transform_push_statement(accumulators, statement):
337     return CPushStatement(expression=transform_expression(accumulators, statement.expression))
338
339 def transform_statement(accumulators, statement):
340     return {
341         normalization.NormalArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
342         normalization.NormalAssignmentStatement: transform_symbol_assignment_statement,
343         normalization.NormalExpressionStatement: transform_expression_statement,
344         normalization.NormalFunctionDefinitionStatement: transform_function_definition_statement,
345         normalization.NormalIfElseStatement: transform_if_else_statement,
346         normalization.NormalListAppendStatement: transform_list_append_statement,
347         normalization.NormalPushStatement: transform_push_statement,
348         normalization.NormalSymbolArrayVariableInitializationStatement: transform_symbol_array_variable_initialization_statement,
349         normalization.NormalVariableInitializationStatement: transform_variable_initialization_statement,
350         normalization.NormalVariableReassignmentStatement: transform_variable_reassignment_statement,
351     }[type(statement)](accumulators, statement)
352
353
354 Accumulators = collections.namedtuple(
355     'Accumulators',
356     [
357         'builtin_set',
358         'function_definition_list',
359         'operator_set',
360         'symbol_list',
361         'string_literal_list',
362     ],
363 )
364
365 def transform(program):
366     accumulators = Accumulators(
367         builtin_set=set(),
368         function_definition_list=[],
369         operator_set=set(),
370         symbol_list=[],
371         string_literal_list=[],
372     )
373
374     statement_list = [
375         transform_statement(accumulators, statement) for statement in program.statement_list
376     ]
377
378     standard_library_set = set()
379     for builtin in accumulators.builtin_set:
380         for standard_library in BUILTINS[builtin]:
381             standard_library_set.add(standard_library)
382
383     return CProgram(
384         builtin_set=accumulators.builtin_set,
385         function_definition_list=accumulators.function_definition_list,
386         operator_declarations=tuple(sorted(accumulators.operator_set)),
387         statements=statement_list,
388         standard_libraries=standard_library_set,
389         string_literal_list=accumulators.string_literal_list,
390         symbol_list=accumulators.symbol_list,
391     )
392
393
394 if __name__ == '__main__':
395     import unittest
396
397     unittest.main()