def get_length(self, out_inst=None): if not out_inst: out_inst = CIntegerLL(None, self.v) out_inst.declare_tmp(name="_len") self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyObject_Length'), c.ExprList(c.ID(self.name))))) self.fail_if_negative(out_inst.name) return out_inst
def add(self, val): out = CIntegerLL(None, self.v) out.declare_tmp(name='_set_add_rv') self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PySet_Add'), c.ExprList( c.ID(self.name), c.ID(val.name))))) self.fail_if_nonzero(out.name) out.decref()
def sequence_del_slice(self, start, end, step): if step is None: tmp_inst = CIntegerLL(None, self.v) tmp_inst.declare_tmp(name='_rv_slice') if start is None: _start = c.Constant('integer', 0) else: _start = c.ID(start.as_ssize().name) if end is None: _end = c.Constant('integer', CIntegerLL.MAX) else: _end = c.ID(end.as_ssize().name) self.v.ctx.add(c.Assignment('=', c.ID(tmp_inst.name), c.FuncCall(c.ID('PySequence_DelSlice'), c.ExprList(c.ID(self.name), _start, _end)))) self.fail_if_nonzero(tmp_inst.name) tmp_inst.decref() else: slice_inst = PySliceLL(None, self.v) slice_inst.declare_tmp(name='_slice') if start is None: _start = self.v.none; _start.incref() else: _start = start.as_pyobject() if end is None: _end = self.v.none; _end.incref() else: _end = end.as_pyobject() _step = step.as_pyobject() slice_inst.new(_start, _end, _step) self.del_item(slice_inst) slice_inst.decref()
def set_attr(self, attr, val): tmp = CIntegerLL(None, self.v) tmp.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyObject_SetAttr'), c.ExprList( c.ID(self.name), c.ID(attr.name), c.ID(val.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def runner_intro(self): '''Set the generator context on the TLS so that we can get to it from generators we call into.''' self.v.ctx.add(c.Comment('cast args to PyObject**')) self.args_name = self.v.scope.ctx.reserve_name('__args__', self.v.tu) self.v.scope.ctx.add_variable(c.Decl(self.args_name, c.PtrDecl(c.PtrDecl(c.TypeDecl(self.args_name, c.IdentifierType('PyObject')))), init=c.ID('NULL')), False) self.v.ctx.add(c.Assignment('=', c.ID(self.args_name), c.Cast(c.PtrDecl(PyObjectLL.typedecl()), c.ID('gen_args')))) self.fail_if_null(self.args_name) #NOTE: we should _not_ incref our __self__ or __gen__ since this function _is_ us -- if we keep this ref and don't # fully drain, then we will never decref ourself and clean up the other references we're holding onto self.v.ctx.add(c.Comment('get function instance')) self.self_inst = PyObjectLL(None, self.v) self.self_inst.declare_tmp(name='__self__') self.v.ctx.add(c.Assignment('=', c.ID(self.self_inst.name), c.ArrayRef(c.ID(self.args_name), c.Constant('integer', self.SELF_INDEX)))) self.fail_if_null(self.self_inst.name) self.v.ctx.add(c.Comment('get generator instance')) self.gen_inst = PyObjectLL(None, self.v) self.gen_inst.declare_tmp(name='__gen__') self.v.ctx.add(c.Assignment('=', c.ID(self.gen_inst.name), c.ArrayRef(c.ID(self.args_name), c.Constant('integer', self.GENERATOR_INDEX)))) self.fail_if_null(self.gen_inst.name) super().runner_intro() self.v.ctx.add(c.Comment('mark us as in the generator')) tmp = CIntegerLL(None, self.v) tmp.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('MpGenerator_EnterContext'), c.ExprList(c.ID(self.gen_inst.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def sequence_contains(self, item): out = CIntegerLL(None, self.v) out.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PySequence_Contains'), c.ExprList( c.ID(self.name), c.ID(item.name))))) self.fail_if_negative(out.name) return out
def sequence_set_slice(self, start, end, step, src_inst): '''Assign a sequence into a sliced sequence.''' # Case 0: no step means we can use the fast sequence SetSlice if step is None: tmp_inst = CIntegerLL(None, self.v) tmp_inst.declare_tmp(name='_rv_slice') if start is None: _start = c.Constant('integer', 0) else: _start = c.ID(start.as_ssize().name) if end is None: _end = c.Constant('integer', CIntegerLL.MAX) else: _end = c.ID(end.as_ssize().name) self.v.ctx.add(c.Assignment('=', c.ID(tmp_inst.name), c.FuncCall(c.ID('PySequence_SetSlice'), c.ExprList(c.ID(self.name), _start, _end, c.ID(src_inst.name))))) self.fail_if_negative(tmp_inst.name) tmp_inst.decref() else: slice_inst = PySliceLL(None, self.v) slice_inst.declare_tmp(name='_slice') if start is None: _start = self.v.none; _start.incref() else: _start = start.as_pyobject() if end is None: _end = self.v.none; _end.incref() else: _end = end.as_pyobject() _step = step.as_pyobject() slice_inst.new(_start, _end, _step) self.set_item(slice_inst, src_inst) slice_inst.decref()
def rich_compare_bool(self, rhs, opid): out = CIntegerLL(None, self.v) out.declare_tmp(name='_cmp') self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PyObject_RichCompareBool'), c.ExprList( c.ID(self.name), c.ID(rhs.name), c.ID(opid))))) self.fail_if_negative(out.name) return out
def mapping_size(self, out_inst=None): if not out_inst: out_inst = CIntegerLL(None, self.v) out_inst.declare_tmp(name='_size') self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyMapping_Size'), c.ExprList(c.ID(self.name))))) self.fail_if_negative(out_inst.name) return out_inst
def del_item(self, key): out = CIntegerLL(None, self.v) out.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PyObject_DelItem'), c.ExprList( c.ID(self.name), c.ID(key.name))))) self.fail_if_nonzero(out.name) out.decref()
def del_attr_string(self, attrname): tmp = CIntegerLL(None, self.v) tmp.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyObject_DelAttrString'), c.ExprList( c.ID(self.name), c.Constant('string', attrname))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def append(self, inst, out_inst=None): if not out_inst: out_inst = CIntegerLL(None, self.v) out_inst.declare_tmp(name='_append_rv') self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyList_Append'), c.ExprList(c.ID(self.name), c.ID(inst.name))))) self.fail_if_nonzero(out_inst.name) return out_inst
def is_instance(self, type_type): out = CIntegerLL(None, self.v) out.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PyObject_IsInstance'), c.ExprList( c.ID(self.name), c.Cast(PyObjectLL.typedecl(), c.UnaryOp('&', c.ID(type_type.typename()))))))) self.fail_if_negative(out.name) return out
def as_ssize(self, out=None): if not out: out = CIntegerLL(None, self.v) out.declare_tmp() assert isinstance(out, CIntegerLL) self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.FuncCall(c.ID('PyNumber_AsSsize_t'), c.ExprList(c.ID(self.name), c.ID('PyExc_OverflowError'))))) self.fail_if_error_occurred() return out
def is_true(self, out_inst=None): if not out_inst: out_inst = CIntegerLL(None, self.v) out_inst.declare_tmp(name="_istrue_rv") assert isinstance(out_inst, CIntegerLL) self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyObject_IsTrue'), c.ExprList(c.ID(self.name))))) self.fail_if_negative(out_inst.name) return out_inst
def set_attr_string(self, attrname, attrval): tmp = CIntegerLL(None, self.v) tmp.declare_tmp(name="_setattr_rv") attrval = attrval.as_pyobject() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyObject_SetAttrString'), c.ExprList( c.ID(self.name), c.Constant('string', attrname), c.ID(attrval.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def set_item_string(self, name:str, var:PyObjectLL): tmp = CIntegerLL(None, self.v) tmp.declare_tmp(name='_set_str_rv') var = var.as_pyobject() #var.incref() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyDict_SetItemString'), c.ExprList( c.ID(self.name), c.Constant('string', name), c.ID(var.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def set_item(self, key:PyObjectLL, val:PyObjectLL): tmp = CIntegerLL(None, self.v) tmp.declare_tmp(name='_set_rv') #key.incref() #val.incref() self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyDict_SetItem'), c.ExprList( c.ID(self.name), c.ID(key.name), c.ID(val.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def get_item(self, offset:CIntegerLL, out_inst=None): if not isinstance(offset, CIntegerLL): offset = offset.as_ssize() if not out_inst: out_inst = PyObjectLL(None, self.v) out_inst.declare_tmp(name="_item") self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyTuple_GetItem'), c.ExprList(c.ID(self.name), c.ID(offset.name))))) self.fail_if_null(out_inst.name) out_inst.incref() return out_inst
def update(self, other:PyObjectLL): tmp = CIntegerLL(None, self.v) tmp.declare_tmp(name='_update_rv') self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyDict_Update'), c.ExprList(c.ID(self.name), c.ID(other.name))))) self.fail_if_nonzero(tmp.name) tmp.decref()
def del_item_string(self, name:str): tmp = CIntegerLL(None, self.v) tmp.declare_tmp(name='_del_rv') self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), c.FuncCall(c.ID('PyDict_DelItemString'), c.ExprList(c.ID(self.name), c.Constant('string', name))))) self.fail_if_nonzero(tmp.name)
def is_(self, other): out = CIntegerLL(None, self.v) out.declare_tmp() self.v.ctx.add(c.Assignment('=', c.ID(out.name), c.BinaryOp('==', c.ID(self.name), c.ID(other.name)))) return out
def get_length(self, out_inst=None): if not out_inst: out_inst = CIntegerLL(None, self.v) out_inst.declare_tmp(name="_len") self.v.ctx.add(c.Assignment('=', c.ID(out_inst.name), c.FuncCall(c.ID('PyList_Size'), c.ExprList(c.ID(self.name))))) return out_inst
def stub_load_args(self, args, defaults, vararg, kwonlyargs, kw_defaults, kwarg): self.stub_arg_insts = [] # get args ref args_tuple = self.stub_args_tuple kwargs_dict = self.stub_kwargs_dict # get copy of kwargs -- clear items out of it as we load them, or skip entirely if kwarg: if_have_kwargs = self.v.ctx.add(c.If(c.ID(kwargs_dict.name), c.Compound(), c.Compound())) with self.v.new_context(if_have_kwargs.iftrue): kwargs_inst = kwargs_dict.copy() with self.v.new_context(if_have_kwargs.iffalse): kwargs_dict.new() kwargs_inst = kwargs_dict else: kwargs_inst = None # load positional and normal keyword args if args: c_args_size = CIntegerLL(None, self.v) c_args_size.declare_tmp(name='_args_size') args_tuple.get_size_unchecked(c_args_size) arg_insts = [None] * len(args) for i, arg in enumerate(args): # Note: different scope than the actual args are declared in.. need to stub them out here #TODO: make this type pull from the arg.arg.hl.get_type() through lookup... maybe create dup_ll_type or something arg_insts[i] = PyObjectLL(arg.arg.hl, self.v) arg_insts[i].declare() # query if in positional args self.v.ctx.add(c.Comment("Grab arg {}".format(str(arg.arg)))) query_inst = self.v.ctx.add(c.If(c.BinaryOp('>', c.ID(c_args_size.name), c.Constant('integer', i)), c.Compound(), c.Compound())) ## get the positional arg on the true side with self.v.new_context(query_inst.iftrue): args_tuple.get_unchecked(i, arg_insts[i]) ## get the keyword arg on the false side with self.v.new_context(query_inst.iffalse): have_kwarg = self.v.ctx.add(c.If(c.ID('kwargs'), c.Compound(), None)) ### if we took kwargs, then get it directly with self.v.new_context(have_kwarg.iftrue): kwargs_dict.get_item_string_nofail(str(arg.arg), arg_insts[i]) ### if no kwargs passed or the item was not in the kwargs, load the default from defaults query_default_inst = self.v.ctx.add(c.If(c.UnaryOp('!', c.ID(arg_insts[i].name)), c.Compound(), c.Compound())) with self.v.new_context(query_default_inst.iftrue): kwstartoffset = len(args) - len(defaults) if i >= kwstartoffset: # try loading from defaults default_offset = i - kwstartoffset tmp = PyTupleLL(None, self.v) tmp.declare_tmp() self.c_obj.get_attr_string('__defaults__', tmp) #self.v.ctx.add(c.Assignment('=', c.ID(tmp.name), # c.FuncCall(c.ID('PyObject_GetAttrString'), c.ExprList(c.ID(self.c_obj.name), c.Constant('string', '__defaults__'))))) # tmp.get_unchecked(default_offset, arg_insts[i]) #self.v.ctx.add(c.Assignment('=', c.ID(arg_insts[i].name), # c.FuncCall(c.ID('PyTuple_GetItem'), c.ExprList(c.ID(tmp.name), c.Constant('integer', default_offset))))) arg_insts[i].incref() tmp.decref() #self.v.ctx.add(c.FuncCall(c.ID('Py_INCREF'), c.ID(arg_insts[i].name))) else: # emit an error for an unpassed arg with self.v.new_context(query_default_inst.iftrue): self.fail('PyExc_TypeError', 'Missing arg {}'.format(str(arg))) ### if we did get the item out of the kwargs, delete it from the inst copy so it's not duped in the args we pass with self.v.new_context(query_default_inst.iffalse): if kwargs_inst: kwargs_inst.del_item_string(str(arg.arg)) self.stub_arg_insts.extend(arg_insts) # add unused args to varargs and pass if in taken args or error if not if vararg: self.v.ctx.add(c.Comment('load varargs')) vararg_inst = args_tuple.get_slice(len(args), args_tuple.get_length()) self.stub_arg_insts.append(vararg_inst) else: len_inst = args_tuple.get_length() ifstmt = self.v.ctx.add(c.If(c.BinaryOp('>', c.ID(len_inst.name), c.Constant('integer', len(args))), c.Compound(), None)) with self.v.new_context(ifstmt.iftrue): self.fail_formatted('PyExc_TypeError', "{}() takes exactly {} positional arguments (%d given)".format(self.hlnode.owner.name, len(args)), len_inst) # load all keyword only args if kwonlyargs: kwarg_insts = [None] * len(kwonlyargs) for i, arg in enumerate(kwonlyargs): kwarg_insts[i] = PyObjectLL(arg.arg.hl, self.v) kwarg_insts[i].declare() # ensure we have kwargs at all have_kwarg = self.v.ctx.add(c.If(c.ID('kwargs'), c.Compound(), c.Compound())) ## in have_kwarg.iftrue, load all kwargs from the kwargs dict with self.v.new_context(have_kwarg.iftrue): for i, arg in enumerate(kwonlyargs): #FIXME: we can make this significantly more efficient with a bit of work kwargs_dict.get_item_string_nofail(str(arg.arg), kwarg_insts[i]) need_default = self.v.ctx.add(c.If(c.UnaryOp('!', c.ID(kwarg_insts[i].name)), c.Compound(), None)) ### not found in kwdict, means we need to load from default with self.v.new_context(need_default.iftrue): kwdefaults0 = PyDictLL(None, self.v) kwdefaults0.declare_tmp(name='_kwdefaults') self.c_obj.get_attr_string('__kwdefaults__', kwdefaults0) kwdefaults0.get_item_string(str(arg.arg), kwarg_insts[i]) kwdefaults0.decref() ### found in kwdict, means we need to delete from kwdict to avoid passing duplicate arg in kwargs if kwargs_inst: need_default.iffalse = c.Compound() with self.v.new_context(need_default.iffalse): kwargs_inst.del_item_string(str(arg.arg)) ## if have_kwarg.iffalse, need to load from the kwdefaults dict #TODO: this is identical to the failure case from above with self.v.new_context(have_kwarg.iffalse): kwdefaults1 = PyDictLL(None, self.v) kwdefaults1.declare_tmp(name='_kwdefaults') self.c_obj.get_attr_string('__kwdefaults__', kwdefaults1) for i, arg in enumerate(kwonlyargs): #have_kwarg.iffalse.add(c.Assignment('=', c.ID(kwdefaults1.name), # c.FuncCall(c.ID('PyObject_GetAttrString'), c.ExprList(c.ID(self.c_obj.name), c.Constant('string', '__kwdefaults__'))))) kwdefaults1.get_item_string(str(arg.arg), kwarg_insts[i]) #have_kwarg.iffalse.add(c.Assignment('=', c.ID(kwarg_insts[i].name), # c.FuncCall(c.ID('PyDict_GetItemString'), c.ExprList(c.ID(kwdefaults1.name), c.Constant('string', str(arg.arg)))))) #self.fail_if_null(kwarg_insts[i].name) kwdefaults1.decref() self.stub_arg_insts.extend(kwarg_insts) # pass remainder of kwargs dict in as the kwarg slot if kwarg: self.stub_arg_insts.append(kwargs_inst) '''