Add a negation operator
[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 CNegationExpression = collections.namedtuple(
20     'CNegationExpression',
21     [
22         'value',
23     ],
24 )
25
26 CAdditionExpression = collections.namedtuple(
27     'CAdditionExpression',
28     [
29         'left',
30         'right',
31     ],
32 )
33
34 CSubtractionExpression = collections.namedtuple(
35     'CSubtractionExpression',
36     [
37         'left',
38         'right',
39     ],
40 )
41
42 CMultiplicationExpression = collections.namedtuple(
43     'CMultiplicationExpression',
44     [
45         'left',
46         'right',
47     ],
48 )
49
50 CIntegerDivisionExpression = collections.namedtuple(
51     'CIntegerDivisionExpression',
52     [
53         'left',
54         'right',
55     ],
56 )
57
58 CModularDivisionExpression = collections.namedtuple(
59     'CModularDivisionExpression',
60     [
61         'left',
62         'right',
63     ],
64 )
65
66 CFunctionCallExpression = collections.namedtuple(
67     'CFunctionCallExpression',
68     [
69         'name',
70         'arguments',
71     ],
72 )
73
74 CProgram = collections.namedtuple(
75     'CProgram',
76     [
77         'builtins',
78         'statements',
79         'standard_libraries',
80     ],
81 )
82
83 BUILTINS = {
84     'pow':      ['math.h'],
85     'print':    ['stdio.h'],
86 }
87
88 def transform_expression(builtin_dependencies, expression):
89     if isinstance(expression, parsing.FurNegationExpression):
90         return transform_negation_expression(builtin_dependencies, expression)
91
92     if isinstance(expression, parsing.FurFunctionCallExpression):
93         return transform_function_call_expression(builtin_dependencies, expression)
94
95     LITERAL_TYPE_MAPPING = {
96         parsing.FurIntegerLiteralExpression: CIntegerLiteral,
97         parsing.FurStringLiteralExpression: CStringLiteral,
98     }
99
100     if type(expression) in LITERAL_TYPE_MAPPING:
101         return LITERAL_TYPE_MAPPING[type(expression)](value=expression.value)
102
103     INFIX_TYPE_MAPPING = {
104         parsing.FurAdditionExpression: CAdditionExpression,
105         parsing.FurSubtractionExpression: CSubtractionExpression,
106         parsing.FurMultiplicationExpression: CMultiplicationExpression,
107         parsing.FurIntegerDivisionExpression: CIntegerDivisionExpression,
108         parsing.FurModularDivisionExpression: CModularDivisionExpression,
109     }
110
111     return INFIX_TYPE_MAPPING[type(expression)](
112         left=transform_expression(builtin_dependencies, expression.left),
113         right=transform_expression(builtin_dependencies, expression.right),
114     )
115
116 def transform_negation_expression(builtin_dependencies, negation_expression):
117     return CNegationExpression(value=transform_expression(builtin_dependencies, negation_expression.value))
118
119 def transform_function_call_expression(builtin_dependencies, function_call):
120     if function_call.name in BUILTINS.keys():
121         builtin_dependencies.add(function_call.name)
122
123         return CFunctionCallExpression(
124             name='builtin$' + function_call.name,
125             arguments=tuple(transform_expression(builtin_dependencies, arg) for arg in function_call.arguments),
126         )
127
128     raise Exception()
129
130 def transform(program):
131     builtins = set()
132
133     c_statements = [
134         transform_function_call_expression(builtins, statement) for statement in program.statement_list
135     ]
136
137     standard_libraries = set()
138     for builtin in builtins:
139         for standard_library in BUILTINS[builtin]:
140             standard_libraries.add(standard_library)
141
142     return CProgram(
143         builtins=builtins,
144         statements=c_statements,
145         standard_libraries=standard_libraries,
146     )
147
148
149 if __name__ == '__main__':
150     import unittest
151
152     unittest.main()