Beispiel #1
0
def var_reference_to_ir2(var: ir3.VarReference, writer: StmtWriter):
    return ir2.VarReference(
        type=type_to_ir2(var.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 deconstructed_list_comprehension_expr_to_ir2(list_var: ir3.VarReference,
                                                 loop_var: ir2.VarReference,
                                                 result_elem_expr: ir2.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_ir2(result_elem_expr.type)
    helper_fun_writer = StmtWriter(writer.fun_writer,
                                   current_fun_args=writer.current_fun_args,
                                   current_fun_return_type=result_elem_type)
    helper_fun_writer.write_stmt(
        ir2.ReturnStmt(result=expr_to_ir2(result_elem_expr, helper_fun_writer),
                       error=None))
    forwarded_vars = ir2.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=ir2.AtomicTypeLiteral('void'))
            ]

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

    helper_fun_call = ir2.FunctionCall(fun=ir2.VarReference(
        name=helper_fun_name,
        type=ir2.FunctionType(argtypes=[var.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(
        ir2.ListComprehensionExpr(list_var=list_var,
                                  loop_var=var_reference_to_ir2(
                                      loop_var, writer),
                                  result_elem_expr=helper_fun_call))
Beispiel #3
0
def match_expr_to_ir2(match_expr: ir3.MatchExpr, writer: StmtWriter):
    matched_vars = [
        expr_to_ir2(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_args,
                                       type_to_ir2(match_expr.type))
        match_case_var = expr_to_ir2(match_case.expr, match_case_writer)
        match_case_writer.write_stmt(
            ir2.ReturnStmt(result=match_case_var, error=None))

        forwarded_vars = ir2.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 = [
            ir2.FunctionArgDecl(type=var.type, name=var.name)
            for var in forwarded_vars
        ]
        writer.write_function(
            ir2.FunctionDefn(
                name=match_fun_name,
                description=
                '(meta)function wrapping the code in a branch of a match expression',
                args=arg_decls,
                body=match_case_writer.stmts,
                return_type=match_case_var.type))
        match_fun_ref = ir2.VarReference(type=ir2.FunctionType(
            argtypes=[var.type for var in forwarded_vars],
            returns=match_case_var.type),
                                         name=match_fun_name,
                                         is_global_function=True,
                                         is_function_that_may_throw=True)

        match_cases.append(
            ir2.MatchCase(type_patterns=[
                type_pattern_expr_to_ir2(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
                          ],
                          expr=ir2.FunctionCall(fun=match_fun_ref,
                                                args=forwarded_vars)))

    return writer.new_var_for_expr_with_error_checking(
        ir2.MatchExpr(matched_vars, match_cases))
Beispiel #4
0
def _select_arbitrary_forwarded_arg(args: List[ir2.FunctionArgDecl]):
    for arg in args:
        if not isinstance(arg.type, ir2.FunctionType):
            selected_arg = arg
            break
    else:
        selected_arg = args[0]

    return ir2.VarReference(type=selected_arg.type,
                            name=selected_arg.name,
                            is_global_function=False,
                            is_function_that_may_throw=isinstance(
                                selected_arg.type, ir2.FunctionType))
Beispiel #5
0
def raise_stmt_to_ir2(raise_stmt: ir3.RaiseStmt, writer: StmtWriter):
    exception_expr = expr_to_ir2(raise_stmt.expr, writer)
    for context in writer.try_except_contexts:
        if context.caught_exception_type == exception_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 = ir2.VarReference(
                type=exception_expr.type,
                name=writer.obfuscate_identifier(
                    context.caught_exception_name),
                is_global_function=False,
                is_function_that_may_throw=False)
            writer.write_stmt(
                ir2.Assignment(lhs=exception_var, rhs=exception_expr))
            handler_result_var = writer.new_var(
                context.except_fun_call_expr.type)
            handler_error_var = writer.new_var(ir2.ErrorOrVoidType())
            writer.write_stmt(
                ir2.Assignment(lhs=handler_result_var,
                               lhs2=handler_error_var,
                               rhs=context.except_fun_call_expr))
            writer.write_stmt(
                ir2.ReturnStmt(result=handler_result_var,
                               error=handler_error_var))
            break
    else:
        writer.write_stmt(ir2.ReturnStmt(result=None, error=exception_expr))
Beispiel #6
0
def try_except_stmt_to_ir2(try_except_stmt: ir3.TryExcept,
                           then_stmts: List[ir3.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_args,
                                       writer.current_fun_return_type)
        stmts_to_ir2(then_stmts, then_stmts_writer)

        then_fun_forwarded_vars = ir2.get_unique_free_variables_in_stmts(
            then_stmts_writer.stmts)
        then_fun_defn = ir2.FunctionDefn(
            name=writer.new_id(),
            description=
            '(meta)function wrapping the code after a try-except statement',
            args=[
                ir2.FunctionArgDecl(type=var.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 = ir2.VarReference(type=ir2.FunctionType(
            argtypes=[arg.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 = ir2.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_args,
                                     writer.current_fun_return_type)
    stmts_to_ir2(try_except_stmt.except_body, except_stmts_writer)
    if then_fun_call_expr and not (
            try_except_stmt.except_body and
            try_except_stmt.except_body[-1].get_return_type().always_returns):
        except_stmts_writer.write_stmt(
            ir2.ReturnStmt(
                result=except_stmts_writer.
                new_var_for_expr_with_error_checking(then_fun_call_expr),
                error=None))

    except_fun_forwarded_vars = ir2.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 = ir2.FunctionDefn(
        name=writer.new_id(),
        description='(meta)function wrapping the code in an except block',
        args=[
            ir2.FunctionArgDecl(type=var.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 = ir2.VarReference(type=ir2.FunctionType(
        argtypes=[arg.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 = ir2.FunctionCall(fun=except_fun_ref,
                                            args=except_fun_forwarded_vars)

    with writer.enter_try_except_context(
            TryExceptContext(
                type_to_ir2(try_except_stmt.caught_exception_type),
                try_except_stmt.caught_exception_name, except_fun_call_expr)):
        stmts_to_ir2(try_except_stmt.try_body, writer)

    if then_fun_call_expr and not (
            try_except_stmt.try_body
            and try_except_stmt.try_body[-1].get_return_type().always_returns):
        writer.write_stmt(
            ir2.ReturnStmt(result=writer.new_var_for_expr_with_error_checking(
                then_fun_call_expr),
                           error=None))
Beispiel #7
0
 def new_var(self, type: ir2.ExprType, is_global_function: bool = False):
     return ir2.VarReference(type=type,
                             name=self.new_id(),
                             is_global_function=is_global_function,
                             is_function_that_may_throw=isinstance(
                                 type, ir2.FunctionType))
Beispiel #8
0
    def new_var_for_expr_with_error_checking(self, expr: ir2.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.type)
            error_var = self.fun_writer.new_var(ir2.ErrorOrVoidType())
            self.write_stmt(ir2.Assignment(lhs=x_var, lhs2=error_var,
                                           rhs=expr))
            b_var = self.new_var_for_expr(
                ir2.FunctionCall(fun=self.fun_writer.is_error_fun_ref,
                                 args=[error_var]))

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

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

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

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

            # x = <expr>

            x_var = self.fun_writer.new_var(expr.type)
            self.write_stmt(ir2.Assignment(lhs=x_var, rhs=expr))
            return x_var