def exc_from_raise(self, w_arg1, w_arg2): """ Create a wrapped exception from the arguments of a raise statement. Returns an FSException object whose w_value is an instance of w_type. """ w_is_type = op.simple_call(const(isinstance), w_arg1, const(type)).eval(self) if self.guessbool(w_is_type): # this is for all cases of the form (Class, something) if self.guessbool(op.is_(w_arg2, w_None).eval(self)): # raise Type: we assume we have to instantiate Type w_value = op.simple_call(w_arg1).eval(self) else: w_valuetype = op.type(w_arg2).eval(self) if self.guessbool(op.issubtype(w_valuetype, w_arg1).eval(self)): # raise Type, Instance: let etype be the exact type of value w_value = w_arg2 else: # raise Type, X: assume X is the constructor argument w_value = op.simple_call(w_arg1, w_arg2).eval(self) else: # the only case left here is (inst, None), from a 'raise inst'. if not self.guessbool(op.is_(w_arg2, const(None)).eval(self)): exc = TypeError("instance exception may not have a " "separate value") raise Raise(const(exc)) w_value = w_arg1 w_type = op.type(w_value).eval(self) return FSException(w_type, w_value)
def LIST_APPEND(self, oparg): w_value = self.popvalue() if sys.version_info < (2, 7): w_list = self.popvalue() else: w_list = self.peekvalue(oparg - 1) w_append_meth = op.getattr(w_list, const('append')).eval(self) op.simple_call(w_append_meth, w_value).eval(self)
def replace_graph_with_bootstrap(GeneratorIterator, graph): Entry = GeneratorIterator.Entry newblock = Block(graph.startblock.inputargs) op_entry = op.simple_call(const(Entry)) v_entry = op_entry.result newblock.operations.append(op_entry) assert len(graph.startblock.inputargs) == len(Entry.varnames) for v, name in zip(graph.startblock.inputargs, Entry.varnames): newblock.operations.append(op.setattr(v_entry, Constant(name), v)) op_generator = op.simple_call(const(GeneratorIterator), v_entry) newblock.operations.append(op_generator) newblock.closeblock(Link([op_generator.result], graph.returnblock)) graph.startblock = newblock
def WITH_CLEANUP(self, oparg): # Note: RPython context managers receive None in lieu of tracebacks # and cannot suppress the exception. unroller = self.popvalue() w_exitfunc = self.popvalue() self.pushvalue(unroller) if isinstance(unroller, Raise): w_exc = unroller.w_exc # The annotator won't allow to merge exception types with None. # Replace it with the exception value... op.simple_call(w_exitfunc, w_exc.w_value, w_exc.w_value, w_None ).eval(self) else: op.simple_call(w_exitfunc, w_None, w_None, w_None).eval(self)
def rtypedelegate(callable, hop, revealargs=[0], revealresult=False): bk = hop.rtyper.annotator.bookkeeper c_meth = Constant(callable) s_meth = bk.immutablevalue(callable) hop2 = hop.copy() for index in revealargs: r_controlled = hop2.args_r[index] if not isinstance(r_controlled, ControlledInstanceRepr): raise TyperError("args_r[%d] = %r, expected ControlledInstanceRepr" % (index, r_controlled)) s_new, r_new = r_controlled.s_real_obj, r_controlled.r_real_obj hop2.args_s[index], hop2.args_r[index] = s_new, r_new v = hop2.args_v[index] if isinstance(v, Constant): real_value = r_controlled.controller.convert(v.value) hop2.args_v[index] = Constant(real_value) if revealresult: r_controlled = hop2.r_result if not isinstance(r_controlled, ControlledInstanceRepr): raise TyperError("r_result = %r, expected ControlledInstanceRepr" % (r_controlled,)) s_new, r_new = r_controlled.s_real_obj, r_controlled.r_real_obj hop2.s_result, hop2.r_result = s_new, r_new hop2.v_s_insertfirstarg(c_meth, s_meth) spaceop = op.simple_call(*hop2.args_v) spaceop.result = hop2.spaceop.result hop2.spaceop = spaceop return hop2.dispatch()
def WITH_CLEANUP(self, oparg): # Note: RPython context managers receive None in lieu of tracebacks # and cannot suppress the exception. # This opcode changed a lot between CPython versions if sys.version_info >= (2, 6): unroller = self.popvalue() w_exitfunc = self.popvalue() self.pushvalue(unroller) else: w_exitfunc = self.popvalue() unroller = self.peekvalue(0) if isinstance(unroller, Raise): w_exc = unroller.w_exc # The annotator won't allow to merge exception types with None. # Replace it with the exception value... op.simple_call(w_exitfunc, w_exc.w_value, w_exc.w_value, w_None ).eval(self) else: op.simple_call(w_exitfunc, w_None, w_None, w_None).eval(self)
def SETUP_WITH(self, target): # A simpler version than the 'real' 2.7 one: # directly call manager.__enter__(), don't use special lookup functions # which don't make sense on the RPython type system. w_manager = self.peekvalue() w_exit = op.getattr(w_manager, const("__exit__")).eval(self) self.settopvalue(w_exit) w_enter = op.getattr(w_manager, const('__enter__')).eval(self) w_result = op.simple_call(w_enter).eval(self) block = WithBlock(self, target) self.blockstack.append(block) self.pushvalue(w_result)
def setattr_SomeInstance(annotator, v_obj, v_attr, v_value): s_attr = annotator.annotation(v_attr) if not s_attr.is_constant() or not isinstance(s_attr.const, str): return attr = s_attr.const setters = _find_property_meth(annotator.annotation(v_obj), attr, 'fset') if setters: if all(setters): get_setter = op.getattr(v_obj, const(attr + '__setter__')) return [get_setter, op.simple_call(get_setter.result, v_value)] elif not any(setters): raise AnnotatorError("Attribute %r is unwritable" % attr)
def _emulate_call(self, hop, meth_name): vinst, = hop.inputargs(self) clsdef = hop.args_s[0].classdef s_unbound_attr = clsdef.find_attribute(meth_name).getvalue() s_attr = clsdef.lookup_filter(s_unbound_attr, meth_name, hop.args_s[0].flags) # does that even happen? assert not s_attr.is_constant() if '__iter__' in self.allinstancefields: raise Exception("__iter__ on instance disallowed") r_method = self.rtyper.getrepr(s_attr) r_method.get_method_from_instance(self, vinst, hop.llops) hop2 = hop.copy() hop2.spaceop = op.simple_call(hop.spaceop.args[0]) hop2.spaceop.result = hop.spaceop.result hop2.args_r = [r_method] hop2.args_s = [s_attr] return hop2.dispatch()
def _emulate_call(self, hop, meth_name): vinst = hop.args_v[0] clsdef = hop.args_s[0].classdef s_unbound_attr = clsdef.find_attribute(meth_name).getvalue() s_attr = clsdef.lookup_filter(s_unbound_attr, meth_name, hop.args_s[0].flags) # does that even happen? assert not s_attr.is_constant() if '__iter__' in self.allinstancefields: raise Exception("__iter__ on instance disallowed") r_method = self.rtyper.getrepr(s_attr) r_method.get_method_from_instance(self, vinst, hop.llops) hop2 = hop.copy() hop2.spaceop = op.simple_call(*hop.spaceop.args) hop2.spaceop.result = hop.spaceop.result hop2.args_r[0] = r_method hop2.args_s[0] = s_attr return hop2.dispatch()
def transform_varargs(annotator, v_func, v_shape, *data_v): callspec = CallSpec.fromshape(v_shape.value, list(data_v)) v_vararg = callspec.w_stararg if callspec.w_stararg: s_vararg = annotator.annotation(callspec.w_stararg) if not isinstance(s_vararg, SomeTuple): raise AnnotatorError( "Calls like f(..., *arg) require 'arg' to be a tuple") n_items = len(s_vararg.items) ops = [op.getitem(v_vararg, const(i)) for i in range(n_items)] new_args = callspec.arguments_w + [hlop.result for hlop in ops] if callspec.keywords: newspec = CallSpec(new_args, callspec.keywords) shape, data_v = newspec.flatten() call_op = op.call_args(v_func, const(shape), *data_v) else: call_op = op.simple_call(v_func, *new_args) ops.append(call_op) return ops
def call_function(self, oparg, w_star=None, w_starstar=None): if w_starstar is not None: raise FlowingError("Dict-unpacking is not RPython") n_arguments = oparg & 0xff n_keywords = (oparg >> 8) & 0xff keywords = {} for _ in range(n_keywords): w_value = self.popvalue() w_key = self.popvalue() key = w_key.value keywords[key] = w_value arguments = self.popvalues(n_arguments) args = CallSpec(arguments, keywords, w_star) w_function = self.popvalue() if args.keywords or isinstance(args.w_stararg, Variable): shape, args_w = args.flatten() hlop = op.call_args(w_function, Constant(shape), *args_w) else: hlop = op.simple_call(w_function, *args.as_list()) self.pushvalue(hlop.eval(self))
def setitem_SomeInstance(annotator, v_ins, v_idx, v_value): get_setitem = op.getattr(v_ins, const('__setitem__')) return [get_setitem, op.simple_call(get_setitem.result, v_idx, v_value)]
def contains_SomeInstance(annotator, v_ins, v_idx): get_contains = op.getattr(v_ins, const('__contains__')) return [get_contains, op.simple_call(get_contains.result, v_idx)]
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) op0 = op.simple_call(const(StopIteration)) op1 = op.type(op0.result) stopblock.operations = [op0, op1] stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations)-1, -1, -1): hlop = block.operations[index] if hlop.opname == 'yield_': [v_yielded_value] = hlop.args del block.operations[index] newlink = split_block(None, block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # op_resume = op.simple_call(const(Resume)) block.operations.append(op_resume) v_resume = op_resume.result for i, name in enumerate(varnames): block.operations.append( op.setattr(v_resume, const(name), newlink.args[i])) op_pair = op.newtuple(v_resume, v_yielded_value) block.operations.append(op_pair) newlink.args = [op_pair.result] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: op_check = op.simple_call( const(isinstance), block.inputargs[0], const(Resume)) block.operations.append(op_check) block.exitswitch = op_check.result link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock(Link([Constant(AssertionError), Constant(AssertionError("bad generator class"))], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def setslice_SomeInstance(annotator, v_obj, v_start, v_stop, v_iterable): get_setslice = op.getattr(v_obj, const('__setslice__')) return [ get_setslice, op.simple_call(get_setslice.result, v_start, v_stop, v_iterable) ]
def getslice_SomeInstance(annotator, v_obj, v_start, v_stop): get_getslice = op.getattr(v_obj, const('__getslice__')) return [get_getslice, op.simple_call(get_getslice.result, v_start, v_stop)]
def next_SomeInstance(annotator, v_arg): get_next = op.getattr(v_arg, const('next')) return [get_next, op.simple_call(get_next.result)]
def len_SomeInstance(annotator, v_arg): get_len = op.getattr(v_arg, const('__len__')) return [get_len, op.simple_call(get_len.result)]
def iter_SomeInstance(annotator, v_arg): get_iter = op.getattr(v_arg, const('__iter__')) return [get_iter, op.simple_call(get_iter.result)]
def appcall(self, func, *args_w): """Call an app-level RPython function directly""" w_func = const(func) return self.do_op(op.simple_call(w_func, *args_w))
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) insert_empty_startblock(graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) op0 = op.simple_call(const(StopIteration)) op1 = op.type(op0.result) stopblock.operations = [op0, op1] stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations) - 1, -1, -1): hlop = block.operations[index] if hlop.opname == 'yield_': [v_yielded_value] = hlop.args del block.operations[index] newlink = split_block(block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # op_resume = op.simple_call(const(Resume)) block.operations.append(op_resume) v_resume = op_resume.result for i, name in enumerate(varnames): block.operations.append( op.setattr(v_resume, const(name), newlink.args[i])) op_pair = op.newtuple(v_resume, v_yielded_value) block.operations.append(op_pair) newlink.args = [op_pair.result] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: op_check = op.isinstance(block.inputargs[0], const(Resume)) block.operations.append(op_check) block.exitswitch = op_check.result link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock( Link([ Constant(AssertionError), Constant(AssertionError("bad generator class")) ], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def setslice_SomeInstance(annotator, v_obj, v_start, v_stop, v_iterable): get_setslice = op.getattr(v_obj, const('__setslice__')) return [get_setslice, op.simple_call(get_setslice.result, v_start, v_stop, v_iterable)]