void setupComplex() { complex_cls->giveAttr("__name__", boxStrConstant("complex")); complex_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)complexNew, UNKNOWN, 3, 2, false, false), { boxInt(0), boxInt(0) })); _addFunc("__add__", BOXED_COMPLEX, (void*)complexAddComplex, (void*)complexAddFloat, (void*)complexAddInt, (void*)complexAdd); _addFunc("__sub__", BOXED_COMPLEX, (void*)complexSubComplex, (void*)complexSubFloat, (void*)complexSubInt, (void*)complexSub); _addFunc("__mul__", BOXED_COMPLEX, (void*)complexMulComplex, (void*)complexMulFloat, (void*)complexMulInt, (void*)complexMul); _addFunc("__div__", BOXED_COMPLEX, (void*)complexDivComplex, (void*)complexDivFloat, (void*)complexDivInt, (void*)complexDiv); complex_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)complexStr, STR, 1))); complex_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)complexRepr, STR, 1))); complex_cls->giveAttr("real", new BoxedMemberDescriptor(BoxedMemberDescriptor::FLOAT, offsetof(BoxedComplex, real))); complex_cls->giveAttr("imag", new BoxedMemberDescriptor(BoxedMemberDescriptor::FLOAT, offsetof(BoxedComplex, imag))); complex_cls->freeze(); }
extern "C" Box* pow_i64_i64(i64 lhs, i64 rhs) { i64 orig_rhs = rhs; i64 rtn = 1, curpow = lhs; if (rhs < 0) return boxFloat(pow_float_float(lhs, rhs)); if (rhs == 0) { if (lhs < 0) return boxInt(-1); return boxInt(1); } assert(rhs > 0); while (rhs) { if (rhs & 1) { // TODO: could potentially avoid restarting the entire computation on overflow? if (__builtin_smull_overflow(rtn, curpow, &rtn)) return longPow(boxLong(lhs), boxLong(orig_rhs)); } if (__builtin_smull_overflow(curpow, curpow, &curpow)) return longPow(boxLong(lhs), boxLong(orig_rhs)); rhs >>= 1; } return boxInt(rtn); }
extern "C" PyObject* PySequence_GetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2) { try { // Not sure if this is really the same: return getitem(o, new BoxedSlice(boxInt(i1), boxInt(i2), None)); } catch (Box* b) { Py_FatalError("unimplemented"); } }
static Box* lineno(Box* obj, void*) noexcept { auto f = static_cast<BoxedFrame*>(obj); if (f->hasExited()) { ASSERT(f->_linenumber > 0 && f->_linenumber < 1000000, "%d", f->_linenumber); return boxInt(f->_linenumber); } AST_stmt* stmt = f->frame_info->stmt; ASSERT(stmt->lineno > 0 && stmt->lineno < 1000000, "%d", stmt->lineno); return boxInt(stmt->lineno); }
void setupTuple() { tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedTupleIterator::gcHandler, 0, 0, sizeof(BoxedTupleIterator), false, "tuple"); tuple_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)tupleNew, UNKNOWN, 1, 0, true, true))); CLFunction* getitem = createRTFunction(2, 0, 0, 0); addRTFunction(getitem, (void*)tupleGetitemInt, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, BOXED_INT }); addRTFunction(getitem, (void*)tupleGetitemSlice, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, SLICE }); addRTFunction(getitem, (void*)tupleGetitem<CXX>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN }, CXX); addRTFunction(getitem, (void*)tupleGetitem<CAPI>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN }, CAPI); tuple_cls->giveAttr("__getitem__", new BoxedFunction(getitem)); tuple_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)tupleContains, BOXED_BOOL, 2))); tuple_cls->giveAttr("index", new BoxedFunction(boxRTFunction((void*)tupleIndex, BOXED_INT, 4, 2, false, false), { boxInt(0), boxInt(std::numeric_limits<Py_ssize_t>::max()) })); tuple_cls->giveAttr("count", new BoxedFunction(boxRTFunction((void*)tupleCount, BOXED_INT, 2))); tuple_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)tupleIter, typeFromClass(tuple_iterator_cls), 1))); tuple_cls->tp_richcompare = tuplerichcompare; tuple_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)tupleNonzero, BOXED_BOOL, 1))); tuple_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)tupleLen, BOXED_INT, 1))); tuple_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)tupleRepr, STR, 1))); tuple_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)tupleAdd, BOXED_TUPLE, 2))); tuple_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)tupleMul, BOXED_TUPLE, 2))); tuple_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)tupleMul, BOXED_TUPLE, 2))); tuple_cls->tp_hash = (hashfunc)tuple_hash; tuple_cls->tp_as_sequence->sq_slice = (ssizessizeargfunc)&tupleslice; add_operators(tuple_cls); tuple_cls->freeze(); tuple_cls->tp_as_sequence->sq_item = (ssizeargfunc)tupleitem; tuple_cls->tp_as_sequence->sq_length = (lenfunc)tuplelength; tuple_cls->tp_iter = tupleIter; CLFunction* hasnext = boxRTFunction((void*)tupleiterHasnextUnboxed, BOOL, 1); addRTFunction(hasnext, (void*)tupleiterHasnext, BOXED_BOOL); tuple_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); tuple_iterator_cls->giveAttr( "__iter__", new BoxedFunction(boxRTFunction((void*)tupleIterIter, typeFromClass(tuple_iterator_cls), 1))); tuple_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)tupleiterNext, UNKNOWN, 1))); tuple_iterator_cls->freeze(); tuple_iterator_cls->tpp_hasnext = tupleiterHasnextUnboxed; }
static bool isBoxNumeric (Tree in, Tree& out) { int numInputs, numOutputs; double x; int i; Tree v, abstr, genv, vis, lenv, var, body; if (isBoxInt(in, &i) || isBoxReal(in, &x)) { out = in; return true; } else if (isClosure(in, abstr, genv, vis, lenv) && isBoxAbstr(abstr, var, body)) { return false; } else { v = a2sb(in); if ( getBoxType(v, &numInputs, &numOutputs) && (numInputs == 0) && (numOutputs == 1) ) { // potential numerical expression Tree lsignals = boxPropagateSig(gGlobal->nil, v , makeSigInputList(numInputs) ); Tree res = simplify(hd(lsignals)); if (isSigReal(res, &x)) { out = boxReal(x); return true; } if (isSigInt(res, &i)) { out = boxInt(i); return true; } } return false; } }
static Box* firstlineno(Box* b, void*) { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast<BoxedCode*>(b); CLFunction* cl = code->f; if (!cl->source) { // I don't think it really matters what we return here; // in CPython, builtin functions don't have code objects. return boxInt(-1); } if (cl->source->ast->lineno == (uint32_t)-1) return boxInt(-1); return boxInt(cl->source->ast->lineno); }
extern "C" Box* intInvert(BoxedInt* v) { if (!isSubclass(v->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__invert__' requires a 'int' object but received a '%s'", getTypeName(v)); return boxInt(~v->n); }
Box* dictLen(BoxedDict* self) { if (!isSubclass(self->cls, dict_cls)) raiseExcHelper(TypeError, "descriptor '__len__' requires a 'dict' object but received a '%s'", getTypeName(self)); return boxInt(self->d.size()); }
extern "C" Box* intPow(BoxedInt* lhs, Box *rhs) { assert(lhs->cls == int_cls); if (rhs->cls != int_cls) { return NotImplemented; } BoxedInt *rhs_int = static_cast<BoxedInt*>(rhs); return boxInt(pow_i64_i64(lhs->n, rhs_int->n)); }
extern "C" Box* intLShift(BoxedInt* lhs, Box *rhs) { assert(lhs->cls == int_cls); if (rhs->cls != int_cls) { return NotImplemented; } BoxedInt *rhs_int = static_cast<BoxedInt*>(rhs); return boxInt(lhs->n << rhs_int->n); }
BoxedSysFlags() { auto zero = boxInt(0); assert(zero); division_warning = zero; bytes_warning = zero; no_user_site = zero; optimize = zero; }
extern "C" PyObject* PySequence_GetItem(PyObject* o, Py_ssize_t i) { try { // Not sure if this is really the same: return getitem(o, boxInt(i)); } catch (Box* b) { Py_FatalError("unimplemented"); } }
extern "C" Box* intPos(BoxedInt* v) { if (!isSubclass(v->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__pos__' requires a 'int' object but received a '%s'", getTypeName(v)); if (v->cls == int_cls) return v; return boxInt(v->n); }
BoxedSysFlags() { auto zero = boxInt(0); assert(zero); division_warning = incref(zero); bytes_warning = incref(zero); no_user_site = incref(zero); optimize = incref(zero); Py_DECREF(zero); }
extern "C" Box* intHash(BoxedInt* self) { if (!isSubclass(self->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__hash__' requires a 'int' object but received a '%s'", getTypeName(self)); if (self->cls == int_cls) return self; return boxInt(self->n); }
extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) { assert(isSubclass(lhs->cls, int_cls)); assert(isSubclass(rhs->cls, int_cls)); if (rhs->n < 0) raiseExcHelper(ValueError, "negative shift count"); // TODO overflow? return boxInt(lhs->n << rhs->n); }
extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) { if (!isSubclass(lhs->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__mod__' requires a 'int' object but received a '%s'", getTypeName(lhs)); if (rhs->cls != int_cls) { return NotImplemented; } BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs); return boxInt(mod_i64_i64(lhs->n, rhs_int->n)); }
void setupSys() { sys_modules_dict = new BoxedDict(); gc::registerPermanentRoot(sys_modules_dict); // This is ok to call here because we've already created the sys_modules_dict sys_module = createModule("sys", "__builtin__"); sys_module->giveAttr("modules", sys_modules_dict); BoxedList* sys_path = new BoxedList(); sys_module->giveAttr("path", sys_path); sys_module->giveAttr("argv", new BoxedList()); sys_module->giveAttr("stdout", new BoxedFile(stdout)); sys_module->giveAttr("stdin", new BoxedFile(stdin)); sys_module->giveAttr("stderr", new BoxedFile(stderr)); sys_module->giveAttr("warnoptions", new BoxedList()); sys_module->giveAttr("py3kwarning", False); sys_module->giveAttr("platform", boxStrConstant("unknown")); // seems like a reasonable, if poor, default sys_module->giveAttr("hexversion", boxInt(PY_VERSION_HEX)); sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX)); sys_flags_cls = new BoxedClass(type_cls, object_cls, BoxedSysFlags::gcHandler, 0, sizeof(BoxedSysFlags), false); sys_flags_cls->giveAttr("__name__", boxStrConstant("flags")); sys_flags_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true))); #define ADD(name) \ sys_flags_cls->giveAttr(STRINGIFY(name), \ new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSysFlags, name))) ADD(division_warning); ADD(bytes_warning); #undef ADD sys_flags_cls->freeze(); sys_module->giveAttr("flags", new BoxedSysFlags()); }
Box* range1(Box* end) { RELEASE_ASSERT(end->cls == int_cls, "%s", getTypeName(end)->c_str()); BoxedList *rtn = new BoxedList(); i64 iend = static_cast<BoxedInt*>(end)->n; for (i64 i = 0; i < iend; i++) { Box *bi = boxInt(i); listAppendInternal(rtn, bi); } return rtn; }
extern "C" Box* div_i64_i64(i64 lhs, i64 rhs) { if (rhs == 0) { raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero"); } // It's possible for division to overflow: #if PYSTON_INT_MIN < -PYSTON_INT_MAX static_assert(PYSTON_INT_MIN == -PYSTON_INT_MAX - 1, ""); if (lhs == PYSTON_INT_MIN && rhs == -1) { return longDiv(boxLong(lhs), boxLong(rhs)); } #endif if (lhs < 0 && rhs > 0) return boxInt((lhs - rhs + 1) / rhs); if (lhs > 0 && rhs < 0) return boxInt((lhs - rhs - 1) / rhs); return boxInt(lhs / rhs); }
extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject* v) noexcept { if (!PyList_Check(a)) { PyErr_BadInternalCall(); return -1; } BoxedList* l = (BoxedList*)a; ASSERT(l->cls == list_cls, "%s", l->cls->tp_name); try { if (v) listSetitemSlice(l, new BoxedSlice(boxInt(ilow), boxInt(ihigh), None), v); else listDelitemSlice(l, new BoxedSlice(boxInt(ilow), boxInt(ihigh), None)); return 0; } catch (ExcInfo e) { setCAPIException(e); return -1; } }
extern "C" Box* abs_(Box* x) { if (x->cls == int_cls) { i64 n = static_cast<BoxedInt*>(x)->n; return boxInt(n >= 0 ? n : -n); } else if (x->cls == float_cls) { double d = static_cast<BoxedFloat*>(x)->d; return boxFloat(d >= 0 ? d : -d); } else { RELEASE_ASSERT(0, "%s", getTypeName(x)->c_str()); } }
extern "C" Box* intSub(BoxedInt* lhs, Box *rhs) { assert(lhs->cls == int_cls); if (rhs->cls == int_cls) { BoxedInt *rhs_int = static_cast<BoxedInt*>(rhs); return boxInt(lhs->n - rhs_int->n); } else if (rhs->cls == float_cls) { BoxedFloat *rhs_float = static_cast<BoxedFloat*>(rhs); return boxFloat(lhs->n - rhs_float->d); } else { return NotImplemented; } }
extern "C" Box* intNew2(Box* cls, Box* val) { assert(cls == int_cls); if (val->cls == int_cls) { return val; } else if (val->cls == str_cls) { BoxedString *s = static_cast<BoxedString*>(val); std::istringstream ss(s->s); int64_t n; ss >> n; return boxInt(n); } else if (val->cls == float_cls) {
Box* BoxedCode::flags(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast<BoxedCode*>(b); int flags = 0; if (code->param_names.has_vararg_name) flags |= CO_VARARGS; if (code->param_names.has_kwarg_name) flags |= CO_VARKEYWORDS; if (code->isGenerator()) flags |= CO_GENERATOR; return boxInt(flags); }
static Box* flags(Box* b, void*) { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast<BoxedCode*>(b); int flags = 0; if (code->f->param_names.vararg.size()) flags |= CO_VARARGS; if (code->f->param_names.kwarg.size()) flags |= CO_VARKEYWORDS; if (code->f->isGenerator()) flags |= CO_GENERATOR; return boxInt(flags); }
Box* tupleCount(BoxedTuple* self, Box* elt) { int size = self->size(); int count = 0; for (int i = 0; i < size; i++) { Box* e = self->elts[i]; int r = PyObject_RichCompareBool(e, elt, Py_EQ); if (r == -1) throwCAPIException(); if (r) count++; } return boxInt(count); }
Box* seqiterHasnext(Box* s) { RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, ""); BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s); Box* next; try { next = getitem(self->b, boxInt(self->idx)); } catch (ExcInfo e) { return False; } self->idx++; self->next = next; return True; }
extern "C" Box* abs_(Box* x) { if (isSubclass(x->cls, int_cls)) { i64 n = static_cast<BoxedInt*>(x)->n; return boxInt(n >= 0 ? n : -n); } else if (x->cls == float_cls) { double d = static_cast<BoxedFloat*>(x)->d; return boxFloat(d >= 0 ? d : -d); } else if (x->cls == long_cls) { return longAbs(static_cast<BoxedLong*>(x)); } else { static const std::string abs_str("__abs__"); return callattr(x, &abs_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }), ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); }