Normalize infix operators
[fur] / normalization.py
1 import collections
2
3 import parsing
4
5 NormalVariableExpression = collections.namedtuple(
6     'NormalVariableExpression',
7     [
8         'variable',
9     ],
10 )
11
12 NormalInfixExpression = collections.namedtuple(
13     'NormalInfixExpression',
14     [
15         'order',
16         'operator',
17         'left',
18         'right',
19     ],
20 )
21
22 NormalFunctionCallExpression = collections.namedtuple(
23     'NormalFunctionCallExpression',
24     [
25         'function',
26         'arguments',
27     ],
28 )
29
30 NormalVariableAssignmentStatement = collections.namedtuple(
31     'NormalVariableAssignmentStatement',
32     [
33         'variable',
34         'expression',
35     ],
36 )
37
38 NormalExpressionStatement = collections.namedtuple(
39     'NormalExpressionStatement',
40     [
41         'expression',
42     ],
43 )
44
45 NormalProgram = collections.namedtuple(
46     'NormalProgram',
47     [
48         'statement_list',
49     ],
50 )
51
52 def fake_normalization(counter, thing):
53     return (counter, (), thing)
54
55 def normalize_function_call_expression(counter, expression):
56     assert isinstance(expression, parsing.FurFunctionCallExpression)
57
58     prestatements = []
59     arguments = []
60
61     for argument in expression.arguments:
62         counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
63
64         for s in argument_prestatements:
65             prestatements.append(s)
66
67         variable = '${}'.format(counter)
68         prestatements.append(NormalVariableAssignmentStatement(
69             variable=variable,
70             expression=normalized_argument,
71         ))
72         arguments.append(NormalVariableExpression(
73             variable=variable,
74         ))
75         counter += 1
76
77     return (
78         counter,
79         tuple(prestatements),
80         NormalFunctionCallExpression(
81             expression.function, # TODO Normalize the function
82             arguments=tuple(arguments),
83         ),
84     )
85
86 def normalize_basic_infix_operation(counter, expression):
87     counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
88     counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
89
90     left_variable = '${}'.format(counter)
91     counter += 1
92     right_variable = '${}'.format(counter)
93     counter += 1
94
95     root_prestatements = (
96         NormalVariableAssignmentStatement(
97             variable=left_variable,
98             expression=left_expression,
99         ),
100         NormalVariableAssignmentStatement(
101             variable=right_variable,
102             expression=right_expression,
103         ),
104     )
105
106     return (
107         counter,
108         left_prestatements + right_prestatements + root_prestatements,
109         NormalInfixExpression(
110             order=expression.order, # TODO Do we need this?
111             operator=expression.operator,
112             left=NormalVariableExpression(variable=left_variable),
113             right=NormalVariableExpression(variable=right_variable),
114         ),
115     )
116
117 def normalize_infix_expression(counter, expression):
118     # TODO Unfake this normalization
119     return {
120         '+':    normalize_basic_infix_operation,
121         '-':    normalize_basic_infix_operation,
122         '*':    normalize_basic_infix_operation,
123         '//':   normalize_basic_infix_operation,
124         '%':    normalize_basic_infix_operation,
125         '==':   fake_normalization,
126         '<=':   fake_normalization,
127         '>=':   fake_normalization,
128         '!=':   fake_normalization,
129         '<':    fake_normalization,
130         '>':    fake_normalization,
131         'and':  fake_normalization,
132         'or':   fake_normalization,
133     }[expression.operator](counter, expression)
134
135 def normalize_expression(counter, expression):
136     return {
137         parsing.FurFunctionCallExpression: normalize_function_call_expression,
138         parsing.FurInfixExpression: normalize_infix_expression,
139         parsing.FurIntegerLiteralExpression: fake_normalization,
140         parsing.FurNegationExpression: fake_normalization, # TODO Don't fake this
141         parsing.FurParenthesizedExpression: fake_normalization, # TODO Don't fake this
142         parsing.FurStringLiteralExpression: fake_normalization,
143         parsing.FurSymbolExpression: fake_normalization,
144     }[type(expression)](counter, expression)
145
146 def normalize_expression_statement(counter, statement):
147     counter, prestatements, normalized = {
148         parsing.FurFunctionCallExpression: normalize_function_call_expression,
149     }[type(statement.expression)](counter, statement.expression)
150
151     return (
152         counter,
153         prestatements,
154         NormalExpressionStatement(expression=normalized),
155     )
156
157 def normalize_statement(counter, statement):
158     return {
159         parsing.FurExpressionStatement: normalize_expression_statement,
160         parsing.FurAssignmentStatement: fake_normalization,
161     }[type(statement)](counter, statement)
162
163 def normalize(program):
164     counter = 0
165     statement_list = []
166
167     for statement in program.statement_list:
168         counter, prestatements, normalized = normalize_statement(counter, statement)
169         for s in prestatements:
170             statement_list.append(s)
171         statement_list.append(normalized)
172
173     return NormalProgram(
174         statement_list=statement_list,
175     )