Start playing out the normalization of other infix operations
[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_comparison_expression(counter, expression):
118     # TODO Unfake this
119     return fake_normalization(counter, expression)
120
121 def normalize_boolean_expression(counter, expression):
122     # TODO Unfake this
123     return fake_normalization(counter, expression)
124
125 def normalize_infix_expression(counter, expression):
126     return {
127         'multiplication_level': normalize_basic_infix_operation,
128         'addition_level': normalize_basic_infix_operation,
129         'comparison_level': normalize_comparison_expression,
130         'and_level': normalize_boolean_expression,
131         'or_level': normalize_boolean_expression,
132     }[expression.order](counter, expression)
133
134 def normalize_expression(counter, expression):
135     return {
136         parsing.FurFunctionCallExpression: normalize_function_call_expression,
137         parsing.FurInfixExpression: normalize_infix_expression,
138         parsing.FurIntegerLiteralExpression: fake_normalization,
139         parsing.FurNegationExpression: fake_normalization, # TODO Don't fake this
140         parsing.FurParenthesizedExpression: fake_normalization, # TODO Don't fake this
141         parsing.FurStringLiteralExpression: fake_normalization,
142         parsing.FurSymbolExpression: fake_normalization,
143     }[type(expression)](counter, expression)
144
145 def normalize_expression_statement(counter, statement):
146     counter, prestatements, normalized = {
147         parsing.FurFunctionCallExpression: normalize_function_call_expression,
148     }[type(statement.expression)](counter, statement.expression)
149
150     return (
151         counter,
152         prestatements,
153         NormalExpressionStatement(expression=normalized),
154     )
155
156 def normalize_statement(counter, statement):
157     return {
158         parsing.FurExpressionStatement: normalize_expression_statement,
159         parsing.FurAssignmentStatement: fake_normalization,
160     }[type(statement)](counter, statement)
161
162 def normalize(program):
163     counter = 0
164     statement_list = []
165
166     for statement in program.statement_list:
167         counter, prestatements, normalized = normalize_statement(counter, statement)
168         for s in prestatements:
169             statement_list.append(s)
170         statement_list.append(normalized)
171
172     return NormalProgram(
173         statement_list=statement_list,
174     )