Handle arguments to functions
[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 CExpressionStatement = collections.namedtuple(
96     'CExpressionStatement',
97     [
98         'expression',
99     ],
100 )
101
102 CIfElseExpression = collections.namedtuple(
103     'CIfElseExpression',
104     [
105         'condition_expression',
106         'if_statement_list',
107         'else_statement_list',
108     ],
109 )
110
111 # TODO If a function definition doesn't end with an expression, we have issues currently because we try to return statement.
112 # TODO Closures currently wrap entire defining environment, even symbols that are not used, which makes garbage collection ineffective.
113 CFunctionDefinition = collections.namedtuple(
114     'CFunctionDefinition',
115     [
116         'name',
117         'index',
118         'argument_name_list',
119         'statement_list',
120     ],
121 )
122
123 CProgram = collections.namedtuple(
124     'CProgram',
125     [
126         'builtin_set',
127         'function_definition_list',
128         'operator_declarations',
129         'statements',
130         'standard_libraries',
131         'string_literal_list',
132         'symbol_list',
133     ],
134 )
135
136 BUILTINS = {
137     'concatenate':      [],
138     'false':            [],
139     'pow':              ['math.h'],
140     'print':            ['stdio.h'],
141     'true':             [],
142 }
143
144 def transform_variable_expression(accumulators, expression):
145     assert isinstance(expression, conversion.CPSVariableExpression)
146     return CVariableExpression(variable=expression.variable)
147
148 def transform_string_literal_expression(accumulators, expression):
149     value = expression.string
150
151     try:
152         index = accumulators.string_literal_list.index(value)
153     except ValueError:
154         index = len(accumulators.string_literal_list)
155         accumulators.string_literal_list.append(value)
156
157     return CStringLiteral(index=index, value=value)
158
159 def transform_symbol_expression(accumulators, expression):
160     if expression.symbol in BUILTINS:
161         accumulators.builtin_set.add(expression.symbol)
162
163     try:
164         symbol_list_index = accumulators.symbol_list.index(expression.symbol)
165     except ValueError:
166         symbol_list_index = len(accumulators.symbol_list)
167         accumulators.symbol_list.append(expression.symbol)
168
169     return CSymbolExpression(
170         symbol=expression.symbol,
171         symbol_list_index=symbol_list_index,
172     )
173
174 def transform_integer_literal_expression(accumulators, expression):
175     return CIntegerLiteral(value=expression.integer)
176
177 CListConstructExpression = collections.namedtuple(
178     'CListConstructExpression',
179     (
180         'allocate',
181     ),
182 )
183
184 CLambdaExpression = collections.namedtuple(
185     'CLambdaExpression',
186     (
187         'name',
188         'index',
189     ),
190 )
191
192 CListAppendStatement = collections.namedtuple(
193     'CListAppendStatement',
194     (
195         'list_expression',
196         'item_expression',
197     ),
198 )
199
200 def transform_structure_literal_expression(accumulators, expression):
201     return CStructureLiteralExpression(
202         field_count=expression.field_count,
203         symbol_list_variable=expression.symbol_list_variable,
204         value_list_variable=expression.value_list_variable,
205     )
206
207 def transform_lambda_expression(accumulators, expression):
208     if expression.name is None:
209         name = '__lambda'
210     else:
211         name = expression.name
212
213     index = accumulators.function_name_iterators.get(name, 0)
214     accumulators.function_name_iterators[name] = index + 1
215
216     accumulators.function_definition_list.append(CFunctionDefinition(
217         name=name,
218         index=index,
219         argument_name_list=expression.argument_name_list,
220         statement_list=tuple(transform_statement(accumulators, s) for s in expression.statement_list),
221     ))
222
223     return CLambdaExpression(
224         name=name,
225         index=index,
226     )
227
228
229 def transform_list_construct_expression(accumulators, expression):
230     return CListConstructExpression(allocate=expression.allocate)
231
232 def transform_list_append_statement(accumulators, expression):
233     return CListAppendStatement(
234         list_expression=transform_expression(accumulators, expression.list_expression),
235         item_expression=transform_expression(accumulators, expression.item_expression),
236     )
237
238 def transform_expression(accumulators, expression):
239     return {
240         conversion.CPSFunctionCallExpression: transform_function_call_expression,
241         conversion.CPSIfElseExpression: transform_if_else_expression,
242         conversion.CPSIntegerLiteralExpression: transform_integer_literal_expression,
243         conversion.CPSLambdaExpression: transform_lambda_expression,
244         conversion.CPSListConstructExpression: transform_list_construct_expression,
245         conversion.CPSStructureLiteralExpression: transform_structure_literal_expression,
246         conversion.CPSStringLiteralExpression: transform_string_literal_expression,
247         conversion.CPSSymbolExpression: transform_symbol_expression,
248         conversion.CPSVariableExpression: transform_variable_expression,
249     }[type(expression)](accumulators, expression)
250
251 def transform_symbol_assignment_statement(accumulators, assignment_statement):
252     # TODO Check that target is not a builtin
253     try:
254         symbol_list_index = accumulators.symbol_list.index(assignment_statement.target)
255     except ValueError:
256         symbol_list_index = len(accumulators.symbol_list)
257         accumulators.symbol_list.append(assignment_statement.target)
258
259     return CSymbolAssignmentStatement(
260         target=assignment_statement.target,
261         target_symbol_list_index=symbol_list_index,
262         expression=transform_expression(
263             accumulators,
264             assignment_statement.expression,
265         ),
266     )
267
268 def transform_function_call_expression(accumulators, function_call):
269     # TODO Use the symbol from SYMBOL LIST
270     return CFunctionCallExpression(
271         metadata=function_call.metadata,
272         function_expression=transform_expression(accumulators, function_call.function_expression),
273         argument_count=function_call.argument_count,
274     )
275
276 def transform_expression_statement(accumulators, statement):
277     return CExpressionStatement(
278         expression=transform_expression(accumulators, statement.expression),
279     )
280
281 def transform_if_else_expression(accumulators, statement):
282     return CIfElseExpression(
283         condition_expression=transform_expression(accumulators, statement.condition_expression),
284         if_statement_list=tuple(transform_statement(accumulators, s) for s in statement.if_statement_list),
285         else_statement_list=tuple(transform_statement(accumulators, s) for s in statement.else_statement_list),
286     )
287
288 def transform_array_variable_initialization_statement(accumulators, statement):
289     return CArrayVariableInitializationStatement(
290         variable=statement.variable,
291         items=tuple(transform_expression(accumulators, i) for i in statement.items),
292     )
293
294 def transform_symbol_array_variable_initialization_statement(accumulators, statement):
295     symbol_list_indices = []
296
297     for symbol in statement.symbol_list:
298         try:
299             symbol_list_index = accumulators.symbol_list.index(symbol)
300         except ValueError:
301             symbol_list_index = len(accumulators.symbol_list)
302             accumulators.symbol_list.append(symbol)
303
304         symbol_list_indices.append(symbol_list_index)
305
306     return CSymbolArrayVariableInitializationStatement(
307         variable=statement.variable,
308         symbol_list=statement.symbol_list,
309         symbol_list_indices=tuple(symbol_list_indices),
310     )
311
312 def transform_variable_initialization_statement(accumulators, statement):
313     return CVariableInitializationStatement(
314         variable=statement.variable,
315         expression=transform_expression(accumulators, statement.expression),
316     )
317
318 def transform_push_statement(accumulators, statement):
319     return CPushStatement(expression=transform_expression(accumulators, statement.expression))
320
321 def transform_statement(accumulators, statement):
322     return {
323         conversion.CPSArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
324         conversion.CPSAssignmentStatement: transform_symbol_assignment_statement,
325         conversion.CPSExpressionStatement: transform_expression_statement,
326         conversion.CPSListAppendStatement: transform_list_append_statement,
327         conversion.CPSPushStatement: transform_push_statement,
328         conversion.CPSSymbolArrayVariableInitializationStatement: transform_symbol_array_variable_initialization_statement,
329         conversion.CPSVariableInitializationStatement: transform_variable_initialization_statement,
330     }[type(statement)](accumulators, statement)
331
332
333 Accumulators = collections.namedtuple(
334     'Accumulators',
335     [
336         'builtin_set',
337         'function_definition_list',
338         'function_name_iterators',
339         'operator_set',
340         'symbol_list',
341         'string_literal_list',
342     ],
343 )
344
345 def transform(program):
346     accumulators = Accumulators(
347         builtin_set=set(),
348         function_definition_list=[],
349         function_name_iterators={},
350         operator_set=set(),
351         symbol_list=[],
352         string_literal_list=[],
353     )
354
355     statement_list = [
356         transform_statement(accumulators, statement) for statement in program.statement_list
357     ]
358
359     standard_library_set = set()
360     for builtin in accumulators.builtin_set:
361         for standard_library in BUILTINS[builtin]:
362             standard_library_set.add(standard_library)
363
364     return CProgram(
365         builtin_set=accumulators.builtin_set,
366         function_definition_list=accumulators.function_definition_list,
367         operator_declarations=tuple(sorted(accumulators.operator_set)),
368         statements=statement_list,
369         standard_libraries=standard_library_set,
370         string_literal_list=accumulators.string_literal_list,
371         symbol_list=accumulators.symbol_list,
372     )
373
374
375 if __name__ == '__main__':
376     import unittest
377
378     unittest.main()