Desugar function definitions to assignments to lambda
[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         'argument_name_list',
126         'statement_list',
127     ],
128 )
129
130 CProgram = collections.namedtuple(
131     'CProgram',
132     [
133         'builtin_set',
134         'function_definition_list',
135         'operator_declarations',
136         'statements',
137         'standard_libraries',
138         'string_literal_list',
139         'symbol_list',
140     ],
141 )
142
143 BUILTINS = {
144     'concatenate':      [],
145     'false':            [],
146     'pow':              ['math.h'],
147     'print':            ['stdio.h'],
148     'true':             [],
149 }
150
151 def transform_variable_expression(accumulators, expression):
152     assert isinstance(expression, conversion.CPSVariableExpression)
153     return CVariableExpression(variable=expression.variable)
154
155 def transform_string_literal_expression(accumulators, expression):
156     value = expression.string
157
158     try:
159         index = accumulators.string_literal_list.index(value)
160     except ValueError:
161         index = len(accumulators.string_literal_list)
162         accumulators.string_literal_list.append(value)
163
164     return CStringLiteral(index=index, value=value)
165
166 def transform_symbol_expression(accumulators, expression):
167     if expression.symbol in BUILTINS:
168         accumulators.builtin_set.add(expression.symbol)
169
170     try:
171         symbol_list_index = accumulators.symbol_list.index(expression.symbol)
172     except ValueError:
173         symbol_list_index = len(accumulators.symbol_list)
174         accumulators.symbol_list.append(expression.symbol)
175
176     return CSymbolExpression(
177         symbol=expression.symbol,
178         symbol_list_index=symbol_list_index,
179     )
180
181 def transform_integer_literal_expression(accumulators, expression):
182     return CIntegerLiteral(value=expression.integer)
183
184 CListConstructExpression = collections.namedtuple(
185     'CListConstructExpression',
186     (
187         'allocate',
188     ),
189 )
190
191 CLambdaExpression = collections.namedtuple(
192     'CLambdaExpression',
193     (
194         'name',
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_lambda_expression(accumulators, expression):
214     # TODO This function feels hacky
215     if len(accumulators.lambda_number_list) == 0:
216         accumulators.lambda_number_list.append(0)
217     else:
218         accumulators.lambda_number_list.append(accumulators.lambda_number_list[-1] + 1)
219
220     if expression.name is None:
221         name = '__lambda_{}'.format(accumulators.lambda_number_list[-1])
222     else:
223         name = expression.name
224
225     accumulators.function_definition_list.append(CFunctionDefinition(
226         name=name,
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(name=name)
232
233
234 def transform_list_construct_expression(accumulators, expression):
235     return CListConstructExpression(allocate=expression.allocate)
236
237 def transform_list_append_statement(accumulators, expression):
238     return CListAppendStatement(
239         list_expression=transform_expression(accumulators, expression.list_expression),
240         item_expression=transform_expression(accumulators, expression.item_expression),
241     )
242
243 def transform_expression(accumulators, expression):
244     return {
245         conversion.CPSFunctionCallExpression: transform_function_call_expression,
246         conversion.CPSIntegerLiteralExpression: transform_integer_literal_expression,
247         conversion.CPSLambdaExpression: transform_lambda_expression,
248         conversion.CPSListConstructExpression: transform_list_construct_expression,
249         conversion.CPSStructureLiteralExpression: transform_structure_literal_expression,
250         conversion.CPSStringLiteralExpression: transform_string_literal_expression,
251         conversion.CPSSymbolExpression: transform_symbol_expression,
252         conversion.CPSVariableExpression: transform_variable_expression,
253     }[type(expression)](accumulators, expression)
254
255 def transform_symbol_assignment_statement(accumulators, assignment_statement):
256     # TODO Check that target is not a builtin
257     try:
258         symbol_list_index = accumulators.symbol_list.index(assignment_statement.target)
259     except ValueError:
260         symbol_list_index = len(accumulators.symbol_list)
261         accumulators.symbol_list.append(assignment_statement.target)
262
263     return CSymbolAssignmentStatement(
264         target=assignment_statement.target,
265         target_symbol_list_index=symbol_list_index,
266         expression=transform_expression(
267             accumulators,
268             assignment_statement.expression,
269         ),
270     )
271
272 def transform_function_call_expression(accumulators, function_call):
273     # TODO Use the symbol from SYMBOL LIST
274     return CFunctionCallExpression(
275         metadata=function_call.metadata,
276         function_expression=transform_expression(accumulators, function_call.function_expression),
277         argument_count=function_call.argument_count,
278     )
279
280 def transform_expression_statement(accumulators, statement):
281     return CExpressionStatement(
282         expression=transform_expression(accumulators, statement.expression),
283     )
284
285 def transform_if_else_statement(accumulators, statement):
286     return CIfElseStatement(
287         condition_expression=transform_expression(accumulators, statement.condition_expression),
288         if_statement_list=tuple(transform_statement(accumulators, s) for s in statement.if_statement_list),
289         else_statement_list=tuple(transform_statement(accumulators, s) for s in statement.else_statement_list),
290     )
291
292 def transform_array_variable_initialization_statement(accumulators, statement):
293     return CArrayVariableInitializationStatement(
294         variable=statement.variable,
295         items=tuple(transform_expression(accumulators, i) for i in statement.items),
296     )
297
298 def transform_symbol_array_variable_initialization_statement(accumulators, statement):
299     symbol_list_indices = []
300
301     for symbol in statement.symbol_list:
302         try:
303             symbol_list_index = accumulators.symbol_list.index(symbol)
304         except ValueError:
305             symbol_list_index = len(accumulators.symbol_list)
306             accumulators.symbol_list.append(symbol)
307
308         symbol_list_indices.append(symbol_list_index)
309
310     return CSymbolArrayVariableInitializationStatement(
311         variable=statement.variable,
312         symbol_list=statement.symbol_list,
313         symbol_list_indices=tuple(symbol_list_indices),
314     )
315
316 def transform_variable_initialization_statement(accumulators, statement):
317     return CVariableInitializationStatement(
318         variable=statement.variable,
319         expression=transform_expression(accumulators, statement.expression),
320     )
321
322 def transform_variable_reassignment_statement(accumulators, statement):
323     return CVariableReassignmentStatement(
324         variable=statement.variable,
325         expression=transform_expression(accumulators, statement.expression),
326     )
327
328 def transform_push_statement(accumulators, statement):
329     return CPushStatement(expression=transform_expression(accumulators, statement.expression))
330
331 def transform_statement(accumulators, statement):
332     return {
333         conversion.CPSArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
334         conversion.CPSAssignmentStatement: transform_symbol_assignment_statement,
335         conversion.CPSExpressionStatement: transform_expression_statement,
336         conversion.CPSIfElseStatement: transform_if_else_statement,
337         conversion.CPSListAppendStatement: transform_list_append_statement,
338         conversion.CPSPushStatement: transform_push_statement,
339         conversion.CPSSymbolArrayVariableInitializationStatement: transform_symbol_array_variable_initialization_statement,
340         conversion.CPSVariableInitializationStatement: transform_variable_initialization_statement,
341         conversion.CPSVariableReassignmentStatement: transform_variable_reassignment_statement,
342     }[type(statement)](accumulators, statement)
343
344
345 Accumulators = collections.namedtuple(
346     'Accumulators',
347     [
348         'builtin_set',
349         'function_definition_list',
350         'lambda_number_list',
351         'operator_set',
352         'symbol_list',
353         'string_literal_list',
354     ],
355 )
356
357 def transform(program):
358     accumulators = Accumulators(
359         builtin_set=set(),
360         function_definition_list=[],
361         lambda_number_list=[],
362         operator_set=set(),
363         symbol_list=[],
364         string_literal_list=[],
365     )
366
367     statement_list = [
368         transform_statement(accumulators, statement) for statement in program.statement_list
369     ]
370
371     standard_library_set = set()
372     for builtin in accumulators.builtin_set:
373         for standard_library in BUILTINS[builtin]:
374             standard_library_set.add(standard_library)
375
376     return CProgram(
377         builtin_set=accumulators.builtin_set,
378         function_definition_list=accumulators.function_definition_list,
379         operator_declarations=tuple(sorted(accumulators.operator_set)),
380         statements=statement_list,
381         standard_libraries=standard_library_set,
382         string_literal_list=accumulators.string_literal_list,
383         symbol_list=accumulators.symbol_list,
384     )
385
386
387 if __name__ == '__main__':
388     import unittest
389
390     unittest.main()