Ignore symbol folders
[fur] / transformation.py
1 import collections
2
3 import normalization
4 import parsing
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 CConstantExpression = collections.namedtuple(
22     'CConstantExpression',
23     [
24         'value'
25     ],
26 )
27
28 CVariableExpression = collections.namedtuple(
29     'CVariableExpression',
30     [
31         'variable',
32     ],
33 )
34
35 CSymbolExpression = collections.namedtuple(
36     'CSymbolExpression',
37     [
38         'symbol',
39         'symbol_list_index',
40     ],
41 )
42
43 CNegationExpression = collections.namedtuple(
44     'CNegationExpression',
45     [
46         'value',
47     ],
48 )
49
50 CFunctionCallForFurInfixOperator = collections.namedtuple(
51     'CFunctionCallForFurInfixOperator',
52     [
53         'name',
54         'left',
55         'right',
56     ],
57 )
58
59 CFunctionCallExpression = collections.namedtuple(
60     'CFunctionCallExpression',
61     [
62         'name',
63         'argument_count',
64         'argument_items',
65     ],
66 )
67
68 CSymbolAssignmentStatement = collections.namedtuple(
69     'CSymbolAssignmentStatement',
70     [
71         'target',
72         'target_symbol_list_index',
73         'expression',
74     ],
75 )
76
77 CArrayVariableInitializationStatement = collections.namedtuple(
78     'CArrayVariableInitializationStatement',
79     [
80         'variable',
81         'items',
82     ],
83 )
84
85 CVariableInitializationStatement = collections.namedtuple(
86     'CVariableInitializationStatement',
87     [
88         'variable',
89         'expression',
90     ],
91 )
92
93 CVariableReassignmentStatement = collections.namedtuple(
94     'CVariableReassignmentStatement',
95     [
96         'variable',
97         'expression',
98     ],
99 )
100
101 CExpressionStatement = collections.namedtuple(
102     'CExpressionStatement',
103     [
104         'expression',
105     ],
106 )
107
108 CIfElseStatement = collections.namedtuple(
109     'CIfElseStatement',
110     [
111         'condition_expression',
112         'if_statements',
113         'else_statements',
114     ],
115 )
116
117 CFunctionDeclaration = collections.namedtuple(
118     'CFunctionDeclaration',
119     [
120         'name',
121     ],
122 )
123
124 CFunctionDefinition = collections.namedtuple(
125     'CFunctionDefinition',
126     [
127         'name',
128         'statement_list',
129     ],
130 )
131
132 CProgram = collections.namedtuple(
133     'CProgram',
134     [
135         'builtin_set',
136         'function_definition_list',
137         'operator_declarations',
138         'statements',
139         'standard_libraries',
140         'string_literal_list',
141         'symbol_list',
142     ],
143 )
144
145 BUILTINS = {
146     'false':    [],
147     'pow':      ['math.h'],
148     'print':    ['stdio.h'],
149     'true':     [],
150 }
151
152 def transform_variable_expression(accumulators, expression):
153     return CVariableExpression(variable=expression.variable)
154
155 def transform_string_literal(accumulators, expression):
156     value = expression.value
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.value in ['true', 'false']:
168         return CConstantExpression(value=expression.value)
169
170     if expression.value not in accumulators.symbol_list:
171         symbol_list.append(expression.value)
172
173     return CSymbolExpression(
174         symbol=expression.value,
175         symbol_list_index=accumulators.symbol_list.index(expression.value),
176     )
177
178 CInfixDeclaration = collections.namedtuple(
179     'CInfixDeclaration',
180     [
181         'name',
182         'in_type',
183         'out_type',
184         'operator',
185     ],
186 )
187
188 INFIX_OPERATOR_TO_DECLARATION = {
189     '+':    CInfixDeclaration(name='add', in_type='integer', out_type='integer', operator='+'),
190     '-':    CInfixDeclaration(name='subtract', in_type='integer', out_type='integer', operator='-'),
191     '*':    CInfixDeclaration(name='multiply', in_type='integer', out_type='integer', operator='*'),
192     '//':   CInfixDeclaration(name='integerDivide', in_type='integer', out_type='integer', operator='/'),
193     '%':    CInfixDeclaration(name='modularDivide', in_type='integer', out_type='integer', operator='%'),
194     'and':  CInfixDeclaration(name='and', in_type='boolean', out_type='boolean', operator='&&'),
195     'or':   CInfixDeclaration(name='or', in_type='boolean', out_type='boolean', operator='||'),
196     '==':   CInfixDeclaration(name='equals', in_type='integer', out_type='boolean', operator='=='),
197     '!=':   CInfixDeclaration(name='notEquals', in_type='integer', out_type='boolean', operator='!='),
198     '<=':   CInfixDeclaration(name='lessThanOrEqual', in_type='integer', out_type='boolean', operator='<='),
199     '>=':   CInfixDeclaration(name='greaterThanOrEqual', in_type='integer', out_type='boolean', operator='>='),
200     '<':    CInfixDeclaration(name='lessThan', in_type='integer', out_type='boolean', operator='<'),
201     '>':    CInfixDeclaration(name='greaterThan', in_type='integer', out_type='boolean', operator='>'),
202 }
203
204 def transform_comparison_level_expression(accumulators, expression):
205     accumulators.operator_set.add(INFIX_OPERATOR_TO_DECLARATION[expression.operator])
206
207     # Transform expressions like 1 < 2 < 3 into expressions like 1 < 2 && 2 < 3
208     if isinstance(expression.left, parsing.FurInfixExpression) and expression.left.order == 'comparison_level':
209         left = transform_comparison_level_expression(
210             accumulators,
211             expression.left
212         )
213
214         middle = left.right
215
216         right = transform_expression(
217             accumulators,
218             expression.right,
219         )
220
221         # TODO Don't evaluate the middle expression twice
222         return CFunctionCallForFurInfixOperator(
223             name='and',
224             left=left,
225             right=CFunctionCallForFurInfixOperator(
226                 name=INFIX_OPERATOR_TO_DECLARATION[expression.operator].name,
227                 left=middle,
228                 right=right,
229             ),
230         )
231
232     return CFunctionCallForFurInfixOperator(
233         name=INFIX_OPERATOR_TO_DECLARATION[expression.operator].name,
234         left=transform_expression(accumulators, expression.left),
235         right=transform_expression(accumulators, expression.right),
236     )
237
238 def transform_infix_expression(accumulators, expression):
239     if expression.order == 'comparison_level':
240         return transform_comparison_level_expression(accumulators, expression)
241
242     accumulators.operator_set.add(INFIX_OPERATOR_TO_DECLARATION[expression.operator])
243
244     return CFunctionCallForFurInfixOperator(
245         name=INFIX_OPERATOR_TO_DECLARATION[expression.operator].name,
246         left=transform_expression(accumulators, expression.left),
247         right=transform_expression(accumulators, expression.right),
248     )
249
250 def transform_integer_literal_expression(accumulators, expression):
251     return CIntegerLiteral(value=expression.value)
252
253 def transform_parenthesized_expression(accumulators, expression):
254     # Parentheses can be removed because everything in the C output is explicitly parenthesized
255     return transform_expression(accumulators, expression.internal)
256
257 def transform_negation_expression(accumulators, expression):
258     return CNegationExpression(
259         value=transform_expression(accumulators, expression.internal_expression),
260     )
261
262 def transform_expression(accumulators, expression):
263     # TODO Clean up handlers for parsing expressions
264     return {
265         parsing.FurFunctionCallExpression: transform_function_call_expression,
266         parsing.FurInfixExpression: transform_infix_expression,
267         parsing.FurIntegerLiteralExpression: transform_integer_literal_expression,
268         parsing.FurNegationExpression: transform_negation_expression,
269         parsing.FurParenthesizedExpression: transform_parenthesized_expression,
270         parsing.FurStringLiteralExpression: transform_string_literal,
271         parsing.FurSymbolExpression: transform_symbol_expression,
272         normalization.NormalFunctionCallExpression: transform_function_call_expression,
273         normalization.NormalInfixExpression: transform_infix_expression,
274         normalization.NormalNegationExpression: transform_negation_expression,
275         normalization.NormalVariableExpression: transform_variable_expression,
276     }[type(expression)](accumulators, expression)
277
278 def transform_symbol_assignment_statement(accumulators, assignment_statement):
279     # TODO Check that target is not a builtin
280     if assignment_statement.target not in accumulators.symbol_list:
281         accumulators.symbol_list.append(assignment_statement.target)
282
283     return CSymbolAssignmentStatement(
284         target=assignment_statement.target,
285         target_symbol_list_index=accumulators.symbol_list.index(assignment_statement.target),
286         expression=transform_expression(
287             accumulators,
288             assignment_statement.expression,
289         ),
290     )
291
292 def transform_function_call_expression(accumulators, function_call):
293     if function_call.function.value in BUILTINS.keys():
294         # TODO Check that the builtin is actually callable
295         accumulators.builtin_set.add(function_call.function.value)
296
297     # TODO Use the symbol from SYMBOL LIST
298     return CFunctionCallExpression(
299         name=function_call.function.value,
300         argument_count=function_call.argument_count,
301         argument_items=transform_expression(accumulators, function_call.argument_items),
302     )
303
304 def transform_expression_statement(accumulators, statement):
305     # TODO At some point we can verify that all expression types are supported and just call transform_expression
306     expression = {
307         parsing.FurFunctionCallExpression: transform_function_call_expression,
308         parsing.FurInfixExpression: transform_expression,
309         parsing.FurIntegerLiteralExpression: transform_expression,
310         parsing.FurSymbolExpression: transform_expression,
311         normalization.NormalFunctionCallExpression: transform_function_call_expression,
312         normalization.NormalVariableExpression: transform_expression,
313     }[type(statement.expression)](accumulators, statement.expression)
314
315     return CExpressionStatement(
316         expression=expression,
317     )
318
319 def transform_if_else_statement(accumulators, statement):
320     return CIfElseStatement(
321         condition_expression=transform_expression(accumulators, statement.condition_expression),
322         if_statements=tuple(transform_statement(accumulators, s) for s in statement.if_statements),
323         else_statements=tuple(transform_statement(accumulators, s) for s in statement.else_statements),
324     )
325
326 def transform_array_variable_initialization_statement(accumulators, statement):
327     return CArrayVariableInitializationStatement(
328         variable=statement.variable,
329         items=tuple(transform_expression(accumulators, i) for i in statement.items),
330     )
331
332 def transform_variable_initialization_statement(accumulators, statement):
333     return CVariableInitializationStatement(
334         variable=statement.variable,
335         expression=transform_expression(accumulators, statement.expression),
336     )
337
338 def transform_variable_reassignment_statement(accumulators, statement):
339     return CVariableReassignmentStatement(
340         variable=statement.variable,
341         expression=transform_expression(accumulators, statement.expression),
342     )
343
344 def transform_function_definition_statement(accumulators, statement):
345     # TODO Allow defining the same function in different contexts
346     if any(fd.name == statement.name for fd in accumulators.function_definition_list):
347         raise Exception('A function with name "{}" already exists'.format(statement.name))
348
349     accumulators.function_definition_list.append(CFunctionDefinition(
350         name=statement.name,
351         statement_list=tuple(transform_statement(accumulators, s) for s in statement.statement_list)
352     ))
353
354     return CFunctionDeclaration(name=statement.name)
355
356 def transform_statement(accumulators, statement):
357     return {
358         parsing.FurAssignmentStatement: transform_symbol_assignment_statement,
359         parsing.FurExpressionStatement: transform_expression_statement,
360         normalization.NormalArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
361         normalization.NormalExpressionStatement: transform_expression_statement,
362         normalization.NormalFunctionDefinitionStatement: transform_function_definition_statement,
363         normalization.NormalIfElseStatement: transform_if_else_statement,
364         normalization.NormalVariableInitializationStatement: transform_variable_initialization_statement,
365         normalization.NormalVariableReassignmentStatement: transform_variable_reassignment_statement,
366     }[type(statement)](accumulators, statement)
367
368
369 Accumulators = collections.namedtuple(
370     'Accumulators',
371     [
372         'builtin_set',
373         'function_definition_list',
374         'operator_set',
375         'symbol_list',
376         'string_literal_list',
377     ],
378 )
379
380 def transform(program):
381     accumulators = Accumulators(
382         builtin_set=set(),
383         function_definition_list=[],
384         operator_set=set(),
385         symbol_list=[],
386         string_literal_list=[],
387     )
388
389     statement_list = [
390         transform_statement(accumulators, statement) for statement in program.statement_list
391     ]
392
393     standard_library_set = set()
394     for builtin in accumulators.builtin_set:
395         for standard_library in BUILTINS[builtin]:
396             standard_library_set.add(standard_library)
397
398     return CProgram(
399         builtin_set=accumulators.builtin_set,
400         function_definition_list=accumulators.function_definition_list,
401         operator_declarations=tuple(sorted(accumulators.operator_set)),
402         statements=statement_list,
403         standard_libraries=standard_library_set,
404         string_literal_list=accumulators.string_literal_list,
405         symbol_list=accumulators.symbol_list,
406     )
407
408
409 if __name__ == '__main__':
410     import unittest
411
412     unittest.main()