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