Added if expression statements
[fur] / normalization.py
index 6f27b55..c96e455 100644 (file)
@@ -10,6 +10,27 @@ NormalVariableExpression = collections.namedtuple(
     ],
 )
 
+NormalIntegerLiteralExpression = collections.namedtuple(
+    'NormalIntegerLiteralExpression',
+    [
+        'integer',
+    ],
+)
+
+NormalStringLiteralExpression = collections.namedtuple(
+    'NormalStringLiteralExpression',
+    [
+        'string',
+    ],
+)
+
+NormalSymbolExpression = collections.namedtuple(
+    'NormalSymbolExpression',
+    [
+        'symbol',
+    ],
+)
+
 NormalNegationExpression = collections.namedtuple(
     'NormalNegationExpression',
     [
@@ -30,7 +51,7 @@ NormalInfixExpression = collections.namedtuple(
 NormalFunctionCallExpression = collections.namedtuple(
     'NormalFunctionCallExpression',
     [
-        'function',
+        'function_expression',
         'argument_count',
         'argument_items',
     ],
@@ -67,12 +88,20 @@ NormalExpressionStatement = collections.namedtuple(
     ],
 )
 
+NormalAssignmentStatement = collections.namedtuple(
+    'NormalAssignmentStatement',
+    [
+        'target',
+        'expression',
+    ],
+)
+
 NormalIfElseStatement = collections.namedtuple(
     'NormalIfElseStatement',
     [
         'condition_expression',
-        'if_statements',
-        'else_statements',
+        'if_statement_list',
+        'else_statement_list',
     ],
 )
 
@@ -80,6 +109,7 @@ NormalFunctionDefinitionStatement = collections.namedtuple(
     'NormalFunctionDefinitionStatement',
     [
         'name',
+        'argument_name_list',
         'statement_list',
     ],
 )
@@ -91,10 +121,48 @@ NormalProgram = collections.namedtuple(
     ],
 )
 
-# TODO Get rid of this
 def fake_normalization(counter, thing):
     return (counter, (), thing)
 
+def normalize_integer_literal_expression(counter, expression):
+    variable = '${}'.format(counter)
+    return (
+        counter + 1,
+        (
+            NormalVariableInitializationStatement(
+                variable=variable,
+                expression=NormalIntegerLiteralExpression(integer=expression.integer),
+            ),
+        ),
+        NormalVariableExpression(variable=variable),
+    )
+
+def normalize_string_literal_expression(counter, expression):
+    variable = '${}'.format(counter)
+    return (
+        counter + 1,
+        (
+            NormalVariableInitializationStatement(
+                variable=variable,
+                expression=NormalStringLiteralExpression(string=expression.string),
+            ),
+        ),
+        NormalVariableExpression(variable=variable),
+    )
+
+def normalize_symbol_expression(counter, expression):
+    variable = '${}'.format(counter)
+    return (
+        counter + 1,
+        (
+            NormalVariableInitializationStatement(
+                variable=variable,
+                expression=NormalSymbolExpression(symbol=expression.symbol),
+            ),
+        ),
+        NormalVariableExpression(variable=variable),
+    )
+
 def normalize_function_call_expression(counter, expression):
     assert isinstance(expression, parsing.FurFunctionCallExpression)
 
@@ -108,10 +176,12 @@ def normalize_function_call_expression(counter, expression):
             prestatements.append(s)
 
         variable = '${}'.format(counter)
-        prestatements.append(NormalVariableInitializationStatement(
-            variable=variable,
-            expression=normalized_argument,
-        ))
+        prestatements.append(
+            NormalVariableInitializationStatement(
+                variable=variable,
+                expression=normalized_argument,
+            )
+        )
         arguments.append(NormalVariableExpression(
             variable=variable,
         ))
@@ -125,11 +195,32 @@ def normalize_function_call_expression(counter, expression):
         items=tuple(arguments),
     ))
 
+    counter, function_prestatements, function_expression = normalize_expression(
+        counter,
+        expression.function,
+    )
+
+    for ps in function_prestatements:
+        prestatements.append(ps)
+
+    if not isinstance(function_expression, NormalVariableExpression):
+        function_variable = '${}'.format(counter)
+
+        prestatements.append(
+            NormalVariableInitializationStatement(
+                variable=function_variable,
+                expression=function_expression,
+            )
+        )
+
+        function_expression = NormalVariableExpression(variable=function_variable)
+        counter += 1
+
     return (
         counter,
         tuple(prestatements),
         NormalFunctionCallExpression(
-            function=expression.function, # TODO Normalize the function
+            function_expression=function_expression,
             argument_count=len(arguments),
             argument_items=NormalVariableExpression(variable=arguments_variable),
         ),
@@ -143,6 +234,8 @@ def normalize_basic_infix_operation(counter, expression):
     counter += 1
     right_variable = '${}'.format(counter)
     counter += 1
+    center_variable = '${}'.format(counter)
+    counter += 1
 
     root_prestatements = (
         NormalVariableInitializationStatement(
@@ -153,17 +246,21 @@ def normalize_basic_infix_operation(counter, expression):
             variable=right_variable,
             expression=right_expression,
         ),
+        NormalVariableInitializationStatement(
+            variable=center_variable,
+            expression=NormalInfixExpression(
+                order=expression.order,
+                operator=expression.operator,
+                left=NormalVariableExpression(variable=left_variable),
+                right=NormalVariableExpression(variable=right_variable),
+            ),
+        ),
     )
 
     return (
         counter,
         left_prestatements + right_prestatements + root_prestatements,
-        NormalInfixExpression(
-            order=expression.order, # TODO Do we need this?
-            operator=expression.operator,
-            left=NormalVariableExpression(variable=left_variable),
-            right=NormalVariableExpression(variable=right_variable),
-        ),
+        NormalVariableExpression(variable=center_variable),
     )
 
 def normalize_comparison_expression(counter, expression):
@@ -195,9 +292,8 @@ def normalize_comparison_expression(counter, expression):
     counter, result_prestatements, result_expression = (
         counter,
         left_prestatements + right_prestatements + root_prestatements,
-        # TODO Implement short-circuiting
         NormalInfixExpression(
-            order=expression.order, # TODO Do we need this?
+            order=expression.order,
             operator=expression.operator,
             left=NormalVariableExpression(variable=left_variable),
             right=NormalVariableExpression(variable=right_variable),
@@ -234,7 +330,10 @@ def normalize_boolean_expression(counter, expression):
     counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
 
     result_variable = '${}'.format(counter)
-    if_else_prestatment = NormalVariableInitializationStatement(variable=result_variable, expression=left_expression)
+    if_else_prestatment = NormalVariableInitializationStatement(
+        variable=result_variable,
+        expression=left_expression,
+    )
     counter += 1
 
     condition_expression=NormalVariableExpression(variable=result_variable)
@@ -243,15 +342,15 @@ def normalize_boolean_expression(counter, expression):
     if expression.operator == 'and':
         if_else_statement = NormalIfElseStatement(
             condition_expression=condition_expression,
-            if_statements=short_circuited_statements,
-            else_statements=(),
+            if_statement_list=short_circuited_statements,
+            else_statement_list=(),
         )
 
     elif expression.operator == 'or':
         if_else_statement = NormalIfElseStatement(
             condition_expression=condition_expression,
-            if_statements=(),
-            else_statements=short_circuited_statements,
+            if_statement_list=(),
+            else_statement_list=short_circuited_statements,
         )
 
     else:
@@ -273,6 +372,45 @@ def normalize_infix_expression(counter, 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)
 
@@ -281,31 +419,34 @@ def normalize_negation_expression(counter, expression):
 
     return (
         counter,
-        prestatements + (NormalVariableInitializationStatement(variable=internal_variable, expression=internal_expression),),
+        prestatements + (
+            NormalVariableInitializationStatement(
+                variable=internal_variable,
+                expression=internal_expression,
+            ),
+        ),
         NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)),
     )
 
-def normalize_parenthesized_expression(counter, expression):
-    return normalize_expression(counter, expression.internal)
-
 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: fake_normalization,
+        parsing.FurIntegerLiteralExpression: normalize_integer_literal_expression,
         parsing.FurNegationExpression: normalize_negation_expression,
-        parsing.FurParenthesizedExpression: normalize_parenthesized_expression,
-        parsing.FurStringLiteralExpression: fake_normalization,
-        parsing.FurSymbolExpression: fake_normalization,
+        parsing.FurStringLiteralExpression: normalize_string_literal_expression,
+        parsing.FurSymbolExpression: normalize_symbol_expression,
     }[type(expression)](counter, expression)
 
 def normalize_expression_statement(counter, statement):
-    counter, prestatements, normalized = {
-        parsing.FurFunctionCallExpression: normalize_function_call_expression,
-        parsing.FurIntegerLiteralExpression: normalize_expression,
-    }[type(statement.expression)](counter, statement.expression)
+    # 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,
@@ -314,34 +455,74 @@ def normalize_expression_statement(counter, statement):
     )
 
 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,
-            statement_list=normalize_statement_list(statement.statement_list),
+            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: fake_normalization, # TODO unfake this
+        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(statement_list):
-    counter = 0
+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:
         counter, prestatements, normalized = normalize_statement(counter, statement)
         for s in prestatements:
-            yield s
-        yield normalized
+            result_statement_list.append(s)
+        result_statement_list.append(normalized)
+
+    last_statement = result_statement_list[-1]
+
+    if isinstance(last_statement, NormalExpressionStatement) and isinstance(last_statement.expression, NormalVariableExpression):
+        result_expression = result_statement_list.pop().expression
+
+        if assign_result_to is not None:
+            result_statement_list.append(
+                NormalVariableReassignmentStatement(
+                    variable=assign_result_to,
+                    expression=result_expression,
+                )
+            )
+
+    return (
+        counter,
+        result_statement_list,
+    )
 
 def normalize(program):
+    _, statement_list = normalize_statement_list(0, program.statement_list)
 
     return NormalProgram(
-        statement_list=normalize_statement_list(program.statement_list),
+        statement_list=statement_list,
     )