+ condition_expression=NormalVariableExpression(variable=result_variable)
+ short_circuited_statements = right_prestatements + (NormalVariableReassignmentStatement(variable=result_variable, expression=right_expression),)
+
+ if expression.operator == 'and':
+ if_else_statement = NormalIfElseStatement(
+ condition_expression=condition_expression,
+ if_statement_list=short_circuited_statements,
+ else_statement_list=(),
+ )
+
+ elif expression.operator == 'or':
+ if_else_statement = NormalIfElseStatement(
+ condition_expression=condition_expression,
+ if_statement_list=(),
+ else_statement_list=short_circuited_statements,
+ )
+
+ else:
+ raise Exception('Unable to handle operator "{}"'.format(expression.operator))
+
+ return (
+ counter,
+ left_prestatements + (if_else_prestatment, if_else_statement),
+ NormalVariableExpression(variable=result_variable),
+ )
+
+def normalize_dot_expression(counter, expression):
+ assert isinstance(expression.right, parsing.FurSymbolExpression)
+
+ counter, prestatements, left_expression = normalize_expression(counter, expression.left)
+
+ variable = '${}'.format(counter)
+
+ dot_expression_prestatement = NormalVariableInitializationStatement(
+ variable=variable,
+ expression=NormalDotExpression(
+ instance=left_expression,
+ field=expression.right.symbol,
+ ),
+ )
+
+ return (
+ counter + 1,
+ prestatements + (dot_expression_prestatement,),
+ NormalVariableExpression(variable=variable),
+ )
+
+def normalize_infix_expression(counter, expression):
+ return {
+ 'multiplication_level': normalize_basic_infix_operation,
+ 'addition_level': normalize_basic_infix_operation,
+ 'comparison_level': normalize_comparison_expression,
+ 'dot_level': normalize_dot_expression,
+ 'and_level': normalize_boolean_expression,
+ 'or_level': normalize_boolean_expression,
+ }[expression.order](counter, expression)
+
+def normalize_if_expression(counter, expression):
+ counter, condition_prestatements, condition_expression = normalize_expression(
+ counter,
+ expression.condition_expression,
+ )
+
+ result_variable = '${}'.format(counter)
+ counter += 1
+
+ counter, if_statement_list = normalize_statement_list(
+ counter,
+ expression.if_statement_list,
+ assign_result_to=result_variable,
+ )
+ counter, else_statement_list = normalize_statement_list(
+ counter,
+ expression.else_statement_list,
+ assign_result_to=result_variable,
+ )
+
+ return (
+ counter,
+ condition_prestatements + (
+ NormalVariableInitializationStatement(
+ variable=result_variable,
+ expression=NormalVariableExpression(variable='builtin$nil'),
+ ),
+ NormalIfElseStatement(
+ condition_expression=condition_expression,
+ if_statement_list=if_statement_list,
+ else_statement_list=else_statement_list,
+ ),
+ ),
+ NormalVariableExpression(variable=result_variable),
+ )
+
+def normalize_negation_expression(counter, expression):
+ counter, prestatements, internal_expression = normalize_expression(counter, expression.value)
+
+ internal_variable = '${}'.format(counter)
+ counter += 1
+
+ return (
+ counter,
+ prestatements + (
+ NormalVariableInitializationStatement(
+ variable=internal_variable,
+ expression=internal_expression,
+ ),
+ ),
+ NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)),
+ )
+
+def normalize_expression(counter, expression):
+ return {
+ NormalInfixExpression: fake_normalization,
+ NormalVariableExpression: fake_normalization,
+ parsing.FurFunctionCallExpression: normalize_function_call_expression,
+ parsing.FurIfExpression: normalize_if_expression,
+ parsing.FurInfixExpression: normalize_infix_expression,
+ parsing.FurIntegerLiteralExpression: normalize_integer_literal_expression,
+ parsing.FurListLiteralExpression: normalize_list_literal_expression,
+ parsing.FurListItemExpression: normalize_list_item_expression,
+ parsing.FurNegationExpression: normalize_negation_expression,
+ parsing.FurStringLiteralExpression: normalize_string_literal_expression,
+ parsing.FurStructureLiteralExpression: normalize_structure_literal_expression,
+ parsing.FurSymbolExpression: normalize_symbol_expression,
+ }[type(expression)](counter, expression)
+
+def normalize_expression_statement(counter, statement):
+ # TODO Normalized will be a NormalVariableExpression, which will go unused
+ # for expression statements in every case except when it's a return
+ # statement. This cases warnings on C compilation. We should only generate
+ # this variable when it will be used on return.
+ counter, prestatements, normalized = normalize_expression(counter, statement.expression)
+
+ return (
+ counter,
+ prestatements,
+ NormalExpressionStatement(expression=normalized),
+ )
+
+def normalize_function_definition_statement(counter, statement):
+ _, statement_list = normalize_statement_list(
+ 0,
+ statement.statement_list,
+ assign_result_to='result',
+ )
+ return (
+ counter,
+ (),
+ NormalFunctionDefinitionStatement(
+ name=statement.name,
+ argument_name_list=statement.argument_name_list,
+ statement_list=statement_list,
+ ),
+ )
+
+def normalize_assignment_statement(counter, statement):
+ counter, prestatements, normalized_expression = normalize_expression(counter, statement.expression)
+ return (
+ counter,
+ prestatements,
+ NormalAssignmentStatement(
+ target=statement.target,
+ expression=normalized_expression,
+ ),
+ )
+
+def normalize_statement(counter, statement):
+ return {
+ parsing.FurAssignmentStatement: normalize_assignment_statement,
+ parsing.FurExpressionStatement: normalize_expression_statement,
+ parsing.FurFunctionDefinitionStatement: normalize_function_definition_statement,
+ }[type(statement)](counter, statement)
+
+@util.force_generator(tuple)
+def normalize_statement_list(counter, statement_list, **kwargs):
+ assign_result_to = kwargs.pop('assign_result_to', None)
+
+ assert len(kwargs) == 0
+
+ result_statement_list = []
+
+ for statement in statement_list: