Beispiel #1
0
def var_reference_to_ir1(var: ir2.VarReference, writer: StmtWriter):
    return ir1.VarReference(
        expr_type=type_to_ir1(var.expr_type),
        name=var.name
        if var.is_global_function else writer.obfuscate_identifier(var.name),
        is_global_function=var.is_global_function,
        is_function_that_may_throw=var.is_function_that_may_throw)
Beispiel #2
0
 def new_var(self,
             expr_type: ir1.ExprType,
             is_global_function: bool = False):
     return ir1.VarReference(expr_type=expr_type,
                             name=self.new_id(),
                             is_global_function=is_global_function,
                             is_function_that_may_throw=isinstance(
                                 expr_type, ir1.FunctionType))
Beispiel #3
0
def _select_arbitrary_forwarded_arg(args: List[ir1.FunctionArgDecl]):
    for arg in args:
        if not isinstance(arg.expr_type, ir1.FunctionType):
            selected_arg = arg
            break
    else:
        selected_arg = args[0]

    return ir1.VarReference(expr_type=selected_arg.expr_type,
                            name=selected_arg.name,
                            is_global_function=False,
                            is_function_that_may_throw=isinstance(
                                selected_arg.expr_type, ir1.FunctionType))
Beispiel #4
0
def raise_stmt_to_ir1(raise_stmt: ir2.RaiseStmt, writer: StmtWriter):
    exception_expr = expr_to_ir1(raise_stmt.expr, writer)
    for context in writer.try_except_contexts:
        if context.caught_exception_type == exception_expr.expr_type:
            # try:
            #   raise f(x)
            # except MyError as e:
            #   ...
            #
            # Becomes:
            #
            # def handler(e, ...) :
            #    ...
            #
            # e = f(x)
            # result, err = handler(e, ...)
            # return result, err
            exception_var = ir1.VarReference(
                expr_type=exception_expr.expr_type,
                name=writer.obfuscate_identifier(
                    context.caught_exception_name),
                is_global_function=False,
                is_function_that_may_throw=False)
            writer.write_stmt(
                ir1.Assignment(lhs=exception_var, rhs=exception_expr))
            handler_result_var = writer.new_var(
                context.except_fun_call_expr.expr_type)
            handler_error_var = writer.new_var(ir1.ErrorOrVoidType())
            writer.write_stmt(
                ir1.Assignment(lhs=handler_result_var,
                               lhs2=handler_error_var,
                               rhs=context.except_fun_call_expr))
            writer.write_stmt(
                ir1.ReturnStmt(result=handler_result_var,
                               error=handler_error_var))
            break
    else:
        writer.write_stmt(ir1.ReturnStmt(result=None, error=exception_expr))
Beispiel #5
0
def try_except_stmt_to_ir1(try_except_stmt: ir2.TryExcept,
                           then_stmts: List[ir2.Stmt], writer: StmtWriter):
    # try:
    #   x = f()
    #   y = g()
    # except MyError as e:
    #   y = e.x
    #   if b:
    #     return 5
    # z = y + 3
    # return z
    #
    # Becomes:
    #
    # def then_fun(y):
    #   z = y + 3
    #   return z
    #
    # def except_fun(e, b):
    #   y = e.x
    #   if b:
    #     return 5
    #   x0, err0 = then_fun(y)
    #   b0 = is_error(err0)
    #   if b0:
    #     return None, err0
    #   return x0, None
    #
    # x, f_err = f()
    # f_b = is_error(f_err)
    # if f_b:
    #   b0 = is_instance_of_MyError(f_err)
    #   if b0:
    #     e = f_err  # type: MyError
    #     res, err = except_fun(...)
    #     return res, err
    #   return None, f_err
    # y, g_err = g()
    # g_b = is_error(g_err)
    # if g_b:
    #   b0 = is_instance_of_MyError(g_err)
    #   if b0:
    #     e = g_err  # type: MyError
    #     res, err = except_fun(...)
    #     return res, err
    #   return None, g_err
    # res, err = then_fun()
    # return res, err

    if then_stmts:
        then_stmts_writer = StmtWriter(writer.fun_writer,
                                       writer.current_fun_name,
                                       writer.current_fun_args,
                                       writer.current_fun_return_type,
                                       writer.try_except_contexts)
        stmts_to_ir1(then_stmts, then_stmts_writer)

        then_fun_forwarded_vars = get_unique_free_variables_in_stmts(
            then_stmts_writer.stmts)
        if not then_fun_forwarded_vars:
            then_fun_forwarded_vars = [
                _select_arbitrary_forwarded_arg(writer.current_fun_args)
            ]

        then_fun_defn = ir1.FunctionDefn(
            name=writer.new_id(),
            description=
            '(meta)function wrapping the code after a try-except statement from the function %s'
            % writer.current_fun_name,
            args=[
                ir1.FunctionArgDecl(expr_type=var.expr_type, name=var.name)
                for var in then_fun_forwarded_vars
            ],
            body=then_stmts_writer.stmts,
            return_type=writer.current_fun_return_type)
        writer.write_function(then_fun_defn)

        then_fun_ref = ir1.VarReference(expr_type=ir1.FunctionType(
            argtypes=[arg.expr_type for arg in then_fun_defn.args],
            returns=then_fun_defn.return_type),
                                        name=then_fun_defn.name,
                                        is_global_function=True,
                                        is_function_that_may_throw=True)
        then_fun_call_expr = ir1.FunctionCall(fun=then_fun_ref,
                                              args=then_fun_forwarded_vars)
    else:
        then_fun_call_expr = None

    except_stmts_writer = StmtWriter(writer.fun_writer,
                                     writer.current_fun_name,
                                     writer.current_fun_args,
                                     writer.current_fun_return_type,
                                     writer.try_except_contexts)
    stmts_to_ir1(try_except_stmt.except_body, except_stmts_writer)
    if then_fun_call_expr and not get_return_type(
            try_except_stmt.except_body).always_returns:
        except_stmts_writer.write_stmt(
            ir1.ReturnStmt(
                result=except_stmts_writer.
                new_var_for_expr_with_error_checking(then_fun_call_expr),
                error=None))

    except_fun_forwarded_vars = get_unique_free_variables_in_stmts(
        except_stmts_writer.stmts)
    if not except_fun_forwarded_vars:
        except_fun_forwarded_vars = [
            _select_arbitrary_forwarded_arg(writer.current_fun_args)
        ]

    except_fun_defn = ir1.FunctionDefn(
        name=writer.new_id(),
        description=
        '(meta)function wrapping the code in an except block from the function %s'
        % writer.current_fun_name,
        args=[
            ir1.FunctionArgDecl(expr_type=var.expr_type, name=var.name)
            for var in except_fun_forwarded_vars
        ],
        body=except_stmts_writer.stmts,
        return_type=writer.current_fun_return_type)
    writer.write_function(except_fun_defn)

    except_fun_ref = ir1.VarReference(expr_type=ir1.FunctionType(
        argtypes=[arg.expr_type for arg in except_fun_defn.args],
        returns=except_fun_defn.return_type),
                                      name=except_fun_defn.name,
                                      is_global_function=True,
                                      is_function_that_may_throw=True)
    except_fun_call_expr = ir1.FunctionCall(fun=except_fun_ref,
                                            args=except_fun_forwarded_vars)

    with writer.enter_try_except_context(
            TryExceptContext(
                type_to_ir1(try_except_stmt.caught_exception_type),
                try_except_stmt.caught_exception_name, except_fun_call_expr)):
        stmts_to_ir1(try_except_stmt.try_body, writer)

    if then_fun_call_expr and not get_return_type(
            try_except_stmt.try_body).always_returns:
        writer.write_stmt(
            ir1.ReturnStmt(result=writer.new_var_for_expr_with_error_checking(
                then_fun_call_expr),
                           error=None))
Beispiel #6
0
def deconstructed_list_comprehension_expr_to_ir1(list_var: ir2.VarReference,
                                                 loop_var: ir1.VarReference,
                                                 result_elem_expr: ir1.Expr,
                                                 writer: StmtWriter):
    # [f(x, y) * 2
    #  for x in l]
    #
    # Becomes:
    #
    # def g(x, y):
    #   return f(x, y) * 2  # (in fact, this will be converted further)
    #
    # [g(x, y)
    #  for x in l]

    result_elem_type = type_to_ir1(result_elem_expr.expr_type)
    helper_fun_writer = StmtWriter(
        writer.fun_writer,
        current_fun_name=writer.current_fun_name,
        current_fun_args=writer.current_fun_args,
        current_fun_return_type=result_elem_type,
        # We can't forward the try_except_contexts here because the return type is different,
        # but it's ok because a list comprehension can't contain "raise" statements (while
        # of course it can throw indirectly).
        try_except_contexts=[])
    helper_fun_writer.write_stmt(
        ir1.ReturnStmt(result=expr_to_ir1(result_elem_expr, helper_fun_writer),
                       error=None))
    forwarded_vars = get_unique_free_variables_in_stmts(
        helper_fun_writer.stmts)
    if not forwarded_vars:
        if writer.current_fun_args:
            forwarded_vars = [
                _select_arbitrary_forwarded_arg(writer.current_fun_args)
            ]
        else:
            forwarded_vars = [
                writer.new_var_for_expr(expr=ir1.AtomicTypeLiteral('void'))
            ]

    helper_fun_name = writer.new_id()
    writer.write_function(
        ir1.FunctionDefn(
            name=helper_fun_name,
            description=
            '(meta)function wrapping the result expression in a list/set comprehension from the function %s'
            % writer.current_fun_name,
            args=[
                ir1.FunctionArgDecl(expr_type=var.expr_type, name=var.name)
                for var in forwarded_vars
            ],
            body=helper_fun_writer.stmts,
            return_type=result_elem_type))

    helper_fun_call = ir1.FunctionCall(fun=ir1.VarReference(
        name=helper_fun_name,
        expr_type=ir1.FunctionType(
            argtypes=[var.expr_type for var in forwarded_vars],
            returns=result_elem_type),
        is_global_function=True,
        is_function_that_may_throw=True),
                                       args=forwarded_vars)
    return writer.new_var_for_expr_with_error_checking(
        ir1.ListComprehensionExpr(list_var=list_var,
                                  loop_var=var_reference_to_ir1(
                                      loop_var, writer),
                                  result_elem_expr=helper_fun_call))
Beispiel #7
0
def match_expr_to_ir1(match_expr: ir2.MatchExpr, writer: StmtWriter):
    matched_vars = [
        expr_to_ir1(expr, writer) for expr in match_expr.matched_exprs
    ]

    match_cases = []
    for match_case in match_expr.match_cases:
        match_case_writer = StmtWriter(writer.fun_writer,
                                       writer.current_fun_name,
                                       writer.current_fun_args,
                                       type_to_ir1(match_expr.expr_type),
                                       writer.try_except_contexts)
        match_case_var = expr_to_ir1(match_case.expr, match_case_writer)
        match_case_writer.write_stmt(
            ir1.ReturnStmt(result=match_case_var, error=None))

        forwarded_vars = get_unique_free_variables_in_stmts(
            match_case_writer.stmts)

        if not forwarded_vars:
            forwarded_vars = [
                _select_arbitrary_forwarded_arg(writer.current_fun_args)
            ]

        match_fun_name = writer.new_id()
        arg_decls = [
            ir1.FunctionArgDecl(expr_type=var.expr_type, name=var.name)
            for var in forwarded_vars
        ]
        writer.write_function(
            ir1.FunctionDefn(
                name=match_fun_name,
                description=
                '(meta)function wrapping the code in a branch of a match expression from the function %s'
                % writer.current_fun_name,
                args=arg_decls,
                body=match_case_writer.stmts,
                return_type=match_case_var.expr_type))
        match_fun_ref = ir1.VarReference(expr_type=ir1.FunctionType(
            argtypes=[var.expr_type for var in forwarded_vars],
            returns=match_case_var.expr_type),
                                         name=match_fun_name,
                                         is_global_function=True,
                                         is_function_that_may_throw=True)

        match_cases.append(
            ir1.MatchCase(
                type_patterns=[
                    type_pattern_expr_to_ir1(type_pattern, writer)
                    for type_pattern in match_case.type_patterns
                ],
                matched_var_names=[
                    writer.obfuscate_identifier(var_name)
                    for var_name in match_case.matched_var_names
                ],
                matched_variadic_var_names=[
                    writer.obfuscate_identifier(var_name)
                    for var_name in match_case.matched_variadic_var_names
                ],
                expr=ir1.FunctionCall(fun=match_fun_ref, args=forwarded_vars)))

    return writer.new_var_for_expr_with_error_checking(
        ir1.MatchExpr(matched_vars, match_cases))
Beispiel #8
0
    def new_var_for_expr_with_error_checking(self, expr: ir1.Expr):
        if self.current_fun_return_type:
            # x, err = <expr>
            # b = is_error(err)
            # if b:
            #   b1 = isinstance(err, MyError1)
            #   if b1:
            #     e1 = err  # type: MyError1
            #     res1, err1 = except_handler_fun1(...)
            #     return res1, err1
            #   ...
            #   bN = isinstance(err, MyErrorN)
            #   if bN:
            #     eN = err  # type: MyErrorN
            #     resN, errN = except_handler_funN(...)
            #     return resN, errN
            #   return None, err

            x_var = self.fun_writer.new_var(expr.expr_type)
            error_var = self.fun_writer.new_var(ir1.ErrorOrVoidType())
            self.write_stmt(ir1.Assignment(lhs=x_var, lhs2=error_var,
                                           rhs=expr))
            b_var = self.new_var_for_expr(
                ir1.FunctionCall(fun=self.fun_writer.is_error_fun_ref,
                                 args=[error_var]))

            outer_if_branch_writer = StmtWriter(
                self.fun_writer,
                self.current_fun_name,
                self.current_fun_args,
                self.current_fun_return_type,
                try_except_contexts=self.try_except_contexts)
            for context in self.try_except_contexts:
                if_branch_writer = StmtWriter(
                    self.fun_writer,
                    self.current_fun_name,
                    self.current_fun_args,
                    self.current_fun_return_type,
                    try_except_contexts=self.try_except_contexts)
                if_branch_writer.write_stmt(
                    ir1.Assignment(
                        lhs=ir1.VarReference(
                            expr_type=context.caught_exception_type,
                            name=self.obfuscate_identifier(
                                context.caught_exception_name),
                            is_global_function=False,
                            is_function_that_may_throw=False),
                        rhs=ir1.SafeUncheckedCast(
                            error_var,
                            expr_type=context.caught_exception_type)))
                res_i = if_branch_writer.new_var(
                    expr_type=self.current_fun_return_type)
                err_i = if_branch_writer.new_var(
                    expr_type=ir1.ErrorOrVoidType())
                if_branch_writer.write_stmt(
                    ir1.Assignment(lhs=res_i,
                                   lhs2=err_i,
                                   rhs=context.except_fun_call_expr))
                if_branch_writer.write_stmt(
                    ir1.ReturnStmt(result=res_i, error=err_i))

                b_i = outer_if_branch_writer.new_var_for_expr(
                    ir1.IsInstanceExpr(error_var,
                                       context.caught_exception_type))
                outer_if_branch_writer.write_stmt(
                    ir1.IfStmt(cond=b_i,
                               if_stmts=if_branch_writer.stmts,
                               else_stmts=[]))

            outer_if_branch_writer.write_stmt(
                ir1.ReturnStmt(result=None, error=error_var))

            self.write_stmt(
                ir1.IfStmt(cond=b_var,
                           if_stmts=outer_if_branch_writer.stmts,
                           else_stmts=[]))
            return x_var
        else:
            # This statement is at top-level.

            # x, err = <expr>

            x_var = self.fun_writer.new_var(expr.expr_type)
            error_var = self.fun_writer.new_var(ir1.ErrorOrVoidType())
            self.write_stmt(ir1.Assignment(lhs=x_var, lhs2=error_var,
                                           rhs=expr))
            self.write_stmt(ir1.CheckIfError(error_var))
            return x_var