Commit 68af64c1 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'merge'

parents b0aea029 1da4cefb
...@@ -48,7 +48,9 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe ...@@ -48,7 +48,9 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
} else { } else {
RELEASE_ASSERT(0, "0x%x", ml_flags); RELEASE_ASSERT(0, "0x%x", ml_flags);
} }
assert(rtn);
checkAndThrowCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn; return rtn;
} }
} }
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef PYSTON_CAPI_TYPES_H #ifndef PYSTON_CAPI_TYPES_H
#define PYSTON_CAPI_TYPES_H #define PYSTON_CAPI_TYPES_H
#include "runtime/capi.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
...@@ -74,7 +75,9 @@ public: ...@@ -74,7 +75,9 @@ public:
} else { } else {
RELEASE_ASSERT(0, "0x%x", self->ml_flags); RELEASE_ASSERT(0, "0x%x", self->ml_flags);
} }
RELEASE_ASSERT(rtn, "need to throw an exception");
checkAndThrowCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn; return rtn;
} }
}; };
...@@ -106,13 +109,17 @@ public: ...@@ -106,13 +109,17 @@ public:
wrapperfunc wrapper = self->descr->wrapper->wrapper; wrapperfunc wrapper = self->descr->wrapper->wrapper;
assert(self->descr->wrapper->offset > 0); assert(self->descr->wrapper->offset > 0);
Box* rtn;
if (flags & PyWrapperFlag_KEYWORDS) { if (flags & PyWrapperFlag_KEYWORDS) {
wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
return (*wk)(self->obj, args, self->descr->wrapped, kwds); rtn = (*wk)(self->obj, args, self->descr->wrapped, kwds);
} else { } else {
return (*wrapper)(self->obj, args, self->descr->wrapped); rtn = (*wrapper)(self->obj, args, self->descr->wrapped);
} }
abort();
checkAndThrowCAPIException();
assert(rtn && "should have set + thrown an exception!");
return rtn;
} }
}; };
......
...@@ -18,6 +18,9 @@ namespace pyston { ...@@ -18,6 +18,9 @@ namespace pyston {
int GLOBAL_VERBOSITY = 0; int GLOBAL_VERBOSITY = 0;
int PYSTON_VERSION_MAJOR = 0;
int PYSTON_VERSION_MINOR = 2;
int PYTHON_VERSION_MAJOR = DEFAULT_PYTHON_MAJOR_VERSION; int PYTHON_VERSION_MAJOR = DEFAULT_PYTHON_MAJOR_VERSION;
int PYTHON_VERSION_MINOR = DEFAULT_PYTHON_MINOR_VERSION; int PYTHON_VERSION_MINOR = DEFAULT_PYTHON_MINOR_VERSION;
int PYTHON_VERSION_MICRO = DEFAULT_PYTHON_MICRO_VERSION; int PYTHON_VERSION_MICRO = DEFAULT_PYTHON_MICRO_VERSION;
......
...@@ -21,6 +21,7 @@ extern "C" { ...@@ -21,6 +21,7 @@ extern "C" {
extern int GLOBAL_VERBOSITY; extern int GLOBAL_VERBOSITY;
#define VERBOSITY(x) GLOBAL_VERBOSITY #define VERBOSITY(x) GLOBAL_VERBOSITY
extern int PYSTON_VERSION_MAJOR, PYSTON_VERSION_MINOR;
// Version number we're targeting: // Version number we're targeting:
extern int PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO, PYTHON_VERSION_HEX; extern int PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO, PYTHON_VERSION_HEX;
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
namespace pyston { namespace pyston {
namespace threading { namespace threading {
__thread ThreadState cur_thread_state
= { NULL, NULL, NULL }; // not sure if we need to explicitly request zero-initialization
PthreadFastMutex threading_lock; PthreadFastMutex threading_lock;
// Certain thread examination functions won't be valid for a brief // Certain thread examination functions won't be valid for a brief
...@@ -128,7 +131,7 @@ static void pushThreadState(pthread_t tid, ucontext_t* context) { ...@@ -128,7 +131,7 @@ static void pushThreadState(pthread_t tid, ucontext_t* context) {
void* stack_end = (void*)(context->uc_mcontext.gregs[REG_RSP] + sizeof(void*)); void* stack_end = (void*)(context->uc_mcontext.gregs[REG_RSP] + sizeof(void*));
#endif #endif
assert(stack_start < stack_end); assert(stack_start < stack_end);
thread_states.push_back(ThreadGCState(tid, context, stack_start, stack_end)); thread_states.push_back(ThreadGCState(tid, context, stack_start, stack_end, &cur_thread_state));
} }
std::vector<ThreadGCState> getAllThreadStates() { std::vector<ThreadGCState> getAllThreadStates() {
...@@ -252,6 +255,7 @@ static void* _thread_start(void* _arg) { ...@@ -252,6 +255,7 @@ static void* _thread_start(void* _arg) {
} }
threading::GLReadRegion _glock; threading::GLReadRegion _glock;
assert(!PyErr_Occurred());
void* rtn = start_func(arg1, arg2, arg3); void* rtn = start_func(arg1, arg2, arg3);
current_threads[current_thread]->assertNoGenerators(); current_threads[current_thread]->assertNoGenerators();
...@@ -350,6 +354,8 @@ void registerMainThread() { ...@@ -350,6 +354,8 @@ void registerMainThread() {
int code = sigaction(SIGUSR2, &act, &oldact); int code = sigaction(SIGUSR2, &act, &oldact);
if (code) if (code)
err(1, NULL); err(1, NULL);
assert(!PyErr_Occurred());
} }
void finishMainThread() { void finishMainThread() {
......
...@@ -28,8 +28,14 @@ class Box; ...@@ -28,8 +28,14 @@ class Box;
namespace threading { namespace threading {
// Whether or not a second thread was ever started:
bool threadWasStarted(); bool threadWasStarted();
struct ThreadState {
Box* curexc_type, *curexc_value, *curexc_traceback;
};
extern __thread ThreadState cur_thread_state;
// returns a thread id (currently, the pthread_t id) // returns a thread id (currently, the pthread_t id)
intptr_t start_thread(void* (*start_func)(Box*, Box*, Box*), Box* arg1, Box* arg2, Box* arg3); intptr_t start_thread(void* (*start_func)(Box*, Box*, Box*), Box* arg1, Box* arg2, Box* arg3);
...@@ -45,8 +51,10 @@ struct ThreadGCState { ...@@ -45,8 +51,10 @@ struct ThreadGCState {
// in a generator, but those generators will be tracked separately. // in a generator, but those generators will be tracked separately.
void* stack_start, *stack_end; void* stack_start, *stack_end;
ThreadGCState(pthread_t tid, ucontext_t* ucontext, void* stack_start, void* stack_end) ThreadState* thread_state;
: tid(tid), ucontext(ucontext), stack_start(stack_start), stack_end(stack_end) {}
ThreadGCState(pthread_t tid, ucontext_t* ucontext, void* stack_start, void* stack_end, ThreadState* thread_state)
: tid(tid), ucontext(ucontext), stack_start(stack_start), stack_end(stack_end), thread_state(thread_state) {}
}; };
// Gets a ThreadGCState per thread, not including the thread calling this function. // Gets a ThreadGCState per thread, not including the thread calling this function.
// For this call to make sense, the threads all should be blocked; // For this call to make sense, the threads all should be blocked;
......
...@@ -47,11 +47,20 @@ void collectRoots(void* start, void* end, TraceStack* stack) { ...@@ -47,11 +47,20 @@ void collectRoots(void* start, void* end, TraceStack* stack) {
void collectOtherThreadsStacks(TraceStack* stack) { void collectOtherThreadsStacks(TraceStack* stack) {
GCVisitor v(stack);
std::vector<threading::ThreadGCState> threads = threading::getAllThreadStates(); std::vector<threading::ThreadGCState> threads = threading::getAllThreadStates();
for (threading::ThreadGCState& tstate : threads) { for (threading::ThreadGCState& tstate : threads) {
collectRoots(tstate.stack_start, tstate.stack_end, stack); collectRoots(tstate.stack_start, tstate.stack_end, stack);
collectRoots(tstate.ucontext, tstate.ucontext + 1, stack); collectRoots(tstate.ucontext, tstate.ucontext + 1, stack);
if (tstate.thread_state->curexc_type)
v.visit(tstate.thread_state->curexc_type);
if (tstate.thread_state->curexc_value)
v.visit(tstate.thread_state->curexc_value);
if (tstate.thread_state->curexc_traceback)
v.visit(tstate.thread_state->curexc_traceback);
} }
} }
...@@ -75,6 +84,14 @@ static void collectLocalStack(TraceStack* stack) { ...@@ -75,6 +84,14 @@ static void collectLocalStack(TraceStack* stack) {
#else #else
collectRoots(stack_bottom, stack_top, stack); collectRoots(stack_bottom, stack_top, stack);
#endif #endif
GCVisitor v(stack);
if (threading::cur_thread_state.curexc_type)
v.visit(threading::cur_thread_state.curexc_type);
if (threading::cur_thread_state.curexc_value)
v.visit(threading::cur_thread_state.curexc_value);
if (threading::cur_thread_state.curexc_traceback)
v.visit(threading::cur_thread_state.curexc_traceback);
} }
void collectStackRoots(TraceStack* stack) { void collectStackRoots(TraceStack* stack) {
......
...@@ -153,7 +153,7 @@ int main(int argc, char** argv) { ...@@ -153,7 +153,7 @@ int main(int argc, char** argv) {
} }
if (repl) { if (repl) {
printf("Pyston v0.2 (rev " STRINGIFY(GITREV) ")"); printf("Pyston v%d.%d (rev " STRINGIFY(GITREV) ")", PYSTON_VERSION_MAJOR, PYSTON_VERSION_MINOR);
printf(", targeting Python %d.%d.%d\n", PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO); printf(", targeting Python %d.%d.%d\n", PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO);
if (!main_module) { if (!main_module) {
......
...@@ -99,6 +99,12 @@ extern "C" Box* dir(Box* obj) { ...@@ -99,6 +99,12 @@ extern "C" Box* dir(Box* obj) {
return result; return result;
} }
extern "C" Box* vars(Box* obj) {
RELEASE_ASSERT(obj, "Don't support 0-arg vars() calls yet");
return makeAttrWrapper(obj);
}
extern "C" Box* abs_(Box* x) { extern "C" Box* abs_(Box* x) {
if (x->cls == int_cls) { if (x->cls == int_cls) {
i64 n = static_cast<BoxedInt*>(x)->n; i64 n = static_cast<BoxedInt*>(x)->n;
...@@ -340,13 +346,21 @@ Box* isinstance_func(Box* obj, Box* cls) { ...@@ -340,13 +346,21 @@ Box* isinstance_func(Box* obj, Box* cls) {
} }
Box* issubclass_func(Box* child, Box* parent) { Box* issubclass_func(Box* child, Box* parent) {
if (parent->cls == classobj_cls) { if (child->cls != type_cls && child->cls != classobj_cls)
Py_FatalError("don't handle issubclass for old style classes yet"); raiseExcHelper(TypeError, "issubclass() arg 1 must be a class");
RELEASE_ASSERT(parent->cls != tuple_cls, "unsupported");
if (child->cls == classobj_cls) {
if (parent->cls != classobj_cls)
return False;
return boxBool(classobjIssubclass(static_cast<BoxedClassobj*>(child), static_cast<BoxedClassobj*>(parent)));
} }
RELEASE_ASSERT(child->cls == type_cls, ""); assert(child->cls == type_cls);
// TODO parent can also be a tuple of classes if (parent->cls != type_cls)
RELEASE_ASSERT(parent->cls == type_cls, ""); return False;
return boxBool(isSubclass(static_cast<BoxedClass*>(child), static_cast<BoxedClass*>(parent))); return boxBool(isSubclass(static_cast<BoxedClass*>(child), static_cast<BoxedClass*>(parent)));
} }
...@@ -911,6 +925,8 @@ void setupBuiltins() { ...@@ -911,6 +925,8 @@ void setupBuiltins() {
builtins_module->giveAttr("filter", new BoxedFunction(boxRTFunction((void*)filter2, LIST, 2))); builtins_module->giveAttr("filter", new BoxedFunction(boxRTFunction((void*)filter2, LIST, 2)));
builtins_module->giveAttr("zip", new BoxedFunction(boxRTFunction((void*)zip2, LIST, 2))); builtins_module->giveAttr("zip", new BoxedFunction(boxRTFunction((void*)zip2, LIST, 2)));
builtins_module->giveAttr("dir", new BoxedFunction(boxRTFunction((void*)dir, LIST, 1, 1, false, false), { NULL })); builtins_module->giveAttr("dir", new BoxedFunction(boxRTFunction((void*)dir, LIST, 1, 1, false, false), { NULL }));
builtins_module->giveAttr("vars",
new BoxedFunction(boxRTFunction((void*)vars, LIST, 1, 1, false, false), { NULL }));
builtins_module->giveAttr("object", object_cls); builtins_module->giveAttr("object", object_cls);
builtins_module->giveAttr("str", str_cls); builtins_module->giveAttr("str", str_cls);
builtins_module->giveAttr("basestring", basestring_cls); builtins_module->giveAttr("basestring", basestring_cls);
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <sstream>
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
...@@ -99,6 +103,14 @@ public: ...@@ -99,6 +103,14 @@ public:
} }
}; };
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();
}
void setupSys() { void setupSys() {
sys_modules_dict = new BoxedDict(); sys_modules_dict = new BoxedDict();
gc::registerPermanentRoot(sys_modules_dict); gc::registerPermanentRoot(sys_modules_dict);
...@@ -122,6 +134,23 @@ void setupSys() { ...@@ -122,6 +134,23 @@ void setupSys() {
sys_module->giveAttr("platform", boxStrConstant("unknown")); // seems like a reasonable, if poor, default sys_module->giveAttr("platform", boxStrConstant("unknown")); // seems like a reasonable, if poor, default
llvm::SmallString<128> main_fn;
// TODO supposed to pass argv0, main_addr to this function:
main_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
sys_module->giveAttr("executable", boxString(main_fn.str()));
// TODO: should configure this in a better way
sys_module->giveAttr("prefix", boxStrConstant("/usr"));
sys_module->giveAttr("exec_prefix", boxStrConstant("/usr"));
sys_module->giveAttr("copyright",
boxStrConstant("Copyright 2014 Dropbox.\nAll Rights Reserved.\n\nCopyright (c) 2001-2014 "
"Python Software Foundation.\nAll Rights Reserved.\n\nCopyright (c) 2000 "
"BeOpen.com.\nAll Rights Reserved.\n\nCopyright (c) 1995-2001 Corporation for "
"National Research Initiatives.\nAll Rights Reserved.\n\nCopyright (c) "
"1991-1995 Stichting Mathematisch Centrum, Amsterdam.\nAll Rights Reserved."));
sys_module->giveAttr("version", boxString(generateVersionString()));
sys_module->giveAttr("hexversion", boxInt(PY_VERSION_HEX)); sys_module->giveAttr("hexversion", boxInt(PY_VERSION_HEX));
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX)); sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
......
...@@ -482,9 +482,28 @@ extern "C" int PyCallable_Check(PyObject* x) { ...@@ -482,9 +482,28 @@ extern "C" int PyCallable_Check(PyObject* x) {
return typeLookup(x->cls, call_attr, NULL) != NULL; return typeLookup(x->cls, call_attr, NULL) != NULL;
} }
void checkAndThrowCAPIException() {
Box* value = threading::cur_thread_state.curexc_value;
if (value) {
RELEASE_ASSERT(threading::cur_thread_state.curexc_traceback == NULL, "unsupported");
// This doesn't seem like the right behavior...
if (value->cls == tuple_cls) {
BoxedTuple* args = static_cast<BoxedTuple*>(value);
value = runtimeCall(threading::cur_thread_state.curexc_type, ArgPassSpec(0, 0, true, false), args, NULL,
NULL, NULL, NULL);
}
RELEASE_ASSERT(value->cls == threading::cur_thread_state.curexc_type, "unsupported");
PyErr_Clear();
throw value;
}
}
extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) { extern "C" void PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback) {
Py_FatalError("setting exceptions from the C API is current unimplemented"); threading::cur_thread_state.curexc_type = type;
threading::cur_thread_state.curexc_value = value;
threading::cur_thread_state.curexc_traceback = traceback;
} }
extern "C" void PyErr_Clear() { extern "C" void PyErr_Clear() {
...@@ -516,9 +535,7 @@ extern "C" int PyErr_ExceptionMatches(PyObject* exc) { ...@@ -516,9 +535,7 @@ extern "C" int PyErr_ExceptionMatches(PyObject* exc) {
} }
extern "C" PyObject* PyErr_Occurred() { extern "C" PyObject* PyErr_Occurred() {
// While there clearly needs to be more here, I think this is ok for now because all of the exception-setting return threading::cur_thread_state.curexc_type;
// functions will abort()
return NULL;
} }
extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t stacklevel) { extern "C" int PyErr_WarnEx(PyObject* category, const char* text, Py_ssize_t stacklevel) {
......
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
#ifndef PYSTON_RUNTIME_CAPI_H #ifndef PYSTON_RUNTIME_CAPI_H
#define PYSTON_RUNTIME_CAPI_H #define PYSTON_RUNTIME_CAPI_H
#include <cstring> #include <string>
namespace pyston { namespace pyston {
class BoxedModule; class BoxedModule;
BoxedModule* importTestExtension(const std::string&); BoxedModule* importTestExtension(const std::string&);
void checkAndThrowCAPIException();
} }
#endif #endif
...@@ -25,19 +25,19 @@ namespace pyston { ...@@ -25,19 +25,19 @@ namespace pyston {
BoxedClass* classobj_cls, *instance_cls; BoxedClass* classobj_cls, *instance_cls;
bool classIssubclass(BoxedClassobj* child, BoxedClassobj* parent) { bool classobjIssubclass(BoxedClassobj* child, BoxedClassobj* parent) {
if (child == parent) if (child == parent)
return true; return true;
for (auto e : child->bases->elts) { for (auto e : child->bases->elts) {
if (e->cls == classobj_cls && classIssubclass(static_cast<BoxedClassobj*>(e), parent)) if (e->cls == classobj_cls && classobjIssubclass(static_cast<BoxedClassobj*>(e), parent))
return true; return true;
} }
return false; return false;
} }
bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls) { bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls) {
return classIssubclass(obj->inst_cls, cls); return classobjIssubclass(obj->inst_cls, cls);
} }
static Box* classLookup(BoxedClassobj* cls, const std::string& attr) { static Box* classLookup(BoxedClassobj* cls, const std::string& attr) {
...@@ -142,6 +142,13 @@ static Box* _instanceGetattribute(Box* _inst, Box* _attr, bool raise_on_missing) ...@@ -142,6 +142,13 @@ static Box* _instanceGetattribute(Box* _inst, Box* _attr, bool raise_on_missing)
BoxedString* attr = static_cast<BoxedString*>(_attr); BoxedString* attr = static_cast<BoxedString*>(_attr);
// TODO: special handling for accessing __dict__ and __class__ // TODO: special handling for accessing __dict__ and __class__
if (attr->s[0] == '_' && attr->s[1] == '_') {
if (attr->s == "__dict__")
return makeAttrWrapper(inst);
if (attr->s == "__class__")
return inst->inst_cls;
}
Box* r = inst->getattr(attr->s); Box* r = inst->getattr(attr->s);
if (r) if (r)
...@@ -155,7 +162,11 @@ static Box* _instanceGetattribute(Box* _inst, Box* _attr, bool raise_on_missing) ...@@ -155,7 +162,11 @@ static Box* _instanceGetattribute(Box* _inst, Box* _attr, bool raise_on_missing)
static const std::string getattr_str("__getattr__"); static const std::string getattr_str("__getattr__");
Box* getattr = classLookup(inst->inst_cls, getattr_str); Box* getattr = classLookup(inst->inst_cls, getattr_str);
RELEASE_ASSERT(getattr == NULL, "unimplemented");
if (getattr) {
getattr = processDescriptor(getattr, inst, inst->inst_cls);
return runtimeCall(getattr, ArgPassSpec(1), _attr, NULL, NULL, NULL, NULL);
}
if (!raise_on_missing) if (!raise_on_missing)
return NULL; return NULL;
...@@ -204,10 +215,22 @@ Box* instanceNonzero(Box* _inst) { ...@@ -204,10 +215,22 @@ Box* instanceNonzero(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
Box* nonzero_func = _instanceGetattribute(inst, boxStrConstant("__nonzero__"), false); Box* nonzero_func = NULL;
try {
nonzero_func = _instanceGetattribute(inst, boxStrConstant("__nonzero__"), false);
} catch (Box* b) {
if (!isInstance(b, AttributeError))
throw;
}
if (nonzero_func == NULL) if (nonzero_func == NULL) {
nonzero_func = _instanceGetattribute(inst, boxStrConstant("__len__"), false); try {
nonzero_func = _instanceGetattribute(inst, boxStrConstant("__len__"), false);
} catch (Box* b) {
if (!isInstance(b, AttributeError))
throw;
}
}
if (nonzero_func) { if (nonzero_func) {
return runtimeCall(nonzero_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); return runtimeCall(nonzero_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
......
...@@ -27,6 +27,7 @@ class BoxedInstance; ...@@ -27,6 +27,7 @@ class BoxedInstance;
extern BoxedClass* classobj_cls, *instance_cls; extern BoxedClass* classobj_cls, *instance_cls;
bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls); bool instanceIsinstance(BoxedInstance* obj, BoxedClassobj* cls);
bool classobjIssubclass(BoxedClassobj* child, BoxedClassobj* parent);
class BoxedClassobj : public Box { class BoxedClassobj : public Box {
public: public:
......
...@@ -94,8 +94,7 @@ Box* fileWrite(BoxedFile* self, Box* val) { ...@@ -94,8 +94,7 @@ Box* fileWrite(BoxedFile* self, Box* val) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
if (self->closed) { if (self->closed) {
fprintf(stderr, "IOError: file is closed\n"); raiseExcHelper(IOError, "file is closed");
raiseExcHelper(IOError, "");
} }
...@@ -129,6 +128,16 @@ Box* fileWrite(BoxedFile* self, Box* val) { ...@@ -129,6 +128,16 @@ Box* fileWrite(BoxedFile* self, Box* val) {
} }
} }
Box* fileFlush(BoxedFile* self) {
RELEASE_ASSERT(self->cls == file_cls, "");
if (self->closed)
raiseExcHelper(IOError, "file is closed");
fflush(self->f);
return None;
}
Box* fileClose(BoxedFile* self) { Box* fileClose(BoxedFile* self) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
if (self->closed) { if (self->closed) {
...@@ -199,6 +208,7 @@ void setupFile() { ...@@ -199,6 +208,7 @@ void setupFile() {
CLFunction* readline = boxRTFunction((void*)fileReadline1, STR, 1); CLFunction* readline = boxRTFunction((void*)fileReadline1, STR, 1);
file_cls->giveAttr("readline", new BoxedFunction(readline)); file_cls->giveAttr("readline", new BoxedFunction(readline));
file_cls->giveAttr("flush", new BoxedFunction(boxRTFunction((void*)fileFlush, NONE, 1)));
file_cls->giveAttr("write", new BoxedFunction(boxRTFunction((void*)fileWrite, NONE, 2))); file_cls->giveAttr("write", new BoxedFunction(boxRTFunction((void*)fileWrite, NONE, 2)));
file_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)fileClose, NONE, 1))); file_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)fileClose, NONE, 1)));
......
...@@ -248,6 +248,10 @@ extern "C" void my_assert(bool b) { ...@@ -248,6 +248,10 @@ extern "C" void my_assert(bool b) {
assert(b); assert(b);
} }
bool isInstance(Box* obj, BoxedClass* cls) {
return isSubclass(obj->cls, cls);
}
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent) { extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent) {
// TODO the class is allowed to override this using __subclasscheck__ // TODO the class is allowed to override this using __subclasscheck__
while (child) { while (child) {
...@@ -2136,6 +2140,17 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa ...@@ -2136,6 +2140,17 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa
return chosen_cf; return chosen_cf;
} }
static std::string getFunctionName(CLFunction* f) {
if (f->source)
return f->source->getName();
else if (f->versions.size()) {
std::ostringstream oss;
oss << "<function at " << f->versions[0]->code << ">";
return oss.str();
}
return "<unknown function>";
}
static void placeKeyword(const std::vector<AST_expr*>& arg_names, std::vector<bool>& params_filled, static void placeKeyword(const std::vector<AST_expr*>& arg_names, std::vector<bool>& params_filled,
const std::string& kw_name, Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs, const std::string& kw_name, Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs,
BoxedDict* okwargs) { BoxedDict* okwargs) {
...@@ -2316,17 +2331,9 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2316,17 +2331,9 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
Box* ovarargs = new BoxedTuple(unused_positional); Box* ovarargs = new BoxedTuple(unused_positional);
getArg(varargs_idx, oarg1, oarg2, oarg3, oargs) = ovarargs; getArg(varargs_idx, oarg1, oarg2, oarg3, oargs) = ovarargs;
} else if (unused_positional.size()) { } else if (unused_positional.size()) {
std::string name = "<unknown function>"; raiseExcHelper(TypeError, "%s() takes at most %d argument%s (%d given)", getFunctionName(f).c_str(),
if (f->source) f->num_args, (f->num_args == 1 ? "" : "s"),
name = f->source->getName(); argspec.num_args + argspec.num_keywords + varargs.size());
else if (f->versions.size()) {
std::ostringstream oss;
oss << "<function at " << f->versions[0]->code << ">";
name = oss.str();
}
raiseExcHelper(TypeError, "%s() takes at most %d argument%s (%d given)", name.c_str(), f->num_args,
(f->num_args == 1 ? "" : "s"), argspec.num_args + argspec.num_keywords + varargs.size());
} }
//// ////
...@@ -2341,7 +2348,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2341,7 +2348,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
const std::vector<AST_expr*>* arg_names = f->source ? f->source->arg_names.args : NULL; const std::vector<AST_expr*>* arg_names = f->source ? f->source->arg_names.args : NULL;
if (arg_names == nullptr && argspec.num_keywords && !f->takes_kwargs) { if (arg_names == nullptr && argspec.num_keywords && !f->takes_kwargs) {
raiseExcHelper(TypeError, "<function @%p>() doesn't take keyword arguments", f->versions[0]->code); raiseExcHelper(TypeError, "%s() doesn't take keyword arguments", getFunctionName(f).c_str());
} }
if (argspec.num_keywords) if (argspec.num_keywords)
...@@ -2374,7 +2381,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2374,7 +2381,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
for (auto& p : d_kwargs->d) { for (auto& p : d_kwargs->d) {
if (p.first->cls != str_cls) if (p.first->cls != str_cls)
raiseExcHelper(TypeError, "<function>() keywords must be strings"); raiseExcHelper(TypeError, "%s() keywords must be strings", getFunctionName(f).c_str());
BoxedString* s = static_cast<BoxedString*>(p.first); BoxedString* s = static_cast<BoxedString*>(p.first);
...@@ -2385,8 +2392,8 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2385,8 +2392,8 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
Box*& v = okwargs->d[p.first]; Box*& v = okwargs->d[p.first];
if (v) { if (v) {
raiseExcHelper(TypeError, "<function>() got multiple values for keyword argument '%s'", raiseExcHelper(TypeError, "%s() got multiple values for keyword argument '%s'",
s->s.c_str()); getFunctionName(f).c_str(), s->s.c_str());
} }
v = p.second; v = p.second;
} }
...@@ -2399,7 +2406,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2399,7 +2406,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (params_filled[i]) if (params_filled[i])
continue; continue;
// TODO not right error message // TODO not right error message
raiseExcHelper(TypeError, "<function>() did not get a value for positional argument %d", i); raiseExcHelper(TypeError, "%s() did not get a value for positional argument %d", getFunctionName(f).c_str(), i);
} }
RewriterVar* r_defaults_array = NULL; RewriterVar* r_defaults_array = NULL;
...@@ -3336,22 +3343,40 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -3336,22 +3343,40 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
if (argspec.has_starargs) { if (argspec.has_starargs) {
rewrite_args = NULL; rewrite_args = NULL;
assert(argspec.num_args == 0); // doesn't need to be true, but assumed here Box* starargs;
Box* starargs = arg1; if (argspec.num_args == 0)
starargs = arg1;
else if (argspec.num_args == 1)
starargs = arg2;
else
abort();
assert(starargs->cls == tuple_cls); assert(starargs->cls == tuple_cls);
BoxedTuple* targs = static_cast<BoxedTuple*>(starargs); BoxedTuple* targs = static_cast<BoxedTuple*>(starargs);
int n = targs->elts.size(); int n = targs->elts.size();
if (n >= 1)
arg1 = targs->elts[0]; if (argspec.num_args == 0) {
if (n >= 2) if (n >= 1)
arg2 = targs->elts[1]; arg1 = targs->elts[0];
if (n >= 3) if (n >= 2)
arg3 = targs->elts[2]; arg2 = targs->elts[1];
if (n >= 4) if (n >= 3)
args = &targs->elts[3]; arg3 = targs->elts[2];
if (n >= 4)
argspec = ArgPassSpec(n); args = &targs->elts[3];
} else if (argspec.num_args == 1) {
if (n >= 1)
arg2 = targs->elts[0];
if (n >= 2)
arg3 = targs->elts[1];
if (n >= 3)
args = &targs->elts[2];
} else {
abort(); // unhandled
}
argspec = ArgPassSpec(n + argspec.num_args);
} }
Box* _cls = arg1; Box* _cls = arg1;
......
...@@ -81,6 +81,7 @@ extern "C" Box* importStar(Box* from_module, BoxedModule* to_module); ...@@ -81,6 +81,7 @@ extern "C" Box* importStar(Box* from_module, BoxedModule* to_module);
extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size); extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size);
extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg); extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg);
extern "C" void assertFail(BoxedModule* inModule, Box* msg); extern "C" void assertFail(BoxedModule* inModule, Box* msg);
extern "C" bool isInstance(Box* obj, BoxedClass* parent);
extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent); extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure); extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
extern "C" Box* getiter(Box* o); extern "C" Box* getiter(Box* o);
......
...@@ -637,6 +637,21 @@ Box* strReplace(Box* _self, Box* _old, Box* _new, Box** _args) { ...@@ -637,6 +637,21 @@ Box* strReplace(Box* _self, Box* _old, Box* _new, Box** _args) {
return rtn; return rtn;
} }
Box* strPartition(BoxedString* self, BoxedString* sep) {
RELEASE_ASSERT(self->cls == str_cls, "");
RELEASE_ASSERT(sep->cls == str_cls, "");
size_t found_idx = self->s.find(sep->s);
if (found_idx == std::string::npos)
return new BoxedTuple({ self, boxStrConstant(""), boxStrConstant("") });
return new BoxedTuple({ boxStrConstantSize(self->s.c_str(), found_idx),
boxStrConstantSize(self->s.c_str() + found_idx, sep->s.size()),
boxStrConstantSize(self->s.c_str() + found_idx + sep->s.size(),
self->s.size() - found_idx - sep->s.size()) });
}
Box* strSplit(BoxedString* self, BoxedString* sep, BoxedInt* _max_split) { Box* strSplit(BoxedString* self, BoxedString* sep, BoxedInt* _max_split) {
assert(self->cls == str_cls); assert(self->cls == str_cls);
if (_max_split->cls != int_cls) if (_max_split->cls != int_cls)
...@@ -1105,6 +1120,8 @@ void setupStr() { ...@@ -1105,6 +1120,8 @@ void setupStr() {
new BoxedFunction(boxRTFunction((void*)strFind, BOXED_INT, 3, 1, false, false), { boxInt(0) })); new BoxedFunction(boxRTFunction((void*)strFind, BOXED_INT, 3, 1, false, false), { boxInt(0) }));
str_cls->giveAttr("rfind", new BoxedFunction(boxRTFunction((void*)strRfind, BOXED_INT, 2))); str_cls->giveAttr("rfind", new BoxedFunction(boxRTFunction((void*)strRfind, BOXED_INT, 2)));
str_cls->giveAttr("partition", new BoxedFunction(boxRTFunction((void*)strPartition, UNKNOWN, 2)));
str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2))); str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2)));
str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2))); str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2)));
str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2))); str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "runtime/classobj.h" #include "runtime/classobj.h"
#include "runtime/ics.h" #include "runtime/ics.h"
#include "runtime/iterobject.h" #include "runtime/iterobject.h"
#include "runtime/list.h"
#include "runtime/long.h" #include "runtime/long.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/set.h" #include "runtime/set.h"
...@@ -726,6 +727,20 @@ public: ...@@ -726,6 +727,20 @@ public:
Box* r = self->b->getattr(key->s); Box* r = self->b->getattr(key->s);
return r ? True : False; return r ? True : False;
} }
static Box* items(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getAttrsPtr();
for (const auto& p : attrs->hcls->attr_offsets) {
BoxedTuple* t = new BoxedTuple({ boxString(p.first), attrs->attr_list->attrs[p.second] });
listAppend(rtn, t);
}
return rtn;
}
}; };
Box* makeAttrWrapper(Box* b) { Box* makeAttrWrapper(Box* b) {
...@@ -937,6 +952,7 @@ void setupRuntime() { ...@@ -937,6 +952,7 @@ void setupRuntime() {
attrwrapper_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::str, UNKNOWN, 1))); attrwrapper_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)AttrWrapper::str, UNKNOWN, 1)));
attrwrapper_cls->giveAttr("__contains__", attrwrapper_cls->giveAttr("__contains__",
new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains, UNKNOWN, 2))); new BoxedFunction(boxRTFunction((void*)AttrWrapper::contains, UNKNOWN, 2)));
attrwrapper_cls->giveAttr("items", new BoxedFunction(boxRTFunction((void*)AttrWrapper::items, LIST, 1)));
attrwrapper_cls->freeze(); attrwrapper_cls->freeze();
// sys is the first module that needs to be set up, due to modules // sys is the first module that needs to be set up, due to modules
......
...@@ -51,3 +51,7 @@ def G(): ...@@ -51,3 +51,7 @@ def G():
yield "A"; yield "B"; yield "C" yield "A"; yield "B"; yield "C"
print list(enumerate(G())) print list(enumerate(G()))
class C(object):
def __init__(self):
self.a = 1
print vars(C()).items()
# skip-if: True
# - wip
import collections
# skip-if: True
# - wip
from distutils.core import setup
...@@ -34,7 +34,7 @@ f = open('/dev/null') ...@@ -34,7 +34,7 @@ f = open('/dev/null')
print iter(f) is f print iter(f) is f
f.close() f.close()
with open('../README.md') as f: with open('README.md') as f:
lines = list(f) lines = list(f)
print lines[:5] print lines[:5]
print lines[-5:] print lines[-5:]
...@@ -44,3 +44,8 @@ try: ...@@ -44,3 +44,8 @@ try:
f = open('this-should-definitely-not-exist.txt') f = open('this-should-definitely-not-exist.txt')
except IOError as e: except IOError as e:
print str(e) print str(e)
f = open("/dev/null", "w")
f.write("hello world")
print f.flush()
f.close()
...@@ -102,3 +102,27 @@ print isinstance(D(), C) ...@@ -102,3 +102,27 @@ print isinstance(D(), C)
print str(f)[:26] print str(f)[:26]
print repr(f)[:26] print repr(f)[:26]
class OldStyleClass:
pass
print issubclass(OldStyleClass, object)
print isinstance(OldStyleClass(), OldStyleClass)
print issubclass(OldStyleClass, OldStyleClass)
class GetattrTest:
def __getattr__(self, attr):
print "getattr", attr
if attr.startswith("__"):
raise AttributeError(attr)
return 1
g = GetattrTest()
g.b = 2
print g.a
print g.b
print g.__class__
print g.__dict__.items()
print bool(g)
...@@ -13,4 +13,7 @@ print type(os.stat("/dev/null")) ...@@ -13,4 +13,7 @@ print type(os.stat("/dev/null"))
print os.path.expanduser("~") == os.environ["HOME"] print os.path.expanduser("~") == os.environ["HOME"]
print os.path.isfile("/dev/null")
print os.path.isfile("/should_not_exist!")
OSError(1, 2, 3) OSError(1, 2, 3)
...@@ -72,3 +72,7 @@ print "hello world".translate(translation_map, "") ...@@ -72,3 +72,7 @@ print "hello world".translate(translation_map, "")
for i in xrange(-10, 10): for i in xrange(-10, 10):
print i, "aaaaa".find("a", i) print i, "aaaaa".find("a", i)
print "hello world".partition("hi")
print "hello world".partition("hello")
print "hello world".partition("o")
# allow-warning: converting unicode literal to str
import sys
import os.path
print sys.version[:3]
print os.path.exists(sys.executable)
print sys.prefix, sys.exec_prefix
print sys.copyright[-200:]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment