Add constant symbol list, which solves all the symbol allocation problems
[fur] / transformation.py
1 import collections
2
3 import parsing
4
5 CIntegerLiteral = collections.namedtuple(
6     'CIntegerLiteral',
7     [
8         'value',
9     ],
10 )
11
12 CStringLiteral = collections.namedtuple(
13     'CStringLiteral',
14     [
15         'value',
16     ],
17 )
18
19 CSymbolExpression = collections.namedtuple(
20     'CSymbolExpression',
21     [
22         'symbol',
23         'symbol_list_index',
24     ],
25 )
26
27 CNegationExpression = collections.namedtuple(
28     'CNegationExpression',
29     [
30         'value',
31     ],
32 )
33
34 CAdditionExpression = collections.namedtuple(
35     'CAdditionExpression',
36     [
37         'left',
38         'right',
39     ],
40 )
41
42 CSubtractionExpression = collections.namedtuple(
43     'CSubtractionExpression',
44     [
45         'left',
46         'right',
47     ],
48 )
49
50 CMultiplicationExpression = collections.namedtuple(
51     'CMultiplicationExpression',
52     [
53         'left',
54         'right',
55     ],
56 )
57
58 CIntegerDivisionExpression = collections.namedtuple(
59     'CIntegerDivisionExpression',
60     [
61         'left',
62         'right',
63     ],
64 )
65
66 CModularDivisionExpression = collections.namedtuple(
67     'CModularDivisionExpression',
68     [
69         'left',
70         'right',
71     ],
72 )
73
74 CFunctionCallExpression = collections.namedtuple(
75     'CFunctionCallExpression',
76     [
77         'name',
78         'arguments',
79     ],
80 )
81
82 CAssignmentStatement = collections.namedtuple(
83     'CAssignmentStatement',
84     [
85         'target',
86         'target_symbol_list_index',
87         'expression',
88     ],
89 )
90
91 CProgram = collections.namedtuple(
92     'CProgram',
93     [
94         'builtins',
95         'statements',
96         'standard_libraries',
97         'symbol_list',
98     ],
99 )
100
101 BUILTINS = {
102     'pow':      ['math.h'],
103     'print':    ['stdio.h'],
104 }
105
106 def transform_expression(builtin_dependencies, symbol_list, expression):
107     if isinstance(expression, parsing.FurNegationExpression):
108         return transform_negation_expression(builtin_dependencies, symbol_list, expression)
109
110     if isinstance(expression, parsing.FurFunctionCallExpression):
111         return transform_function_call_expression(builtin_dependencies, symbol_list, expression)
112
113     if isinstance(expression, parsing.FurSymbolExpression):
114         if expression.value not in symbol_list:
115             symbol_list.append(expression.value)
116
117         return CSymbolExpression(
118             symbol=expression.value,
119             symbol_list_index=symbol_list.index(expression.value),
120         )
121
122     LITERAL_TYPE_MAPPING = {
123         parsing.FurIntegerLiteralExpression: CIntegerLiteral,
124         parsing.FurStringLiteralExpression: CStringLiteral,
125     }
126
127     if type(expression) in LITERAL_TYPE_MAPPING:
128         return LITERAL_TYPE_MAPPING[type(expression)](value=expression.value)
129
130     INFIX_TYPE_MAPPING = {
131         parsing.FurAdditionExpression: CAdditionExpression,
132         parsing.FurSubtractionExpression: CSubtractionExpression,
133         parsing.FurMultiplicationExpression: CMultiplicationExpression,
134         parsing.FurIntegerDivisionExpression: CIntegerDivisionExpression,
135         parsing.FurModularDivisionExpression: CModularDivisionExpression,
136     }
137
138     return INFIX_TYPE_MAPPING[type(expression)](
139         left=transform_expression(builtin_dependencies, symbol_list, expression.left),
140         right=transform_expression(builtin_dependencies, symbol_list, expression.right),
141     )
142
143 def transform_assignment_statement(builtin_dependencies, symbol_list, assignment_statement):
144     # TODO Check that target is not a builtin
145     if assignment_statement.target not in symbol_list:
146         symbol_list.append(assignment_statement.target)
147
148     return CAssignmentStatement(
149         target=assignment_statement.target,
150         target_symbol_list_index=symbol_list.index(assignment_statement.target),
151         expression=transform_expression(
152             builtin_dependencies,
153             symbol_list,
154             assignment_statement.expression,
155         ),
156     )
157
158 def transform_negation_expression(builtin_dependencies, symbol_list, negation_expression):
159     return CNegationExpression(
160         value=transform_expression(builtin_dependencies, symbol_list, negation_expression.value),
161     )
162
163 def transform_function_call_expression(builtin_dependencies, symbol_list, function_call):
164     if function_call.function.value in BUILTINS.keys():
165         builtin_dependencies.add(function_call.function.value)
166
167         return CFunctionCallExpression(
168             name='builtin$' + function_call.function.value,
169             arguments=tuple(
170                 transform_expression(builtin_dependencies, symbol_list, arg)
171                 for arg in function_call.arguments
172             ),
173         )
174
175     raise Exception()
176
177 def transform_statement(builtin_dependencies, symbol_list, statement):
178     return {
179         parsing.FurAssignmentStatement: transform_assignment_statement,
180         parsing.FurFunctionCallExpression: transform_function_call_expression,
181     }[type(statement)](builtin_dependencies, symbol_list, statement)
182
183 def transform(program):
184     builtins = set()
185     symbol_list = []
186
187     c_statements = [
188         transform_statement(builtins, symbol_list, statement) for statement in program.statement_list
189     ]
190
191     standard_libraries = set()
192     for builtin in builtins:
193         for standard_library in BUILTINS[builtin]:
194             standard_libraries.add(standard_library)
195
196     return CProgram(
197         builtins=builtins,
198         statements=c_statements,
199         standard_libraries=standard_libraries,
200         symbol_list=symbol_list,
201     )
202
203
204 if __name__ == '__main__':
205     import unittest
206
207     unittest.main()