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