5 NormalVariableExpression = collections.namedtuple(
6 'NormalVariableExpression',
12 NormalNegationExpression = collections.namedtuple(
13 'NormalNegationExpression',
15 'internal_expression',
19 NormalInfixExpression = collections.namedtuple(
20 'NormalInfixExpression',
29 NormalFunctionCallExpression = collections.namedtuple(
30 'NormalFunctionCallExpression',
38 NormalArrayVariableInitializationStatement = collections.namedtuple(
39 'NormalArrayVariableInitializationStatement',
46 NormalVariableInitializationStatement = collections.namedtuple(
47 'NormalVariableInitializationStatement',
54 NormalVariableReassignmentStatement = collections.namedtuple(
55 'NormalVariableReassignmentStatement',
62 NormalExpressionStatement = collections.namedtuple(
63 'NormalExpressionStatement',
69 NormalIfElseStatement = collections.namedtuple(
70 'NormalIfElseStatement',
72 'condition_expression',
78 NormalProgram = collections.namedtuple(
85 def fake_normalization(counter, thing):
86 return (counter, (), thing)
88 def normalize_function_call_expression(counter, expression):
89 assert isinstance(expression, parsing.FurFunctionCallExpression)
94 for argument in expression.arguments:
95 counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
97 for s in argument_prestatements:
98 prestatements.append(s)
100 variable = '${}'.format(counter)
101 prestatements.append(NormalVariableInitializationStatement(
103 expression=normalized_argument,
105 arguments.append(NormalVariableExpression(
110 arguments_variable = '${}'.format(counter)
113 prestatements.append(NormalArrayVariableInitializationStatement(
114 variable=arguments_variable,
115 items=tuple(arguments),
120 tuple(prestatements),
121 NormalFunctionCallExpression(
122 function=expression.function, # TODO Normalize the function
123 argument_count=len(arguments),
124 argument_items=NormalVariableExpression(variable=arguments_variable),
128 def normalize_basic_infix_operation(counter, expression):
129 counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
130 counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
132 left_variable = '${}'.format(counter)
134 right_variable = '${}'.format(counter)
137 root_prestatements = (
138 NormalVariableInitializationStatement(
139 variable=left_variable,
140 expression=left_expression,
142 NormalVariableInitializationStatement(
143 variable=right_variable,
144 expression=right_expression,
150 left_prestatements + right_prestatements + root_prestatements,
151 NormalInfixExpression(
152 order=expression.order, # TODO Do we need this?
153 operator=expression.operator,
154 left=NormalVariableExpression(variable=left_variable),
155 right=NormalVariableExpression(variable=right_variable),
159 def normalize_comparison_expression(counter, expression):
162 while isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level':
163 stack.append((expression.operator, expression.order, expression.right))
164 expression = expression.left
166 counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
167 counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
169 left_variable = '${}'.format(counter)
171 right_variable = '${}'.format(counter)
174 root_prestatements = (
175 NormalVariableInitializationStatement(
176 variable=left_variable,
177 expression=left_expression,
179 NormalVariableInitializationStatement(
180 variable=right_variable,
181 expression=right_expression,
185 counter, result_prestatements, result_expression = (
187 left_prestatements + right_prestatements + root_prestatements,
188 # TODO Implement short-circuiting
189 NormalInfixExpression(
190 order=expression.order, # TODO Do we need this?
191 operator=expression.operator,
192 left=NormalVariableExpression(variable=left_variable),
193 right=NormalVariableExpression(variable=right_variable),
197 while len(stack) > 0:
198 right_operator, right_order, right_expression = stack.pop()
199 and_right_expression = parsing.FurInfixExpression(
200 operator=right_operator,
202 left=NormalVariableExpression(variable=right_variable),
203 right=right_expression,
206 and_expression = parsing.FurInfixExpression(
209 left=result_expression,
210 right=and_right_expression,
213 counter, and_prestatements, result_expression = normalize_boolean_expression(
218 result_prestatements = result_prestatements + and_prestatements
220 return (counter, result_prestatements, result_expression)
222 def normalize_boolean_expression(counter, expression):
223 counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
224 counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
226 result_variable = '${}'.format(counter)
227 if_else_prestatment = NormalVariableInitializationStatement(variable=result_variable, expression=left_expression)
230 condition_expression=NormalVariableExpression(variable=result_variable)
231 short_circuited_statements = right_prestatements + (NormalVariableReassignmentStatement(variable=result_variable, expression=right_expression),)
233 if expression.operator == 'and':
234 if_else_statement = NormalIfElseStatement(
235 condition_expression=condition_expression,
236 if_statements=short_circuited_statements,
240 elif expression.operator == 'or':
241 if_else_statement = NormalIfElseStatement(
242 condition_expression=condition_expression,
244 else_statements=short_circuited_statements,
248 raise Exception('Unable to handle operator "{}"'.format(expression.operator))
252 left_prestatements + (if_else_prestatment, if_else_statement),
253 NormalVariableExpression(variable=result_variable),
257 def normalize_infix_expression(counter, expression):
259 'multiplication_level': normalize_basic_infix_operation,
260 'addition_level': normalize_basic_infix_operation,
261 'comparison_level': normalize_comparison_expression,
262 'and_level': normalize_boolean_expression,
263 'or_level': normalize_boolean_expression,
264 }[expression.order](counter, expression)
266 def normalize_negation_expression(counter, expression):
267 counter, prestatements, internal_expression = normalize_expression(counter, expression.value)
269 internal_variable = '${}'.format(counter)
274 prestatements + (NormalVariableInitializationStatement(variable=internal_variable, expression=internal_expression),),
275 NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)),
278 def normalize_parenthesized_expression(counter, expression):
279 return normalize_expression(counter, expression.internal)
281 def normalize_expression(counter, expression):
283 NormalInfixExpression: fake_normalization,
284 NormalVariableExpression: fake_normalization,
285 parsing.FurFunctionCallExpression: normalize_function_call_expression,
286 parsing.FurInfixExpression: normalize_infix_expression,
287 parsing.FurIntegerLiteralExpression: fake_normalization,
288 parsing.FurNegationExpression: normalize_negation_expression,
289 parsing.FurParenthesizedExpression: normalize_parenthesized_expression,
290 parsing.FurStringLiteralExpression: fake_normalization,
291 parsing.FurSymbolExpression: fake_normalization,
292 }[type(expression)](counter, expression)
294 def normalize_expression_statement(counter, statement):
295 counter, prestatements, normalized = {
296 parsing.FurFunctionCallExpression: normalize_function_call_expression,
297 }[type(statement.expression)](counter, statement.expression)
302 NormalExpressionStatement(expression=normalized),
305 def normalize_statement(counter, statement):
307 parsing.FurExpressionStatement: normalize_expression_statement,
308 parsing.FurAssignmentStatement: fake_normalization,
309 }[type(statement)](counter, statement)
311 def normalize(program):
315 for statement in program.statement_list:
316 counter, prestatements, normalized = normalize_statement(counter, statement)
317 for s in prestatements:
318 statement_list.append(s)
319 statement_list.append(normalized)
321 return NormalProgram(
322 statement_list=statement_list,