def setup_non_ext_dict(builder: IRBuilder, cdef: ClassDef, metaclass: Value, bases: Value) -> Value: """ Initialize the class dictionary for a non-extension class. This class dictionary is passed to the metaclass constructor. """ # Check if the metaclass defines a __prepare__ method, and if so, call it. has_prepare = builder.primitive_op(py_hasattr_op, [metaclass, builder.load_static_unicode('__prepare__')], cdef.line) non_ext_dict = builder.alloc_temp(dict_rprimitive) true_block, false_block, exit_block, = BasicBlock(), BasicBlock(), BasicBlock() builder.add_bool_branch(has_prepare, true_block, false_block) builder.activate_block(true_block) cls_name = builder.load_static_unicode(cdef.name) prepare_meth = builder.py_get_attr(metaclass, '__prepare__', cdef.line) prepare_dict = builder.py_call(prepare_meth, [cls_name, bases], cdef.line) builder.assign(non_ext_dict, prepare_dict, cdef.line) builder.goto(exit_block) builder.activate_block(false_block) builder.assign(non_ext_dict, builder.primitive_op(new_dict_op, [], cdef.line), cdef.line) builder.goto(exit_block) builder.activate_block(exit_block) return non_ext_dict
def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr) -> Value: """Generate IR for an arbitrary call of form e.m(...). This can also deal with calls to module-level functions. """ if builder.is_native_ref_expr(callee): # Call to module-level native function or such return translate_call(builder, expr, callee) elif (isinstance(callee.expr, RefExpr) and isinstance(callee.expr.node, TypeInfo) and callee.expr.node in builder.mapper.type_to_ir and builder.mapper.type_to_ir[callee.expr.node].has_method(callee.name)): # Call a method via the *class* assert isinstance(callee.expr.node, TypeInfo) ir = builder.mapper.type_to_ir[callee.expr.node] decl = ir.method_decl(callee.name) args = [] arg_kinds, arg_names = expr.arg_kinds[:], expr.arg_names[:] # Add the class argument for class methods in extension classes if decl.kind == FUNC_CLASSMETHOD and ir.is_ext_class: args.append( builder.load_native_type_object(callee.expr.node.fullname)) arg_kinds.insert(0, ARG_POS) arg_names.insert(0, None) args += [builder.accept(arg) for arg in expr.args] if ir.is_ext_class: return builder.builder.call(decl, args, arg_kinds, arg_names, expr.line) else: obj = builder.accept(callee.expr) return builder.gen_method_call(obj, callee.name, args, builder.node_type(expr), expr.line, expr.arg_kinds, expr.arg_names) elif builder.is_module_member_expr(callee): # Fall back to a PyCall for non-native module calls function = builder.accept(callee) args = [builder.accept(arg) for arg in expr.args] return builder.py_call(function, args, expr.line, arg_kinds=expr.arg_kinds, arg_names=expr.arg_names) else: receiver_typ = builder.node_type(callee.expr) # If there is a specializer for this method name/type, try calling it. if (callee.name, receiver_typ) in specializers: val = specializers[callee.name, receiver_typ](builder, expr, callee) if val is not None: return val obj = builder.accept(callee.expr) args = [builder.accept(arg) for arg in expr.args] return builder.gen_method_call(obj, callee.name, args, builder.node_type(expr), expr.line, expr.arg_kinds, expr.arg_names)
def transform_with(builder: IRBuilder, expr: Expression, target: Optional[Lvalue], body: GenFunc, line: int) -> None: # This is basically a straight transcription of the Python code in PEP 343. # I don't actually understand why a bunch of it is the way it is. # We could probably optimize the case where the manager is compiled by us, # but that is not our common case at all, so. mgr_v = builder.accept(expr) typ = builder.primitive_op(type_op, [mgr_v], line) exit_ = builder.maybe_spill(builder.py_get_attr(typ, '__exit__', line)) value = builder.py_call( builder.py_get_attr(typ, '__enter__', line), [mgr_v], line ) mgr = builder.maybe_spill(mgr_v) exc = builder.maybe_spill_assignable(builder.primitive_op(true_op, [], -1)) def try_body() -> None: if target: builder.assign(builder.get_assignment_target(target), value, line) body() def except_body() -> None: builder.assign(exc, builder.primitive_op(false_op, [], -1), line) out_block, reraise_block = BasicBlock(), BasicBlock() builder.add_bool_branch( builder.py_call(builder.read(exit_), [builder.read(mgr)] + get_sys_exc_info(builder), line), out_block, reraise_block ) builder.activate_block(reraise_block) builder.primitive_op(reraise_exception_op, [], NO_TRACEBACK_LINE_NO) builder.add(Unreachable()) builder.activate_block(out_block) def finally_body() -> None: out_block, exit_block = BasicBlock(), BasicBlock() builder.add( Branch(builder.read(exc), exit_block, out_block, Branch.BOOL_EXPR) ) builder.activate_block(exit_block) none = builder.none_object() builder.py_call( builder.read(exit_), [builder.read(mgr), none, none, none], line ) builder.goto_and_activate(out_block) transform_try_finally_stmt( builder, lambda: transform_try_except(builder, try_body, [(None, None, except_body)], None, line), finally_body )
def translate_call(builder: IRBuilder, expr: CallExpr, callee: Expression) -> Value: # The common case of calls is refexprs if isinstance(callee, RefExpr): return translate_refexpr_call(builder, expr, callee) function = builder.accept(callee) args = [builder.accept(arg) for arg in expr.args] return builder.py_call(function, args, expr.line, arg_kinds=expr.arg_kinds, arg_names=expr.arg_names)
def load_decorated_class(builder: IRBuilder, cdef: ClassDef, type_obj: Value) -> Value: """ Given a decorated ClassDef and a register containing a non-extension representation of the ClassDef created via the type constructor, applies the corresponding decorator functions on that decorated ClassDef and returns a register containing the decorated ClassDef. """ decorators = cdef.decorators dec_class = type_obj for d in reversed(decorators): decorator = d.accept(builder.visitor) assert isinstance(decorator, Value) dec_class = builder.py_call(decorator, [dec_class], dec_class.line) return dec_class
def load_non_ext_class(builder: IRBuilder, ir: ClassIR, non_ext: NonExtClassInfo, line: int) -> Value: cls_name = builder.load_static_unicode(ir.name) finish_non_ext_dict(builder, non_ext, line) class_type_obj = builder.py_call( non_ext.metaclass, [cls_name, non_ext.bases, non_ext.dict], line ) return class_type_obj
def transform_super_expr(builder: IRBuilder, o: SuperExpr) -> Value: # warning(builder, 'can not optimize super() expression', o.line) sup_val = builder.load_module_attr_by_fullname('builtins.super', o.line) if o.call.args: args = [builder.accept(arg) for arg in o.call.args] else: assert o.info is not None typ = builder.load_native_type_object(o.info.fullname) ir = builder.mapper.type_to_ir[o.info] iter_env = iter(builder.environment.indexes) vself = next(iter_env) # grab first argument if builder.fn_info.is_generator: # grab sixth argument (see comment in translate_super_method_call) self_targ = list(builder.environment.symtable.values())[6] vself = builder.read(self_targ, builder.fn_info.fitem.line) elif not ir.is_ext_class: vself = next( iter_env) # second argument is self if non_extension class args = [typ, vself] res = builder.py_call(sup_val, args, o.line) return builder.py_get_attr(res, o.name, o.line)
def transform_assert_stmt(builder: IRBuilder, a: AssertStmt) -> None: if builder.options.strip_asserts: return cond = builder.accept(a.expr) ok_block, error_block = BasicBlock(), BasicBlock() builder.add_bool_branch(cond, ok_block, error_block) builder.activate_block(error_block) if a.msg is None: # Special case (for simpler generated code) builder.add(RaiseStandardError(RaiseStandardError.ASSERTION_ERROR, None, a.line)) elif isinstance(a.msg, StrExpr): # Another special case builder.add(RaiseStandardError(RaiseStandardError.ASSERTION_ERROR, a.msg.value, a.line)) else: # The general case -- explicitly construct an exception instance message = builder.accept(a.msg) exc_type = builder.load_module_attr_by_fullname('builtins.AssertionError', a.line) exc = builder.py_call(exc_type, [message], a.line) builder.primitive_op(raise_exception_op, [exc], a.line) builder.add(Unreachable()) builder.activate_block(ok_block)