예제 #1
0
def basic_block(statements: List[Statement]) -> BasicBlock:
    done_label = TempManager.new_label()
    statement_lists = []

    block_start_index = 0
    for index, statement in enumerate(statements):
        if isinstance(statement, Label):
            # If the label is supposed to be the beginning of a new block, we do not end the
            # previous block since it was already ended by a jump.
            # If not, then we end the previous block and start the new one with the current label.
            if block_start_index < index:
                statement_lists.append(statements[block_start_index:index])
                block_start_index = index
        elif isinstance(statement, Jump) or isinstance(statement,
                                                       ConditionalJump):
            statement_lists.append(statements[block_start_index:index + 1])
            block_start_index = index + 1
    last_block = statements[block_start_index:len(statements)] + [
        Jump(Name(done_label), [done_label])
    ]
    statement_lists.append(last_block)

    for index, statement_list in enumerate(statement_lists):
        if not isinstance(statement_list[0], Label):
            statement_lists[index] = [Label(TempManager.new_label())
                                      ] + statement_list

    for index, statement_list in enumerate(statement_lists[:-1]):
        if not isinstance(statement_list[-1], Jump) and not isinstance(
                statement_list[-1], ConditionalJump):
            next_block_label = statement_lists[index + 1][0]
            statement_lists[index] = statement_list + [
                Jump(Name(next_block_label.label), [next_block_label.label])
            ]
    return BasicBlock(done_label, statement_lists)
예제 #2
0
def for_expression(
    variable: TranslatedExpression,
    lo: TranslatedExpression,
    hi: TranslatedExpression,
    body: TranslatedExpression,
    break_label: TempLabel,
) -> TranslatedExpression:
    test_label = TempManager.new_label()
    body_label = TempManager.new_label()
    limit = TempManager.new_temp()
    variable_expression = convert_to_expression(variable)

    sequence = Sequence([
        Move(variable_expression, convert_to_expression(lo)),
        Move(Temporary(limit), convert_to_expression(hi)),
        Label(test_label),
        ConditionalJump(
            RelationalOperator.le,
            variable_expression,
            Temporary(limit),
            body_label,
            break_label,
        ),
        Label(body_label),
        convert_to_statement(body),
        Move(
            variable_expression,
            BinaryOperation(BinaryOperator.plus, variable_expression,
                            Constant(1)),
        ),
        Jump(Name(test_label), [test_label]),
        Label(break_label),
    ])

    return NoResult(sequence)
예제 #3
0
def if_expression(
    test: TranslatedExpression,
    then: TranslatedExpression,
    else_do: Optional[TranslatedExpression],
) -> TranslatedExpression:
    test_condition = convert_to_condition(test)
    then_expression = convert_to_expression(then)
    else_expression = (convert_to_expression(else_do)
                       if else_do is not None else Constant(0))

    true_label = TempManager.new_label()
    false_label = TempManager.new_label()
    join_label = TempManager.new_label()

    result = TempManager.new_temp()

    patch_true_labels(test_condition.trues, true_label)
    patch_false_labels(test_condition.trues, false_label)

    sequence = Sequence([
        test_condition.statement,
        Label(true_label),
        Move(Temporary(result), then_expression),
        Jump(Name(join_label), [join_label]),
        Label(false_label),
        Move(Temporary(result), else_expression),
        Label(join_label),
    ])

    return Expression(EvaluateSequence(sequence, Temporary(result)))
예제 #4
0
def convert_to_expression(exp: TranslatedExpression) -> tree.Expression:
    if isinstance(exp, Expression):
        return exp.expression

    if isinstance(exp, NoResult):
        return EvaluateSequence(exp.statement, Constant(0))

    if isinstance(exp, Conditional):
        temporary_value = TempManager.new_temp()
        true = TempManager.new_label()
        false = TempManager.new_label()
        patch_true_labels(exp.condition.trues, true)
        patch_false_labels(exp.condition.falses, false)
        return EvaluateSequence(
            Move(Temporary(temporary_value), Constant(1)),
            EvaluateSequence(
                exp.condition.statement,
                EvaluateSequence(
                    Label(false),
                    EvaluateSequence(
                        Move(Temporary(temporary_value), Constant(0)),
                        EvaluateSequence(Label(true),
                                         Temporary(temporary_value)),
                    ),
                ),
            ),
        )
예제 #5
0
def convert_to_statement(exp: TranslatedExpression) -> tree.Statement:
    if isinstance(exp, Expression):
        return StatementExpression(exp.expression)

    if isinstance(exp, NoResult):
        return exp.statement

    if isinstance(exp, Conditional):
        true = TempManager.new_label()
        false = TempManager.new_label()
        patch_true_labels(exp.condition.trues, true)
        patch_false_labels(exp.condition.falses, false)
        return Sequence([exp.condition.statement, Label(true), Label(false)])
예제 #6
0
def while_expression(test: TranslatedExpression, body: TranslatedExpression,
                     break_label: TempLabel) -> TranslatedExpression:
    test_label = TempManager.new_label()
    body_label = TempManager.new_label()

    sequence = Sequence([
        Label(test_label),
        ConditionalJump(
            RelationalOperator.ne,
            convert_to_expression(test),
            Constant(0),
            body_label,
            break_label,
        ),
        Label(body_label),
        convert_to_statement(body),
        Jump(Name(test_label), [test_label]),
        Label(break_label),
    ])

    return NoResult(sequence)
예제 #7
0
def string_expression(string: str) -> TranslatedExpression:
    string_label = TempManager.new_label()
    FragmentManager.add_fragment(StringFragment(string_label, string))
    return Expression(Name(string_label))
예제 #8
0
def translate_declaration(
    value_env: SymbolTable[EnvironmentEntry],
    type_env: SymbolTable[Type],
    declaration: ast.Declaration,
    level: RealLevel,
    break_label: Optional[TempLabel],
) -> TranslatedExpression:
    if isinstance(declaration, ast.FunctionDecBlock):
        # Function declaration block: Check that all function names are unique. Then, evaluate each
        # function header and add it to the value environment. Then, for each function, push its
        # parameters to the value environment and make sure the function body returns the same type
        # as the declared one.
        if not check_name_uniqueness(declaration.function_dec_list):
            raise SemanticError(
                "All names in the function declaration block must be unique",
                declaration.position,
            )
        function_entries = []
        for function_dec in declaration.function_dec_list:
            formals = []
            for parameter in function_dec.params:
                param_type = type_env.find(parameter.type)
                if param_type is None:
                    raise SemanticError(
                        f"Undefined argument type {parameter.type} for parameter {parameter.name}"
                        + f"in function {function_dec.name}",
                        parameter.position,
                    )
                formals.append(param_type)
            if function_dec.return_type is None:
                return_type = VoidType()
            else:
                return_type = type_env.find(function_dec.return_type)
                if return_type is None:
                    raise SemanticError(
                        f"Undefined return type {function_dec.return_type}" +
                        f" for function {function_dec.name}",
                        function_dec.position,
                    )
            function_label = TempManager.new_label()
            function_level = RealLevel(level, function_label,
                                       function_dec.param_escapes)
            function_entry = FunctionEntry(function_level, function_label,
                                           formals, return_type)
            function_entries.append(function_entry)
            value_env.add(function_dec.name, function_entry)
        for function_dec, function_entry in zip(declaration.function_dec_list,
                                                function_entries):
            value_env.begin_scope()
            # We ignore the static link since we need the accesses of the REAL function formals.
            formal_accesses = function_entry.level.formals()[1:]
            for param, formal_type, formal_access in zip(
                    function_dec.params, function_entry.formals,
                    formal_accesses):
                value_env.add(param.name,
                              VariableEntry(formal_access, formal_type))
            trans_exp = translate_expression(
                value_env,
                type_env,
                function_entry.level,
                function_dec.body,
                break_label,
            )
            if not are_types_equal(trans_exp.type, function_entry.result):
                raise SemanticError(
                    f"Function {function_dec.name} returns a value of a type" +
                    " different than its declared type",
                    function_dec.position,
                )
            IRT.proc_entry_exit(function_entry.level, trans_exp.expression)
            value_env.end_scope()
        return no_op_expression()

    elif isinstance(declaration, ast.VariableDec):
        # Variable declaration: Translate the expression, make sure its type matches the declared
        # type and that a variable initialized to nil has a type declaration of a record type.
        trans_exp = translate_expression(value_env, type_env, level,
                                         declaration.exp, break_label)
        if isinstance(trans_exp.type, NilType) and declaration.type is None:
            raise SemanticError(
                f"Must declare the type of variable {declaration.name} when initializing it to nil",
                declaration.position,
            )
        variable_type = trans_exp.type
        if declaration.type is not None:
            declared_type = type_env.find(declaration.type)
            if declared_type is None:
                raise SemanticError(
                    f"Undefined type {declaration.type} in variable declaration"
                    + f" for {declaration.name}",
                    declaration.position,
                )
            if isinstance(trans_exp.type, NilType) and not isinstance(
                    declared_type, RecordType):
                raise SemanticError(
                    f"Variable {declaration.name} must be of a record type when initialized to nil",
                    declaration.position,
                )
            if not are_types_equal(declared_type, trans_exp.type):
                raise SemanticError(
                    f"Initial value for variable {declaration.name} is not of its"
                    + f" declared type {declaration.type}",
                    declaration.position,
                )
            variable_type = declared_type

        variable_access = level.alloc_local(declaration.escape)
        value_env.add(declaration.name,
                      VariableEntry(variable_access, variable_type))
        return IRT.assignment_expression(
            IRT.simple_variable(variable_access, level), trans_exp.expression)

    elif isinstance(declaration, ast.TypeDecBlock):
        # Type declaration block: Check that all type names are unique. Then, follow these steps:
        # - Add a dummy reference to the type environment for every type declaration, so as to be
        # able to recognize undefined types in the following step.
        # - Translate each type and add it to the type environment. In this step, references to
        # types in the same block are stored as a name reference and not as a pointer to the real
        # referenced type.
        # - For each definition that is a type alias (the name we give to those that just name
        # another type instead of creating a record or array), keep moving forward in the type
        # aliases chain until you find a record or array type. Then make all involved type aliases
        # point to that record or array type. If you only find type aliases, you are inside a loop,
        # so return an error once you detect it.
        # - Go through all types again and, now that all type aliases are eliminated and point
        # at the right type definition, eliminate any name type references left by replacing them
        # with a pointer to the right type.
        # This implementation is not optimized at all, but It Just Works(TM) and we found it easier
        # to follow than the one in the book.
        if not check_name_uniqueness(declaration.type_dec_list):
            raise SemanticError(
                "All names in the type declaration block must be unique",
                declaration.position,
            )
        for type_dec in declaration.type_dec_list:
            type_env.add(type_dec.name, NameType(type_dec.name))
        for type_dec in declaration.type_dec_list:
            type_env.add(type_dec.name, translate_type(type_env,
                                                       type_dec.type))
        for type_dec in declaration.type_dec_list:
            if simplify_type_aliases(type_dec.name, type_env, set()) is None:
                raise SemanticError(
                    f"Cyclic type definition found involving type {type_dec.name}",
                    type_dec.position,
                )
        for type_dec in declaration.type_dec_list:
            type_definition = type_env.find(type_dec.name)
            eliminate_name_types(type_definition, type_env)
        return no_op_expression()

    else:
        raise SemanticError("Unknown declaration kind", declaration.position)
예제 #9
0
def translate_expression(
    value_env: SymbolTable[EnvironmentEntry],
    type_env: SymbolTable[Type],
    level: RealLevel,
    expression: ast.Expression,
    break_label: Optional[TempLabel],
) -> TypedExpression:
    if isinstance(expression, ast.VarExp):
        # Variable name: Translate the variable and return that value.
        return translate_variable(value_env, type_env, level, expression.var)

    if isinstance(expression, ast.NilExp):
        # Nil constant: Return nil type.
        return TypedExpression(IRT.nil_expression(), NilType())

    if isinstance(expression, ast.IntExp):
        # Integer constant: Return integer type.
        return TypedExpression(IRT.integer_expression(expression.int),
                               IntType())

    if isinstance(expression, ast.StringExp):
        # String constant: Return string type.
        return TypedExpression(IRT.string_expression(expression.string),
                               StringType())

    if isinstance(expression, ast.CallExp):
        # Function call: Look up the function name, check the types of the parameters and return
        # its return value type.
        func_value = value_env.find(expression.func)
        if func_value is None:
            raise SemanticError(f"Undefined function {expression.func}",
                                expression.position)
        if not isinstance(func_value, FunctionEntry):
            raise SemanticError(
                f"Non-function value {expression.func} is not callable",
                expression.position,
            )
        if len(expression.args) != len(func_value.formals):
            raise SemanticError(
                f"Wrong number of arguments in function call to {expression.func},"
                +
                f" {len(func_value.formals)} expected, but {len(expression.args)} given",
                expression.position,
            )
        translated_arguments = []
        for arg_position in range(len(expression.args)):
            trans_exp = translate_expression(value_env, type_env, level,
                                             expression.args[arg_position],
                                             break_label)
            translated_arguments.append(trans_exp.expression)
            if not are_types_equal(func_value.formals[arg_position],
                                   trans_exp.type):
                raise SemanticError(
                    f"Wrong type for argument in position {arg_position}" +
                    f" in call to {expression.func}",
                    expression.position,
                )
        return TypedExpression(
            IRT.call_expression(func_value.label, func_value.level, level,
                                translated_arguments),
            func_value.result,
        )

    if isinstance(expression, ast.OpExp):
        # Operation: If an arithmetic operation, check if both values are Integers.
        # If an in/equality comparison, check if both values have the same type.
        # If an order comparison, check if both values are either Integers or Strings.
        left = translate_expression(value_env, type_env, level,
                                    expression.left, break_label)
        right = translate_expression(value_env, type_env, level,
                                     expression.right, break_label)
        if expression.oper in (
                ast.Oper.plus,
                ast.Oper.minus,
                ast.Oper.times,
                ast.Oper.divide,
        ):
            if not isinstance(left.type, IntType):
                raise SemanticError(
                    "Left arithmetic operand must be an Integer",
                    expression.left.position,
                )
            if not isinstance(right.type, IntType):
                raise SemanticError(
                    "Right arithmetic operand must be an Integer",
                    expression.right.position,
                )
            intermediate_expression = IRT.arithmetic_operation_expression(
                expression.oper, left.expression, right.expression)
        elif expression.oper in (
                ast.Oper.eq,
                ast.Oper.neq,
                ast.Oper.lt,
                ast.Oper.le,
                ast.Oper.gt,
                ast.Oper.ge,
        ):
            if not are_types_equal(left.type, right.type):
                raise SemanticError(
                    "Values must be of the same type to test for equality or order",
                    expression.position,
                )
            if expression.oper in (
                    ast.Oper.lt,
                    ast.Oper.le,
                    ast.Oper.gt,
                    ast.Oper.ge,
            ) and not (are_types_equal(left.type, IntType())
                       or are_types_equal(left.type, StringType())):
                raise SemanticError(
                    "Values must be Integers or Strings to compare their order",
                    expression.position,
                )
            if are_types_equal(left.type, StringType()):
                intermediate_expression = IRT.string_conditional_operation_expression(
                    expression.oper, left.expression, right.expression)
            else:
                intermediate_expression = IRT.conditional_operation_expression(
                    expression.oper, left.expression, right.expression)
        else:
            raise SemanticError("Unknown operator", expression.position)
        return TypedExpression(intermediate_expression, IntType())

    if isinstance(expression, ast.RecordExp):
        # Record creation: Check the type is a record type, that only and all its defined fields
        # are declared and that all their associated expressions have the declared type.
        trans_typ = type_env.find(expression.type)
        if trans_typ is None:
            raise SemanticError(
                f"Undefined record type {expression.type}",
                expression.position,
            )
        if not isinstance(trans_typ, RecordType):
            raise SemanticError(
                f"Trying to create a record of type {expression.type}, which is not a record type",
                expression.position,
            )
        checked_fields = {}
        for exp_field in expression.fields:
            if exp_field.name in checked_fields:
                raise SemanticError(
                    f"Repeated field assignment for field {exp_field.name} in record creation",
                    exp_field.position,
                )
            found_field = False
            expected_field_type = None
            for type_field in trans_typ.fields:
                if type_field.name == exp_field.name:
                    found_field = True
                    expected_field_type = type_field.type
                    break
            if not found_field:
                raise SemanticError(
                    f"Unknown field {exp_field.name} in record creation",
                    exp_field.position,
                )
            trans_exp = translate_expression(value_env, type_env, level,
                                             exp_field.exp, break_label)
            checked_fields[exp_field.name] = trans_exp.expression
            if not are_types_equal(expected_field_type, trans_exp.type):
                raise SemanticError(
                    f"Assigning value of a wrong type to field {exp_field.name} in record creation",
                    exp_field.exp.position,
                )
        if len(checked_fields) < len(trans_typ.fields):
            raise SemanticError(
                "Missing field assignment in record creation",
                expression.position,
            )

        ordered_field_expressions = [
            checked_fields[field.name] for field in trans_typ.fields
        ]
        return TypedExpression(
            IRT.record_expression(ordered_field_expressions), trans_typ)

    if isinstance(expression, ast.SeqExp):
        # Sequence of expressions: Evaluate each of them and return the type of the last one.
        if len(expression.seq) == 0:
            return translate_expression(
                value_env,
                type_env,
                level,
                ast.EmptyExp(expression.position),
                break_label,
            )

        translated_expressions = []
        last_expression_type = VoidType()
        for seq_expression in expression.seq:
            trans_exp = translate_expression(value_env, type_env, level,
                                             seq_expression, break_label)
            translated_expressions.append(trans_exp.expression)
            last_expression_type = trans_exp.type

        return TypedExpression(IRT.sequence_expression(translated_expressions),
                               last_expression_type)

    if isinstance(expression, ast.AssignExp):
        # Assignment: Look up the l-value, make sure it's not a loop variable and that the
        # expression and l-value types match.
        if isinstance(expression.var, ast.SimpleVar):
            var_entry = value_env.find(expression.var.sym)
            if var_entry is None:
                raise SemanticError(
                    f"Trying to assign a value to undefined variable {expression.var.sym}",
                    expression.var.position,
                )
            if isinstance(var_entry,
                          VariableEntry) and not var_entry.is_editable:
                raise SemanticError(
                    f"For loop variable {expression.var.sym} is not assignable",
                    expression.var.position,
                )
        trans_var = translate_variable(value_env, type_env, level,
                                       expression.var)
        trans_exp = translate_expression(value_env, type_env, level,
                                         expression.exp, break_label)
        if not are_types_equal(trans_var.type, trans_exp.type):
            raise SemanticError(
                "Trying to assign a value to a variable of a different type",
                expression.position,
            )
        return TypedExpression(
            IRT.assignment_expression(trans_var.expression,
                                      trans_exp.expression),
            VoidType(),
        )

    if isinstance(expression, ast.IfExp):
        # If: Check the conditional expression returns an Integer type.
        # If it only has a then branch, then check it produces no value and return no value.
        # If it also has an else branch. make sure both produce the same type and return it.
        trans_test = translate_expression(value_env, type_env, level,
                                          expression.test, break_label)
        if not isinstance(trans_test.type, IntType):
            raise SemanticError(
                "The condition of an If expression must be an Integer",
                expression.test.position,
            )
        trans_then = translate_expression(value_env, type_env, level,
                                          expression.then_do, break_label)
        if expression.else_do is None:
            if not isinstance(trans_then.type, VoidType):
                raise SemanticError(
                    "Then branch of an If expression must produce no value" +
                    " when there is no Else branch",
                    expression.then_do.position,
                )
            return TypedExpression(
                IRT.if_expression(trans_test.expression, trans_then.expression,
                                  None),
                VoidType(),
            )
        trans_else = translate_expression(value_env, type_env, level,
                                          expression.else_do, break_label)
        if not are_types_equal(trans_then.type, trans_else.type):
            raise SemanticError(
                "Then and Else branches of an If expression must return values of the same type",
                expression.position,
            )
        # Special check in case one of the branches returns NilType and the other a RecordType.
        # In that case, we should return the RecordType since it's the most generic one.
        if isinstance(trans_then.type, NilType):
            returned_type = trans_else.type
        else:
            returned_type = trans_then.type
        return TypedExpression(
            IRT.if_expression(trans_test.expression, trans_then.expression,
                              trans_else.expression),
            returned_type,
        )

    if isinstance(expression, ast.WhileExp):
        # While: Check that the condition is an Integer and that the body produces no value.
        trans_test = translate_expression(value_env, type_env, level,
                                          expression.test, break_label)
        if not isinstance(trans_test.type, IntType):
            raise SemanticError(
                "The condition of a While expression must be an Integer",
                expression.position,
            )
        value_env.begin_scope(True)
        type_env.begin_scope(True)
        new_break_label = TempManager.new_label()
        trans_body = translate_expression(value_env, type_env, level,
                                          expression.body, new_break_label)
        if not isinstance(trans_body.type, VoidType):
            raise SemanticError("While body must produce no value",
                                expression.body.position)
        value_env.end_scope()
        type_env.end_scope()

        return TypedExpression(
            IRT.while_expression(trans_test.expression, trans_body.expression,
                                 new_break_label),
            VoidType(),
        )

    if isinstance(expression, ast.BreakExp):
        # Break: Make sure that the closest scope start is a While or a For loop.
        if not value_env.is_closest_scope_a_loop():
            raise SemanticError(
                "Break expression must be inside a For or While loop",
                expression.position,
            )
        return TypedExpression(IRT.break_expression(break_label), VoidType())

    if isinstance(expression, ast.ForExp):
        # For: Check that ends of the for variable iteration are Integers. Then add a non editable
        # Integer variable to the value env and evaluate the body, making sure it produces no value.
        trans_lo = translate_expression(value_env, type_env, level,
                                        expression.lo, break_label)
        if not isinstance(trans_lo.type, IntType):
            raise SemanticError(
                "Starting value for loop variable in a For expression must be an Integer",
                expression.lo.position,
            )
        trans_hi = translate_expression(value_env, type_env, level,
                                        expression.hi, break_label)
        if not isinstance(trans_hi.type, IntType):
            raise SemanticError(
                "Ending value for loop variable in a For expression must be an Integer",
                expression.hi.position,
            )
        value_env.begin_scope(True)
        type_env.begin_scope(True)
        new_break_label = TempManager.new_label()
        loop_variable_access = level.alloc_local(expression.escape)
        value_env.add(expression.var,
                      VariableEntry(loop_variable_access, IntType(), False))
        trans_body = translate_expression(value_env, type_env, level,
                                          expression.body, new_break_label)
        if not isinstance(trans_body.type, VoidType):
            raise SemanticError("For body must produce no value",
                                expression.body.position)
        value_env.end_scope()
        type_env.end_scope()
        return TypedExpression(
            IRT.for_expression(
                IRT.simple_variable(loop_variable_access, level),
                trans_lo.expression,
                trans_hi.expression,
                trans_body.expression,
                new_break_label,
            ),
            VoidType(),
        )

    if isinstance(expression, ast.LetExp):
        # Let: Go through all declarations and then evaluate the body of the expression. The return
        # type is the one of the last expression in the body (or Void if there are none)
        value_env.begin_scope()
        type_env.begin_scope()
        translated_declarations = []
        for declaration in expression.decs.declaration_list:
            translated_declarations.append(
                translate_declaration(value_env, type_env, declaration, level,
                                      break_label))
        trans_exp = translate_expression(value_env, type_env, level,
                                         expression.body, break_label)
        value_env.end_scope()
        type_env.end_scope()
        return TypedExpression(
            IRT.let_expression(translated_declarations, trans_exp.expression),
            trans_exp.type,
        )

    if isinstance(expression, ast.ArrayExp):
        # Array creation: Check that the declared type is an array type, that the size is an Integer
        # and that the initial value is of the type of the elements of the array.
        trans_typ = type_env.find(expression.type)
        if trans_typ is None:
            raise SemanticError(
                f"Undefined array type {expression.type}",
                expression.position,
            )
        if not isinstance(trans_typ, ArrayType):
            raise SemanticError(
                f"Trying to create an array of type {expression.type}, which is not an array type",
                expression.position,
            )
        trans_size = translate_expression(value_env, type_env, level,
                                          expression.size, break_label)
        if not isinstance(trans_size.type, IntType):
            raise SemanticError("Array size must be an Integer",
                                expression.size.position)
        trans_init = translate_expression(value_env, type_env, level,
                                          expression.init, break_label)
        if not are_types_equal(trans_typ.type, trans_init.type):
            raise SemanticError(
                "Array initial value must be of its declared type",
                expression.init.position,
            )

        return TypedExpression(
            IRT.array_expression(trans_size.expression, trans_init.expression),
            trans_typ,
        )

    if isinstance(expression, ast.EmptyExp):
        return TypedExpression(IRT.empty_expression(), VoidType())

    raise SemanticError("Unknown expression kind", expression.position)
예제 #10
0
파일: trace.py 프로젝트: Tomasfdel/Pythiger
def add_new_false_label(statements: List[Statement]):
    new_false_label = TempManager.new_label()
    statements[-1].false = new_false_label
    statements.append(Label(new_false_label))
    statements.append(Jump(Name(new_false_label), [new_false_label]))