def type_to_ir1(expr_type: ir2.ExprType): if isinstance(expr_type, ir2.BoolType): return ir1.BoolType() elif isinstance(expr_type, ir2.IntType): return ir1.IntType() elif isinstance(expr_type, ir2.TypeType): return ir1.TypeType() elif isinstance(expr_type, ir2.BottomType): return ir1.BottomType() elif isinstance(expr_type, ir2.ListType): return ir1.ListType(elem_type=type_to_ir1(expr_type.elem_type)) elif isinstance(expr_type, ir2.SetType): return ir1.ListType(elem_type=type_to_ir1(expr_type.elem_type)) elif isinstance(expr_type, ir2.FunctionType): return ir1.FunctionType( argtypes=[type_to_ir1(arg) for arg in expr_type.argtypes], returns=type_to_ir1(expr_type.returns)) elif isinstance(expr_type, ir2.CustomType): return ir1.CustomType(name=expr_type.name, arg_types=[ ir1.CustomTypeArgDecl(name=arg.name, expr_type=type_to_ir1( arg.expr_type)) for arg in expr_type.arg_types ]) else: raise NotImplementedError('Unexpected type: %s' % str(expr_type.__class__))
def __init__(self, identifier_generator: Iterator[str]): self.identifier_generator = identifier_generator self.is_error_fun_ref = self.new_var(ir1.FunctionType( argtypes=[ir1.ErrorOrVoidType()], returns=ir1.BoolType()), is_global_function=True) self.function_defns = [self._create_is_error_fun_defn()] self.obfuscated_identifiers_by_identifier: Dict[ str, str] = defaultdict(lambda: self.new_id())
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))