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)
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))
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))
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))
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))
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))
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))
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