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