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))
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))
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))
def _create_is_error_fun_defn(self): # def is_error(x: ErrorOrVoid): # v = Type('void') # b = (x == v) # b2 = not b # return b2 x_var = self.new_var(type=ir2.ErrorOrVoidType()) arg_decls = [ir2.FunctionArgDecl(type=x_var.type, name=x_var.name)] stmt_writer = StmtWriter(self, current_fun_return_type=ir2.BoolType(), current_fun_args=arg_decls) v_var = stmt_writer.new_var_for_expr(ir2.AtomicTypeLiteral('void')) b_var = stmt_writer.new_var_for_expr( ir2.EqualityComparison(lhs=x_var, rhs=v_var)) b2_var = stmt_writer.new_var_for_expr(ir2.NotExpr(b_var)) stmt_writer.write_stmt(ir2.ReturnStmt(result=b2_var, error=None)) return ir2.FunctionDefn(name=self.is_error_fun_ref.name, description='The is_error (meta)function', args=arg_decls, body=stmt_writer.stmts, return_type=ir2.BoolType())
def return_stmt_to_ir2(return_stmt: ir3.ReturnStmt, writer: StmtWriter): writer.write_stmt( ir2.ReturnStmt(result=expr_to_ir2(return_stmt.expr, writer), error=None))
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))
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