Ejemplo n.º 1
0
def match_expr_to_ir(match_expr: highir.MatchExpr, writer: StmtWriter):
    matched_vars = [
        expr_to_ir(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,
                                       type_to_ir(match_expr.type))
        match_case_var = expr_to_ir(match_case.expr, match_case_writer)
        match_case_writer.write_stmt(
            ir.ReturnStmt(result=match_case_var, error=None))

        forwarded_vars = ir.get_unique_free_variables_in_stmts(
            match_case_writer.stmts)

        match_fun_name = writer.new_id()
        writer.write_function(
            ir.FunctionDefn(name=match_fun_name,
                            args=[
                                ir.FunctionArgDecl(type=var.type,
                                                   name=var.name)
                                for var in forwarded_vars
                            ],
                            body=match_case_writer.stmts,
                            return_type=match_case_var.type))
        match_fun_ref = ir.VarReference(type=ir.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)
        replacements = {
            var_name: writer.obfuscate_identifier(var_name)
            for var_name in match_case.matched_var_names
        }

        match_cases.append(
            ir.MatchCase(type_patterns=[
                utils.replace_identifiers(type_pattern, replacements)
                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=ir.FunctionCall(fun=match_fun_ref,
                                              args=forwarded_vars)))

    return writer.new_var_for_expr_with_error_checking(
        ir.MatchExpr(matched_vars, match_cases))
Ejemplo n.º 2
0
def raise_stmt_to_ir(raise_stmt: highir.RaiseStmt, writer: StmtWriter):
    exception_expr = expr_to_ir(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 = ir.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(
                ir.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(ir.ErrorOrVoidType())
            writer.write_stmt(
                ir.Assignment(lhs=handler_result_var,
                              lhs2=handler_error_var,
                              rhs=context.except_fun_call_expr))
            writer.write_stmt(
                ir.ReturnStmt(result=handler_result_var,
                              error=handler_error_var))
            break
    else:
        writer.write_stmt(ir.ReturnStmt(result=None, error=exception_expr))
Ejemplo n.º 3
0
def list_comprehension_expr_to_ir(expr: highir.ListComprehension,
                                  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]

    l_var = expr_to_ir(expr.list_expr, writer)

    result_elem_type = type_to_ir(expr.result_elem_expr.type)
    helper_fun_writer = StmtWriter(writer.fun_writer,
                                   current_fun_return_type=result_elem_type)
    helper_fun_writer.write_stmt(
        ir.ReturnStmt(result=expr_to_ir(expr.result_elem_expr,
                                        helper_fun_writer),
                      error=None))
    forwarded_vars = ir.get_unique_free_variables_in_stmts(
        helper_fun_writer.stmts)
    helper_fun_name = writer.new_id()
    writer.write_function(
        ir.FunctionDefn(name=helper_fun_name,
                        args=[
                            ir.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 = ir.FunctionCall(fun=ir.VarReference(
        name=helper_fun_name,
        type=ir.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(
        ir.ListComprehensionExpr(list_var=l_var,
                                 loop_var=var_reference_to_ir(
                                     expr.loop_var, writer),
                                 result_elem_expr=helper_fun_call))
Ejemplo n.º 4
0
    def _create_is_error_fun_defn(self):
        # def is_error(x: ErrorOrVoid):
        #   v = Type('void')
        #   b = (x == v)
        #   b2 = not b
        #   return b2

        stmt_writer = StmtWriter(self, current_fun_return_type=ir.BoolType())
        x_var = self.new_var(type=ir.ErrorOrVoidType())
        v_var = stmt_writer.new_var_for_expr(
            ir.TypeLiteral(cpp_type='void', args=dict()))
        b_var = stmt_writer.new_var_for_expr(
            ir.EqualityComparison(lhs=x_var, rhs=v_var))
        b2_var = stmt_writer.new_var_for_expr(ir.NotExpr(b_var))
        stmt_writer.write_stmt(ir.ReturnStmt(result=b2_var, error=None))

        return ir.FunctionDefn(
            name=self.is_error_fun_ref.name,
            args=[ir.FunctionArgDecl(type=x_var.type, name=x_var.name)],
            body=stmt_writer.stmts,
            return_type=ir.BoolType())
Ejemplo n.º 5
0
def return_stmt_to_ir(return_stmt: highir.ReturnStmt, writer: StmtWriter):
    writer.write_stmt(
        ir.ReturnStmt(result=expr_to_ir(return_stmt.expr, writer), error=None))
Ejemplo n.º 6
0
def try_except_stmt_to_ir(try_except_stmt: highir.TryExcept,
                          then_stmts: List[highir.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_return_type)
        stmts_to_ir(then_stmts, then_stmts_writer)

        then_fun_forwarded_vars = ir.get_unique_free_variables_in_stmts(
            then_stmts_writer.stmts)
        then_fun_defn = ir.FunctionDefn(
            name=writer.new_id(),
            args=[
                ir.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 = ir.VarReference(type=ir.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 = ir.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_return_type)
    stmts_to_ir(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(
            ir.ReturnStmt(
                result=except_stmts_writer.
                new_var_for_expr_with_error_checking(then_fun_call_expr),
                error=None))

    except_fun_forwarded_vars = ir.get_unique_free_variables_in_stmts(
        except_stmts_writer.stmts)
    except_fun_defn = ir.FunctionDefn(
        name=writer.new_id(),
        args=[
            ir.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 = ir.VarReference(type=ir.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 = ir.FunctionCall(fun=except_fun_ref,
                                           args=except_fun_forwarded_vars)

    with writer.enter_try_except_context(
            TryExceptContext(type_to_ir(try_except_stmt.caught_exception_type),
                             try_except_stmt.caught_exception_name,
                             except_fun_call_expr)):
        stmts_to_ir(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(
            ir.ReturnStmt(result=writer.new_var_for_expr_with_error_checking(
                then_fun_call_expr),
                          error=None))
Ejemplo n.º 7
0
    def new_var_for_expr_with_error_checking(self, expr: ir.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(ir.ErrorOrVoidType())
            self.write_stmt(ir.Assignment(lhs=x_var, lhs2=error_var, rhs=expr))
            b_var = self.new_var_for_expr(
                ir.FunctionCall(fun=self.fun_writer.is_error_fun_ref,
                                args=[error_var]))

            outer_if_branch_writer = StmtWriter(self.fun_writer,
                                                self.current_fun_return_type)
            for context in self.try_except_contexts:
                if_branch_writer = StmtWriter(self.fun_writer,
                                              self.current_fun_return_type)
                if_branch_writer.write_stmt(
                    ir.Assignment(lhs=ir.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=ir.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=ir.ErrorOrVoidType())
                if_branch_writer.write_stmt(
                    ir.Assignment(lhs=res_i,
                                  lhs2=err_i,
                                  rhs=context.except_fun_call_expr))
                if_branch_writer.write_stmt(
                    ir.ReturnStmt(result=res_i, error=err_i))

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

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

            self.write_stmt(
                ir.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(ir.Assignment(lhs=x_var, rhs=expr))
            return x_var