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