Fix/simplify the generation of if/else statements
authorDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 23 Aug 2019 05:40:00 +0000 (01:40 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 23 Aug 2019 05:40:00 +0000 (01:40 -0400)
conversion.py
crossplatform_ir_generation.py
generation.py
normalization.py
transformation.py

index 49e27fd..b71e834 100644 (file)
@@ -87,8 +87,8 @@ CPSExpressionStatement = collections.namedtuple(
     ),
 )
 
-CPSIfElseStatement = collections.namedtuple(
-    'CPSIfElseStatement',
+CPSIfElseExpression = collections.namedtuple(
+    'CPSIfElseExpression',
     (
         'condition_expression',
         'if_statement_list',
@@ -127,14 +127,6 @@ CPSSymbolArrayVariableInitializationStatement = collections.namedtuple(
     ),
 )
 
-CPSVariableReassignmentStatement = collections.namedtuple(
-    'CPSVariableReassignmentStatement',
-    (
-        'variable',
-        'expression',
-    ),
-)
-
 CPSProgram = collections.namedtuple(
     'CPSProgram',
     (
@@ -181,6 +173,7 @@ def convert_variable_expression(expression):
 def convert_expression(expression):
     return {
         normalization.NormalFunctionCallExpression: convert_function_call_expression,
+        normalization.NormalIfElseExpression: convert_if_else_expression,
         normalization.NormalIntegerLiteralExpression: convert_integer_literal_expression,
         normalization.NormalLambdaExpression: convert_lambda_expression,
         normalization.NormalListConstructExpression: convert_list_construct_expression,
@@ -207,11 +200,14 @@ def convert_expression_statement(statement):
         expression=convert_expression(statement.expression),
     )
 
-def convert_if_else_statement(statement):
-    return CPSIfElseStatement(
+def convert_if_else_expression(statement):
+    if_statement_list=tuple(convert_statement(s) for s in statement.if_statement_list)
+    else_statement_list=tuple(convert_statement(s) for s in statement.else_statement_list)
+
+    return CPSIfElseExpression(
         condition_expression=convert_expression(statement.condition_expression),
-        if_statement_list=tuple(convert_statement(s) for s in statement.if_statement_list),
-        else_statement_list=tuple(convert_statement(s) for s in statement.else_statement_list),
+        if_statement_list=if_statement_list,
+        else_statement_list=else_statement_list,
     )
 
 def convert_list_append_statement(statement):
@@ -232,12 +228,6 @@ def convert_variable_initialization_statement(statement):
         expression=convert_expression(statement.expression),
     )
 
-def convert_variable_reassignment_statement(statement):
-    return CPSVariableReassignmentStatement(
-        variable=statement.variable,
-        expression=convert_expression(statement.expression),
-    )
-
 def convert_symbol_array_variable_initialization_statement(statement):
     return CPSSymbolArrayVariableInitializationStatement(
         variable=statement.variable,
@@ -249,15 +239,17 @@ def convert_statement(statement):
         normalization.NormalArrayVariableInitializationStatement: convert_array_variable_initialization_statement,
         normalization.NormalAssignmentStatement: convert_assignment_statement,
         normalization.NormalExpressionStatement: convert_expression_statement,
-        normalization.NormalIfElseStatement: convert_if_else_statement,
         normalization.NormalListAppendStatement: convert_list_append_statement,
         normalization.NormalPushStatement: convert_push_statement,
         normalization.NormalVariableInitializationStatement: convert_variable_initialization_statement,
-        normalization.NormalVariableReassignmentStatement: convert_variable_reassignment_statement,
         normalization.NormalSymbolArrayVariableInitializationStatement: convert_symbol_array_variable_initialization_statement,
     }[type(statement)](statement)
 
+def convert_statement_list(statement_list):
+    return tuple(convert_statement(s) for s in statement_list)
+
+
 def convert(program):
     return CPSProgram(
-        statement_list=tuple(convert_statement(s) for s in program.statement_list),
+        statement_list=convert_statement_list(program.statement_list),
     )
index c7d855f..332a74f 100644 (file)
@@ -123,6 +123,7 @@ def generate_variable_expression(counters, expression):
 def generate_expression(counters, expression):
     return {
         conversion.CPSFunctionCallExpression: generate_function_call_expression,
+        conversion.CPSIfElseExpression: generate_if_else_expression,
         conversion.CPSIntegerLiteralExpression: generate_integer_literal_expression,
         conversion.CPSLambdaExpression: generate_lambda_expression,
         conversion.CPSStringLiteralExpression: generate_string_literal_expression,
@@ -145,18 +146,27 @@ def generate_expression_statement(counters, statement):
 
     return referenced_entry_list, instruction_list
 
-def generate_if_else_statement(counters, statement):
+def generate_if_else_expression(counters, statement):
     if_counter = counters['if']
     counters['if'] += 1
 
     referenced_entry_list_list = []
 
+    condition_referenced_entry_list, condition_instruction_list = generate_expression(
+        counters,
+        statement.condition_expression,
+    )
+
     if_instruction_list_list = []
     for if_statement in statement.if_statement_list:
         referenced_entry_list, instruction_list = generate_statement(counters, if_statement)
         referenced_entry_list_list.append(referenced_entry_list)
         if_instruction_list_list.append(instruction_list)
 
+    if_instruction_list = flatten(if_instruction_list_list)
+    assert if_instruction_list[-1].instruction == 'drop'
+    if_instruction_list = if_instruction_list[:-1]
+
     else_instruction_list_list = []
 
     for else_statement in statement.else_statement_list:
@@ -164,30 +174,38 @@ def generate_if_else_statement(counters, statement):
         referenced_entry_list_list.append(referenced_entry_list)
         else_instruction_list_list.append(instruction_list)
 
+    else_instruction_list = flatten(else_instruction_list_list)
+    assert else_instruction_list[-1].instruction == 'drop'
+    else_instruction_list = else_instruction_list[:-1]
+
     if_label = '__if${}__'.format(if_counter)
     else_label = '__else${}__'.format(if_counter)
     endif_label = '__endif${}__'.format(if_counter)
 
-    instruction_list = (
-        referenced_entry_list_list,
-        generate_expression(counters, statement.condition_expression) + (
-            CIRInstruction(
-                instruction='jump_if_false',
-                argument=else_label,
-            ),
-            CIRLabel(label=if_label),
-        ) + flatten(if_instruction_list_list) + (
-            CIRInstruction(
-                instruction='jump',
-                argument=endif_label,
-            ),
-            CIRLabel(label=else_label),
-        ) + flatten(else_instruction_list_list) + (
-            CIRLabel(label=endif_label),
+    instruction_list = condition_instruction_list + (
+        CIRInstruction(
+            instruction='jump_if_false',
+            argument=else_label,
         ),
+        CIRInstruction(
+            instruction='jump',
+            argument=if_label,
+        ),
+        CIRLabel(label=if_label),
+    ) + if_instruction_list + (
+        CIRInstruction(
+            instruction='jump',
+            argument=endif_label,
+        ),
+        CIRLabel(label=else_label),
+    ) + else_instruction_list + (
+        CIRLabel(label=endif_label),
     )
 
-    return flatten(referenced_entry_list_list), instruction_list
+    return (
+        condition_referenced_entry_list + flatten(referenced_entry_list_list),
+        instruction_list,
+    )
 
 def generate_assignment_statement(counters, statement):
     referenced_entry_list, instruction_list = generate_expression(
@@ -222,29 +240,12 @@ def generate_variable_initialization_statement(counters, statement):
 
     return referenced_entry_list, instruction_list
 
-def generate_variable_reassignment_statement(counters, statement):
-    referenced_entry_list, instruction_list = generate_expression(
-        counters,
-        statement.expression,
-    )
-
-    instruction_list += (
-        CIRInstruction(
-            instruction='pop',
-            argument=generate_symbol_literal(statement.variable),
-        ),
-    )
-
-    return referenced_entry_list, instruction_list
-
 def generate_statement(counters, statement):
     return {
         conversion.CPSAssignmentStatement: generate_assignment_statement,
         conversion.CPSExpressionStatement: generate_expression_statement,
-        conversion.CPSIfElseStatement: generate_if_else_statement,
         conversion.CPSPushStatement: generate_push_statement,
         conversion.CPSVariableInitializationStatement: generate_variable_initialization_statement,
-        conversion.CPSVariableReassignmentStatement: generate_variable_reassignment_statement,
     }[type(statement)](counters, statement)
 
 def generate(converted):
index d855d07..645441f 100644 (file)
@@ -45,6 +45,7 @@ def generate_list_construct_expression(expression):
 def generate_expression(expression):
     return {
         transformation.CFunctionCallExpression: generate_function_call,
+        transformation.CIfElseExpression: generate_if_else_expression,
         transformation.CIntegerLiteral: generate_integer_literal,
         transformation.CLambdaExpression: generate_lambda_expression,
         transformation.CListConstructExpression: generate_list_construct_expression,
@@ -98,17 +99,10 @@ def generate_variable_initialization_statement(statement):
         generate_expression(statement.expression),
     )
 
-def generate_variable_reassignment_statement(statement):
-    return '{} = {};'.format(
-        statement.variable,
-        generate_expression(statement.expression),
-    )
-
-
 def indent(s):
     return '\n'.join(' ' * 2 + l for l in s.split('\n'))
 
-def generate_if_else_statement(statement):
+def generate_if_else_expression(statement):
     # TODO Check that the argument is boolean
     condition_expression = '{}.instance.boolean'.format(
         generate_expression(statement.condition_expression),
@@ -153,13 +147,11 @@ def generate_statement(statement):
     return {
         transformation.CArrayVariableInitializationStatement: generate_array_variable_initialization_statement,
         transformation.CExpressionStatement: generate_expression_statement,
-        transformation.CIfElseStatement: generate_if_else_statement,
         transformation.CListAppendStatement: generate_list_append_statement,
         transformation.CPushStatement: generate_push_statement,
         transformation.CSymbolAssignmentStatement: generate_symbol_assignment_statement,
         transformation.CSymbolArrayVariableInitializationStatement: generate_symbol_array_variable_initialization_statement,
         transformation.CVariableInitializationStatement: generate_variable_initialization_statement,
-        transformation.CVariableReassignmentStatement: generate_variable_reassignment_statement,
     }[type(statement)](statement)
 
 def generate_function_definition(definition):
index 71f1fba..7ce7488 100644 (file)
@@ -80,14 +80,6 @@ NormalVariableInitializationStatement = collections.namedtuple(
     ],
 )
 
-NormalVariableReassignmentStatement = collections.namedtuple(
-    'NormalVariableReassignmentStatement',
-    [
-        'variable',
-        'expression',
-    ],
-)
-
 NormalExpressionStatement = collections.namedtuple(
     'NormalExpressionStatement',
     [
@@ -103,8 +95,8 @@ NormalAssignmentStatement = collections.namedtuple(
     ],
 )
 
-NormalIfElseStatement = collections.namedtuple(
-    'NormalIfElseStatement',
+NormalIfElseExpression = collections.namedtuple(
+    'NormalIfElseExpression',
     [
         'condition_expression',
         'if_statement_list',
@@ -132,7 +124,6 @@ def normalize_lambda_expression(counter, expression):
     _, statement_list = normalize_statement_list(
         0,
         expression.statement_list,
-        assign_result_to='result',
     )
 
     return (
@@ -328,34 +319,23 @@ def normalize_if_expression(counter, expression):
         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,
-            ),
+        condition_prestatements,
+        NormalIfElseExpression(
+            condition_expression=condition_expression,
+            if_statement_list=if_statement_list,
+            else_statement_list=else_statement_list,
         ),
-        NormalVariableExpression(variable=result_variable),
     )
 
 def normalize_expression(counter, expression):
@@ -401,11 +381,7 @@ def normalize_statement(counter, 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
-
+def normalize_statement_list(counter, statement_list):
     result_statement_list = []
 
     for statement in statement_list:
@@ -414,19 +390,6 @@ def normalize_statement_list(counter, statement_list, **kwargs):
             result_statement_list.append(s)
         result_statement_list.append(normalized)
 
-    # TODO The way we fix the last statement is really confusing
-    last_statement = result_statement_list[-1]
-
-    if isinstance(last_statement, NormalExpressionStatement) and isinstance(last_statement.expression, NormalVariableExpression):
-        if assign_result_to is not None:
-            result_expression = result_statement_list.pop().expression
-            result_statement_list.append(
-                NormalVariableReassignmentStatement(
-                    variable=assign_result_to,
-                    expression=result_expression,
-                )
-            )
-
     return (
         counter,
         result_statement_list,
index a9cad95..6aa7080 100644 (file)
@@ -92,14 +92,6 @@ CVariableInitializationStatement = collections.namedtuple(
     ],
 )
 
-CVariableReassignmentStatement = collections.namedtuple(
-    'CVariableReassignmentStatement',
-    [
-        'variable',
-        'expression',
-    ],
-)
-
 CExpressionStatement = collections.namedtuple(
     'CExpressionStatement',
     [
@@ -107,8 +99,8 @@ CExpressionStatement = collections.namedtuple(
     ],
 )
 
-CIfElseStatement = collections.namedtuple(
-    'CIfElseStatement',
+CIfElseExpression = collections.namedtuple(
+    'CIfElseExpression',
     [
         'condition_expression',
         'if_statement_list',
@@ -246,6 +238,7 @@ def transform_list_append_statement(accumulators, expression):
 def transform_expression(accumulators, expression):
     return {
         conversion.CPSFunctionCallExpression: transform_function_call_expression,
+        conversion.CPSIfElseExpression: transform_if_else_expression,
         conversion.CPSIntegerLiteralExpression: transform_integer_literal_expression,
         conversion.CPSLambdaExpression: transform_lambda_expression,
         conversion.CPSListConstructExpression: transform_list_construct_expression,
@@ -285,8 +278,8 @@ def transform_expression_statement(accumulators, statement):
         expression=transform_expression(accumulators, statement.expression),
     )
 
-def transform_if_else_statement(accumulators, statement):
-    return CIfElseStatement(
+def transform_if_else_expression(accumulators, statement):
+    return CIfElseExpression(
         condition_expression=transform_expression(accumulators, statement.condition_expression),
         if_statement_list=tuple(transform_statement(accumulators, s) for s in statement.if_statement_list),
         else_statement_list=tuple(transform_statement(accumulators, s) for s in statement.else_statement_list),
@@ -322,12 +315,6 @@ def transform_variable_initialization_statement(accumulators, statement):
         expression=transform_expression(accumulators, statement.expression),
     )
 
-def transform_variable_reassignment_statement(accumulators, statement):
-    return CVariableReassignmentStatement(
-        variable=statement.variable,
-        expression=transform_expression(accumulators, statement.expression),
-    )
-
 def transform_push_statement(accumulators, statement):
     return CPushStatement(expression=transform_expression(accumulators, statement.expression))
 
@@ -336,12 +323,10 @@ def transform_statement(accumulators, statement):
         conversion.CPSArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
         conversion.CPSAssignmentStatement: transform_symbol_assignment_statement,
         conversion.CPSExpressionStatement: transform_expression_statement,
-        conversion.CPSIfElseStatement: transform_if_else_statement,
         conversion.CPSListAppendStatement: transform_list_append_statement,
         conversion.CPSPushStatement: transform_push_statement,
         conversion.CPSSymbolArrayVariableInitializationStatement: transform_symbol_array_variable_initialization_statement,
         conversion.CPSVariableInitializationStatement: transform_variable_initialization_statement,
-        conversion.CPSVariableReassignmentStatement: transform_variable_reassignment_statement,
     }[type(statement)](accumulators, statement)