// Have a special helper function for syntax errors, since we want to include the location // of the syntax error in the traceback, even though it is not part of the execution: void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func) { Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL); auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, boxString(file), boxString(func)), None); assert(!PyErr_Occurred()); throw ExcInfo(exc->cls, exc, tb); }
static Box* setRepr(BoxedSet* self) { RELEASE_ASSERT(PyAnySet_Check(self), ""); std::vector<char> chars; int status = Py_ReprEnter((PyObject*)self); if (status != 0) { if (status < 0) throwCAPIException(); std::string ty = std::string(self->cls->tp_name); chars.insert(chars.end(), ty.begin(), ty.end()); chars.push_back('('); chars.push_back('.'); chars.push_back('.'); chars.push_back('.'); chars.push_back(')'); return boxString(llvm::StringRef(&chars[0], chars.size())); } try { std::string ty = std::string(self->cls->tp_name); chars.insert(chars.end(), ty.begin(), ty.end()); chars.push_back('('); chars.push_back('['); bool first = true; for (auto&& elt : self->s) { if (!first) { chars.push_back(','); chars.push_back(' '); } BoxedString* str = static_cast<BoxedString*>(repr(elt.value)); AUTO_DECREF(str); chars.insert(chars.end(), str->s().begin(), str->s().end()); first = false; } chars.push_back(']'); chars.push_back(')'); } catch (ExcInfo e) { Py_ReprLeave((PyObject*)self); throw e; } Py_ReprLeave((PyObject*)self); return boxString(llvm::StringRef(&chars[0], chars.size())); }
Box* tupleRepr(BoxedTuple* t) { assert(isSubclass(t->cls, tuple_cls)); int n; std::vector<char> chars; int status = Py_ReprEnter((PyObject*)t); n = t->size(); if (n == 0) { chars.push_back('('); chars.push_back(')'); return boxString(llvm::StringRef(&chars[0], chars.size())); } if (status != 0) { if (status < 0) throwCAPIException(); chars.push_back('('); chars.push_back('.'); chars.push_back('.'); chars.push_back('.'); chars.push_back(')'); return boxString(llvm::StringRef(&chars[0], chars.size())); } try { chars.push_back('('); for (int i = 0; i < n; i++) { if (i) { chars.push_back(','); chars.push_back(' '); } BoxedString* elt_repr = static_cast<BoxedString*>(repr(t->elts[i])); chars.insert(chars.end(), elt_repr->s().begin(), elt_repr->s().end()); } if (n == 1) chars.push_back(','); chars.push_back(')'); } catch (ExcInfo e) { Py_ReprLeave((PyObject*)t); throw e; } Py_ReprLeave((PyObject*)t); return boxString(llvm::StringRef(&chars[0], chars.size())); }
static Box* createAndRunModule(BoxedString* name, const std::string& fn, const std::string& module_path) { BoxedModule* module = createModule(name, fn.c_str()); Box* b_path = boxString(module_path); BoxedList* path_list = new BoxedList(); listAppendInternal(path_list, b_path); static BoxedString* path_str = internStringImmortal("__path__"); module->setattr(path_str, path_list, NULL); AST_Module* ast = caching_parse_file(fn.c_str(), /* future_flags = */ 0); assert(ast); try { compileAndRunModule(ast, module); } catch (ExcInfo e) { removeModule(name); throw e; } Box* r = getSysModulesDict()->getOrNull(name); if (!r) raiseExcHelper(ImportError, "Loaded module %.200s not found in sys.modules", name->c_str()); return r; }
void addToSysArgv(const char* str) { static BoxedString* argv_str = getStaticString("argv"); Box* sys_argv = sys_module->getattr(argv_str); assert(sys_argv); assert(sys_argv->cls == list_cls); listAppendInternalStolen(sys_argv, boxString(str)); }
Box* fileRead(BoxedFile* self, Box* _size) { assert(self->cls == file_cls); if (_size->cls != int_cls) { fprintf(stderr, "TypeError: an integer is required\n"); raiseExcHelper(TypeError, ""); } int64_t size = static_cast<BoxedInt*>(_size)->n; if (self->closed) { fprintf(stderr, "IOError: file not open for reading\n"); raiseExcHelper(IOError, ""); } std::ostringstream os(""); if (size < 0) size = 1L << 60; i64 read = 0; while (read < size) { const int BUF_SIZE = 1024; char buf[BUF_SIZE]; size_t more_read = fread(buf, 1, std::min((i64)BUF_SIZE, size - read), self->f); if (more_read == 0) { ASSERT(!ferror(self->f), "%d", ferror(self->f)); break; } read += more_read; // this is probably inefficient: os << std::string(buf, more_read); } return boxString(os.str()); }
static Box* methodGetDoc(Box* b, void*) { assert(b->cls == method_cls); const char* s = static_cast<BoxedMethodDescriptor*>(b)->method->ml_doc; if (s) return boxString(s); return None; }
Box* typeRepr(BoxedClass* self) { if (isUserDefined(self)) { std::ostringstream os; os << "<class '"; Box* m = self->getattr("__module__"); RELEASE_ASSERT(m, ""); if (m->cls == str_cls) { BoxedString* sm = static_cast<BoxedString*>(m); os << sm->s << '.'; } Box* n = self->getattr("__name__"); RELEASE_ASSERT(n, ""); RELEASE_ASSERT(n->cls == str_cls, "should have prevented you from setting __name__ to non-string"); BoxedString* sn = static_cast<BoxedString*>(n); os << sn->s; os << "'>"; return boxString(os.str()); } else { char buf[80]; snprintf(buf, 80, "<type '%s'>", getNameOfClass(self)->c_str()); return boxStrConstant(buf); } }
static Box* _fileRead(BoxedFile* self, i64 size) { if (self->closed) { fprintf(stderr, "IOError: file not open for reading\n"); raiseExc(); } std::ostringstream os(""); if (size < 0) size = 1L << 60; i64 read = 0; while (read < size) { const int BUF_SIZE = 1024; char buf[BUF_SIZE]; size_t more_read = fread(buf, 1, std::min((i64)BUF_SIZE, size - read), self->f); if (more_read == 0) { ASSERT(!ferror(self->f), "%d", ferror(self->f)); break; } read += more_read; // this is probably inefficient: os << std::string(buf, more_read); } return boxString(os.str()); }
extern "C" BoxedString* intRepr(BoxedInt* v) { if (!isSubclass(v->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__repr__' requires a 'int' object but received a '%s'", getTypeName(v)); char buf[80]; int len = snprintf(buf, 80, "%ld", v->n); return static_cast<BoxedString*>(boxString(llvm::StringRef(buf, len))); }
BoxedCode::BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, const char* name, const char* doc, const ParamNames& param_names) : source(nullptr), // TODO what to do with this? filename(nullptr), name(boxString(name)), // TODO what to do with this? firstlineno(-1), _doc(doc[0] == '\0' ? incref(Py_None) : boxString(doc)), param_names(param_names), takes_varargs(takes_varargs), takes_kwargs(takes_kwargs), num_args(num_args), times_interpreted(0), internal_callable(NULL, NULL) { }
static Box* varnames(Box* b, void*) { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast<BoxedCode*>(b); auto& param_names = code->f->param_names; if (!param_names.takes_param_names) return EmptyTuple; std::vector<Box*, StlCompatAllocator<Box*>> elts; for (auto sr : param_names.args) elts.push_back(boxString(sr)); if (param_names.vararg.size()) elts.push_back(boxString(param_names.vararg)); if (param_names.kwarg.size()) elts.push_back(boxString(param_names.kwarg)); return BoxedTuple::create(elts.size(), &elts[0]); }
Box* BoxedTraceback::getLines(Box* b) { assert(b->cls == traceback_cls); BoxedTraceback* tb = static_cast<BoxedTraceback*>(b); if (!tb->py_lines) { BoxedList* lines = new BoxedList(); for (BoxedTraceback* wtb = tb; wtb && wtb != None; wtb = static_cast<BoxedTraceback*>(wtb->tb_next)) { auto& line = wtb->line; auto l = BoxedTuple::create({ boxString(line.file), boxString(line.func), boxInt(line.line) }); listAppendInternal(lines, l); } tb->py_lines = lines; } return tb->py_lines; }
void setupThread() { // Hacky: we want to use some of CPython's implementation of the thread module (the threading local stuff), // and some of ours (thread handling). Start off by calling a cut-down version of initthread, and then // add our own attributes to the module it creates. initthread(); RELEASE_ASSERT(!PyErr_Occurred(), ""); Box* thread_module = getSysModulesDict()->getOrNull(boxString("thread")); assert(thread_module); thread_module->giveAttr("start_new_thread", new BoxedBuiltinFunctionOrMethod( boxRTFunction((void*)startNewThread, BOXED_INT, 3, 1, false, false), "start_new_thread", { NULL })); thread_module->giveAttr("allocate_lock", new BoxedBuiltinFunctionOrMethod( boxRTFunction((void*)allocateLock, UNKNOWN, 0), "allocate_lock")); thread_module->giveAttr( "get_ident", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)getIdent, BOXED_INT, 0), "get_ident")); thread_module->giveAttr( "stack_size", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)stackSize, BOXED_INT, 0), "stack_size")); thread_lock_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedThreadLock), false, "lock"); thread_lock_cls->tp_dealloc = BoxedThreadLock::threadLockDestructor; thread_lock_cls->has_safe_tp_dealloc = true; thread_lock_cls->giveAttr("__module__", boxString("thread")); thread_lock_cls->giveAttr( "acquire", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::acquire, BOXED_BOOL, 2, 1, false, false), { boxInt(1) })); thread_lock_cls->giveAttr("release", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::release, NONE, 1))); thread_lock_cls->giveAttr("acquire_lock", thread_lock_cls->getattr(internStringMortal("acquire"))); thread_lock_cls->giveAttr("release_lock", thread_lock_cls->getattr(internStringMortal("release"))); thread_lock_cls->giveAttr("__enter__", thread_lock_cls->getattr(internStringMortal("acquire"))); thread_lock_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::exit, NONE, 4))); thread_lock_cls->giveAttr("locked", new BoxedFunction(boxRTFunction((void*)BoxedThreadLock::locked, BOXED_BOOL, 1))); thread_lock_cls->giveAttr("locked_lock", thread_lock_cls->getattr(internStringMortal("locked"))); thread_lock_cls->freeze(); ThreadError = BoxedHeapClass::create(type_cls, Exception, NULL, Exception->attrs_offset, Exception->tp_weaklistoffset, Exception->tp_basicsize, false, "error"); ThreadError->giveAttr("__module__", boxString("thread")); ThreadError->freeze(); thread_module->giveAttr("error", ThreadError); }
extern "C" Box* createClass(std::string *name, BoxedModule *parent_module) { BoxedClass* rtn = new BoxedClass(true, NULL); rtn->giveAttr("__name__", boxString(*name)); Box* modname = parent_module->getattr("__name__", NULL, NULL); rtn->giveAttr("__module__", modname); return rtn; }
Box* getDocString(llvm::ArrayRef<AST_stmt*> body) { if (body.size() > 0 && body[0]->type == AST_TYPE::Expr && static_cast<AST_Expr*>(body[0])->value->type == AST_TYPE::Str) { auto expr = static_cast<AST_Expr*>(body[0]); auto str = static_cast<AST_Str*>(expr->value); return boxString(str->str_data); } return incref(Py_None); }
extern "C" BoxedFunction::BoxedFunction(CLFunction *f) : HCBox(&function_flavor, function_cls), f(f) { if (f->source) { assert(f->source->ast); //this->giveAttr("__name__", boxString(&f->source->ast->name)); this->giveAttr("__name__", boxString(f->source->getName())); Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL); this->giveAttr("__module__", modname); } }
extern "C" Box* chr(Box* arg) { if (arg->cls != int_cls) { fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg)->c_str()); raiseExc(); } i64 n = static_cast<BoxedInt*>(arg)->n; RELEASE_ASSERT(n >= 0 && n < 256, ""); return boxString(std::string(1, (char)n)); }
void setupSysEnd() { std::vector<Box*> builtin_module_names; for (int i = 0; PyImport_Inittab[i].name != NULL; i++) builtin_module_names.push_back(boxString(PyImport_Inittab[i].name)); std::sort<decltype(builtin_module_names)::iterator, PyLt>(builtin_module_names.begin(), builtin_module_names.end(), PyLt()); sys_module->giveAttr("builtin_module_names", BoxedTuple::create(builtin_module_names.size(), &builtin_module_names[0])); for (Box* b : builtin_module_names) Py_DECREF(b); #ifndef NDEBUG for (const auto& p : *sys_modules_dict) { assert(PyString_Check(p.first)); bool found = false; for (int i = 0; PyImport_Inittab[i].name != NULL; i++) { if (((BoxedString*)p.first)->s() == PyImport_Inittab[i].name) { found = true; } } if (!found) assert(0 && "found a module which is inside sys.modules but not listed inside PyImport_Inittab!"); } #endif /* version_info */ if (VersionInfoType.tp_name == 0) PyStructSequence_InitType((PyTypeObject*)&VersionInfoType, &version_info_desc); /* prevent user from creating new instances */ VersionInfoType.tp_init = NULL; VersionInfoType.tp_new = NULL; SET_SYS_FROM_STRING("version_info", make_version_info()); /* float_info */ if (FloatInfoType.tp_name == 0) PyStructSequence_InitType((PyTypeObject*)&FloatInfoType, &float_info_desc); /* flags */ if (FlagsType.tp_name == 0) PyStructSequence_InitType((PyTypeObject*)&FlagsType, &flags_desc); SET_SYS_FROM_STRING("flags", make_flags()); /* prevent user from creating new instances */ FlagsType.tp_init = NULL; FlagsType.tp_new = NULL; /* prevent user from creating new instances */ FloatInfoType.tp_init = NULL; FloatInfoType.tp_new = NULL; SET_SYS_FROM_STRING("float_info", PyFloat_GetInfo()); }
Box* moduleRepr(BoxedModule* m) { assert(m->cls == module_cls); std::ostringstream os; os << "<module '" << m->name() << "' "; if (m->fn == "__builtin__") { os << "(built-in)>"; } else { os << "from '" << m->fn << "'>"; } return boxString(os.str()); }
Box* tupleRepr(BoxedTuple* t) { assert(isSubclass(t->cls, tuple_cls)); int n; std::string O(""); llvm::raw_string_ostream os(O); n = t->size(); if (n == 0) { os << "()"; return boxString(os.str()); } int status = Py_ReprEnter((PyObject*)t); if (status != 0) { if (status < 0) return boxString(os.str()); os << "(...)"; return boxString(os.str()); } os << "("; for (int i = 0; i < n; i++) { if (i) os << ", "; BoxedString* elt_repr = static_cast<BoxedString*>(repr(t->elts[i])); os << elt_repr->s(); } if (n == 1) os << ","; os << ")"; Py_ReprLeave((PyObject*)t); return boxString(os.str()); }
extern "C" Box* intOct(BoxedInt* self) { if (!isSubclass(self->cls, int_cls)) raiseExcHelper(TypeError, "descriptor '__oct__' requires a 'int' object but received a '%s'", getTypeName(self)); char buf[80]; int len = 0; bool is_negative = self->n < 0; if (is_negative) len = snprintf(buf, sizeof(buf), "-%#lo", std::abs(self->n)); else len = snprintf(buf, sizeof(buf), "%#lo", self->n); return boxString(llvm::StringRef(buf, len)); }
BoxedString* internStringImmortal(llvm::StringRef s) noexcept { auto it = interned_strings.find_as(s); if (it != interned_strings.end()) return incref(*it); num_interned_strings.log(); BoxedString* entry = boxString(s); // CPython returns mortal but in our current implementation they are inmortal entry->interned_state = SSTATE_INTERNED_IMMORTAL; interned_strings.insert((BoxedString*)entry); Py_INCREF(entry); return entry; }
static Box* _setRepr(BoxedSet* self, const char* type_name) { std::ostringstream os(""); os << type_name << "(["; bool first = true; for (Box* elt : self->s) { if (!first) { os << ", "; } os << static_cast<BoxedString*>(repr(elt))->s; first = false; } os << "])"; return boxString(os.str()); }
extern "C" void raise0_capi(ExcInfo* frame_exc_info) noexcept { updateFrameExcInfoIfNeeded(frame_exc_info); assert(frame_exc_info->type); // TODO need to clean up when we call normalize, do_raise, etc if (frame_exc_info->type == None) { frame_exc_info->type = TypeError; frame_exc_info->value = boxString("exceptions must be old-style classes or derived from BaseException, not NoneType"); frame_exc_info->traceback = None; PyErr_NormalizeException(&frame_exc_info->type, &frame_exc_info->value, &frame_exc_info->traceback); } startReraise(); PyErr_Restore(frame_exc_info->type, frame_exc_info->value, frame_exc_info->traceback); }
Box* BoxedCode::varnames(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast<BoxedCode*>(b); auto& param_names = code->param_names; if (!param_names.takes_param_names) return incref(EmptyTuple); std::vector<Box*> elts; for (auto sr : param_names.allArgsAsStr()) elts.push_back(boxString(sr)); auto rtn = BoxedTuple::create(elts.size(), &elts[0]); for (auto e : elts) Py_DECREF(e); return rtn; }
void prependToSysPath(llvm::StringRef path) { BoxedList* sys_path = getSysPath(); static BoxedString* insert_str = internStringImmortal("insert"); CallattrFlags callattr_flags{.cls_only = false, .null_on_nonexistent = false, .argspec = ArgPassSpec(2) }; callattr(sys_path, insert_str, callattr_flags, boxInt(0), boxString(path), NULL, NULL, NULL); } static BoxedClass* sys_flags_cls; class BoxedSysFlags : public Box { public: Box* division_warning, *bytes_warning, *no_user_site, *optimize; BoxedSysFlags() { auto zero = boxInt(0); assert(zero); division_warning = zero; bytes_warning = zero; no_user_site = zero; optimize = zero; } DEFAULT_CLASS(sys_flags_cls); static void gcHandler(GCVisitor* v, Box* _b) { assert(_b->cls == sys_flags_cls); Box::gcHandler(v, _b); BoxedSysFlags* self = static_cast<BoxedSysFlags*>(_b); v->visit(self->division_warning); v->visit(self->bytes_warning); v->visit(self->no_user_site); v->visit(self->optimize); } static Box* __new__(Box* cls, Box* args, Box* kwargs) { raiseExcHelper(TypeError, "cannot create 'sys.flags' instances"); } }; static std::string generateVersionString() { std::ostringstream oss; oss << PYTHON_VERSION_MAJOR << '.' << PYTHON_VERSION_MINOR << '.' << PYTHON_VERSION_MICRO; oss << '\n'; oss << "[Pyston " << PYSTON_VERSION_MAJOR << '.' << PYSTON_VERSION_MINOR << "]"; return oss.str(); }
Box* fileReadline1(BoxedFile* self) { assert(self->cls == file_cls); std::ostringstream os(""); while (true) { char c; int nread = fread(&c, 1, 1, self->f); if (nread == 0) break; os << c; if (c == '\n') break; } return boxString(os.str()); }
Box* moduleRepr(BoxedModule* m) { assert(m->cls == module_cls); std::ostringstream os; os << "<module '"; Box* name = m->peekattr("__name__"); if (!name || name->cls != str_cls) { os << '?'; } else { BoxedString *sname = static_cast<BoxedString*>(name); os << sname->s; } // TODO not all modules will be built-in os << "' (built-in)>"; return boxString(os.str()); }
extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults) : Box(&function_flavor, function_cls), f(f), ndefaults(0), defaults(NULL) { // make sure to initialize defaults first, since the GC behavior is triggered by ndefaults, // and a GC can happen within this constructor: this->defaults = new (defaults.size()) GCdArray(); memcpy(this->defaults->elts, defaults.begin(), defaults.size() * sizeof(Box*)); this->ndefaults = defaults.size(); if (f->source) { assert(f->source->ast); // this->giveAttr("__name__", boxString(&f->source->ast->name)); this->giveAttr("__name__", boxString(f->source->getName())); Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL); this->giveAttr("__module__", modname); } assert(f->num_defaults == ndefaults); }