Commit 039ea8f2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #518 from undingen/misc

Support for inspect.isgenerator, round(int), property.__doc__
parents 3dba07f5 bbb19558
...@@ -129,6 +129,7 @@ ...@@ -129,6 +129,7 @@
#define HAVE_UNISTD_H 1 #define HAVE_UNISTD_H 1
#define HAVE_UTIME_H 1 #define HAVE_UTIME_H 1
#define HAVE_WCHAR_H 1 #define HAVE_WCHAR_H 1
#define HAVE_WORKING_TZSET 1
#define HAVE_PUTENV 1 #define HAVE_PUTENV 1
// Added this for some Pyston modifications: // Added this for some Pyston modifications:
......
...@@ -44,6 +44,7 @@ from collections import namedtuple ...@@ -44,6 +44,7 @@ from collections import namedtuple
# Pyston change: we don't support all of these flags yet, so just enable the ones that we do: # Pyston change: we don't support all of these flags yet, so just enable the ones that we do:
CO_VARARGS = 0x4 CO_VARARGS = 0x4
CO_VARKEYWORDS = 0x8 CO_VARKEYWORDS = 0x8
CO_GENERATOR = 0x20
# These constants are from Include/code.h. # These constants are from Include/code.h.
# CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8 # CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8
# CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40 # CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40
......
...@@ -759,8 +759,6 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v ...@@ -759,8 +759,6 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
takes_closure = source_info->scoping->getScopeInfoForNode(node)->takesClosure(); takes_closure = source_info->scoping->getScopeInfoForNode(node)->takesClosure();
} }
bool is_generator = cl->source->is_generator;
BoxedClosure* closure = 0; BoxedClosure* closure = 0;
if (takes_closure) { if (takes_closure) {
if (scope_info->createsClosure()) { if (scope_info->createsClosure()) {
...@@ -775,7 +773,7 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v ...@@ -775,7 +773,7 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
Box* passed_globals = NULL; Box* passed_globals = NULL;
if (!getCF()->clfunc->source->scoping->areGlobalsFromModule()) if (!getCF()->clfunc->source->scoping->areGlobalsFromModule())
passed_globals = globals; passed_globals = globals;
return boxCLFunction(cl, closure, is_generator, passed_globals, u.il); return boxCLFunction(cl, closure, passed_globals, u.il);
} }
Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) { Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) {
...@@ -815,7 +813,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) { ...@@ -815,7 +813,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
Box* passed_globals = NULL; Box* passed_globals = NULL;
if (!getCF()->clfunc->source->scoping->areGlobalsFromModule()) if (!getCF()->clfunc->source->scoping->areGlobalsFromModule())
passed_globals = globals; passed_globals = globals;
Box* attrDict = runtimeCall(boxCLFunction(cl, closure, false, passed_globals, {}), ArgPassSpec(0), 0, 0, 0, 0, 0); Box* attrDict = runtimeCall(boxCLFunction(cl, closure, passed_globals, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
Box* classobj = createUserClass(&node->name.str(), basesTuple, attrDict); Box* classobj = createUserClass(&node->name.str(), basesTuple, attrDict);
......
...@@ -723,8 +723,8 @@ ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo& ...@@ -723,8 +723,8 @@ ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo&
return boolFromI1(emitter, rtn_val); return boolFromI1(emitter, rtn_val);
} }
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, bool isGenerator, CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, Box* globals,
Box* globals, const std::vector<ConcreteCompilerVariable*>& defaults) { const std::vector<ConcreteCompilerVariable*>& defaults) {
// Unlike the CLFunction*, which can be shared between recompilations, the Box* around it // Unlike the CLFunction*, which can be shared between recompilations, the Box* around it
// should be created anew every time the functiondef is encountered // should be created anew every time the functiondef is encountered
...@@ -752,17 +752,14 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab ...@@ -752,17 +752,14 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
scratch = getNullPtr(g.llvm_value_type_ptr_ptr); scratch = getNullPtr(g.llvm_value_type_ptr_ptr);
} }
llvm::Value* isGenerator_v = llvm::ConstantInt::get(g.i1, isGenerator, false);
assert(globals == NULL); assert(globals == NULL);
llvm::Value* globals_v = getNullPtr(g.llvm_value_type_ptr); llvm::Value* globals_v = getNullPtr(g.llvm_value_type_ptr);
// We know this function call can't throw, so it's safe to use emitter.getBuilder()->CreateCall() rather than // We know this function call can't throw, so it's safe to use emitter.getBuilder()->CreateCall() rather than
// emitter.createCall(). // emitter.createCall().
llvm::Value* boxed = emitter.getBuilder()->CreateCall( llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxCLFunction, g.funcs.boxCLFunction, std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_clfunction_type_ptr), closure_v,
std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_clfunction_type_ptr), closure_v, isGenerator_v, globals_v, scratch, getConstantInt(defaults.size(), g.i64) });
globals_v, scratch, getConstantInt(defaults.size(), g.i64) });
if (convertedClosure) if (convertedClosure)
convertedClosure->decvref(emitter); convertedClosure->decvref(emitter);
......
...@@ -398,8 +398,8 @@ ConcreteCompilerVariable* makeLong(IREmitter& emitter, std::string&); ...@@ -398,8 +398,8 @@ ConcreteCompilerVariable* makeLong(IREmitter& emitter, std::string&);
ConcreteCompilerVariable* makePureImaginary(IREmitter& emitter, double imag); ConcreteCompilerVariable* makePureImaginary(IREmitter& emitter, double imag);
CompilerVariable* makeStr(const std::string*); CompilerVariable* makeStr(const std::string*);
CompilerVariable* makeUnicode(IREmitter& emitter, const std::string*); CompilerVariable* makeUnicode(IREmitter& emitter, const std::string*);
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, bool isGenerator, CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, Box* globals,
Box* globals, const std::vector<ConcreteCompilerVariable*>& defaults); const std::vector<ConcreteCompilerVariable*>& defaults);
ConcreteCompilerVariable* undefVariable(); ConcreteCompilerVariable* undefVariable();
CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts); CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts);
......
...@@ -1269,7 +1269,7 @@ private: ...@@ -1269,7 +1269,7 @@ private:
// but since the classdef can't create its own closure, shouldn't need to explicitly // but since the classdef can't create its own closure, shouldn't need to explicitly
// create that scope to pass the closure through. // create that scope to pass the closure through.
assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule()); assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule());
CompilerVariable* func = makeFunction(emitter, cl, created_closure, false, NULL, {}); CompilerVariable* func = makeFunction(emitter, cl, created_closure, NULL, {});
CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(unw_info), ArgPassSpec(0), {}, NULL); CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(unw_info), ArgPassSpec(0), {}, NULL);
...@@ -1333,7 +1333,7 @@ private: ...@@ -1333,7 +1333,7 @@ private:
} }
assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule()); assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule());
CompilerVariable* func = makeFunction(emitter, cl, created_closure, is_generator, NULL, defaults); CompilerVariable* func = makeFunction(emitter, cl, created_closure, NULL, defaults);
for (auto d : defaults) { for (auto d : defaults) {
d->decvref(emitter); d->decvref(emitter);
......
...@@ -322,6 +322,12 @@ public: ...@@ -322,6 +322,12 @@ public:
osr_versions[compiled->entry_descriptor] = compiled; osr_versions[compiled->entry_descriptor] = compiled;
} }
} }
bool isGenerator() const {
if (source)
return source->is_generator;
return false;
}
}; };
CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
......
...@@ -1017,12 +1017,10 @@ Box* input(Box* prompt) { ...@@ -1017,12 +1017,10 @@ Box* input(Box* prompt) {
} }
Box* builtinRound(Box* _number, Box* _ndigits) { Box* builtinRound(Box* _number, Box* _ndigits) {
if (!isSubclass(_number->cls, float_cls)) double x = PyFloat_AsDouble(_number);
if (PyErr_Occurred())
raiseExcHelper(TypeError, "a float is required"); raiseExcHelper(TypeError, "a float is required");
BoxedFloat* number = (BoxedFloat*)_number;
double x = number->d;
/* interpret 2nd argument as a Py_ssize_t; clip on overflow */ /* interpret 2nd argument as a Py_ssize_t; clip on overflow */
Py_ssize_t ndigits = PyNumber_AsSsize_t(_ndigits, NULL); Py_ssize_t ndigits = PyNumber_AsSsize_t(_ndigits, NULL);
if (ndigits == -1 && PyErr_Occurred()) if (ndigits == -1 && PyErr_Occurred())
......
...@@ -62,6 +62,9 @@ public: ...@@ -62,6 +62,9 @@ public:
return boxInt(-1); return boxInt(-1);
} }
if (cl->source->ast->lineno == (uint32_t)-1)
return boxInt(-1);
return boxInt(cl->source->ast->lineno); return boxInt(cl->source->ast->lineno);
} }
...@@ -98,6 +101,8 @@ public: ...@@ -98,6 +101,8 @@ public:
flags |= CO_VARARGS; flags |= CO_VARARGS;
if (code->f->param_names.kwarg.size()) if (code->f->param_names.kwarg.size())
flags |= CO_VARKEYWORDS; flags |= CO_VARKEYWORDS;
if (code->f->isGenerator())
flags |= CO_GENERATOR;
return boxInt(flags); return boxInt(flags);
} }
}; };
......
...@@ -188,7 +188,7 @@ void setupDescr() { ...@@ -188,7 +188,7 @@ void setupDescr() {
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_set))); new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_set)));
property_cls->giveAttr("fdel", property_cls->giveAttr("fdel",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_del))); new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_del)));
property_cls->giveAttr("fdoc", property_cls->giveAttr("__doc__",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_doc))); new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_doc)));
property_cls->freeze(); property_cls->freeze();
......
...@@ -2112,7 +2112,8 @@ extern "C" bool nonzero(Box* obj) { ...@@ -2112,7 +2112,8 @@ extern "C" bool nonzero(Box* obj) {
ASSERT(isUserDefined(obj->cls) || obj->cls == classobj_cls || obj->cls == type_cls ASSERT(isUserDefined(obj->cls) || obj->cls == classobj_cls || obj->cls == type_cls
|| isSubclass(obj->cls, Exception) || obj->cls == file_cls || obj->cls == traceback_cls || isSubclass(obj->cls, Exception) || obj->cls == file_cls || obj->cls == traceback_cls
|| obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls || obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls
|| obj->cls == builtin_function_or_method_cls || obj->cls == method_cls, || obj->cls == builtin_function_or_method_cls || obj->cls == method_cls || obj->cls == frame_cls
|| obj->cls == capi_getset_cls || obj->cls == pyston_getset_cls,
"%s.__nonzero__", getTypeName(obj)); // TODO "%s.__nonzero__", getTypeName(obj)); // TODO
// TODO should rewrite these? // TODO should rewrite these?
...@@ -2845,7 +2846,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -2845,7 +2846,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
int num_output_args = f->numReceivedArgs(); int num_output_args = f->numReceivedArgs();
int num_passed_args = argspec.totalPassed(); int num_passed_args = argspec.totalPassed();
if (argspec.has_starargs || argspec.has_kwargs || func->isGenerator) { if (argspec.has_starargs || argspec.has_kwargs || f->isGenerator()) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED(""); REWRITE_ABORTED("");
} }
...@@ -2879,7 +2880,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -2879,7 +2880,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple // Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple
// django-admin test this covers something like 93% of all calls to callFunc. // django-admin test this covers something like 93% of all calls to callFunc.
if (!func->isGenerator) { if (!f->isGenerator()) {
if (argspec.num_keywords == 0 && !argspec.has_starargs && !argspec.has_kwargs && argspec.num_args == f->num_args if (argspec.num_keywords == 0 && !argspec.has_starargs && !argspec.has_kwargs && argspec.num_args == f->num_args
&& !f->takes_varargs && !f->takes_kwargs) { && !f->takes_varargs && !f->takes_kwargs) {
return callCLFunc(f, rewrite_args, argspec.num_args, closure, NULL, func->globals, arg1, arg2, arg3, args); return callCLFunc(f, rewrite_args, argspec.num_args, closure, NULL, func->globals, arg1, arg2, arg3, args);
...@@ -3166,7 +3167,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -3166,7 +3167,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// special handling for generators: // special handling for generators:
// the call to function containing a yield should just create a new generator object. // the call to function containing a yield should just create a new generator object.
Box* res; Box* res;
if (func->isGenerator) { if (f->isGenerator()) {
res = createGenerator(func, oarg1, oarg2, oarg3, oargs); res = createGenerator(func, oarg1, oarg2, oarg3, oargs);
} else { } else {
res = callCLFunc(f, rewrite_args, num_output_args, closure, NULL, func->globals, oarg1, oarg2, oarg3, oargs); res = callCLFunc(f, rewrite_args, num_output_args, closure, NULL, func->globals, oarg1, oarg2, oarg3, oargs);
......
...@@ -287,8 +287,7 @@ Box* Box::nextIC() { ...@@ -287,8 +287,7 @@ Box* Box::nextIC() {
std::string builtinStr("__builtin__"); std::string builtinStr("__builtin__");
extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f) extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f)
: in_weakreflist(NULL), f(f), closure(NULL), isGenerator(false), ndefaults(0), defaults(NULL), modname(NULL), : in_weakreflist(NULL), f(f), closure(NULL), ndefaults(0), defaults(NULL), modname(NULL), name(NULL), doc(NULL) {
name(NULL), doc(NULL) {
if (f->source) { if (f->source) {
this->modname = PyDict_GetItemString(getGlobalsDict(), "__name__"); this->modname = PyDict_GetItemString(getGlobalsDict(), "__name__");
this->doc = f->source->getDocString(); this->doc = f->source->getDocString();
...@@ -301,9 +300,8 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f) ...@@ -301,9 +300,8 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f)
} }
extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_list<Box*> defaults, extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_list<Box*> defaults,
BoxedClosure* closure, bool isGenerator) BoxedClosure* closure)
: in_weakreflist(NULL), f(f), closure(closure), isGenerator(isGenerator), ndefaults(0), defaults(NULL), : in_weakreflist(NULL), f(f), closure(closure), ndefaults(0), defaults(NULL), modname(NULL), name(NULL), doc(NULL) {
modname(NULL), name(NULL), doc(NULL) {
if (defaults.size()) { if (defaults.size()) {
// make sure to initialize defaults first, since the GC behavior is triggered by ndefaults, // make sure to initialize defaults first, since the GC behavior is triggered by ndefaults,
// and a GC can happen within this constructor: // and a GC can happen within this constructor:
...@@ -326,9 +324,8 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_ ...@@ -326,9 +324,8 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_
BoxedFunction::BoxedFunction(CLFunction* f) : BoxedFunction(f, {}) { BoxedFunction::BoxedFunction(CLFunction* f) : BoxedFunction(f, {}) {
} }
BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure, BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure, Box* globals)
bool isGenerator, Box* globals) : BoxedFunctionBase(f, defaults, closure) {
: BoxedFunctionBase(f, defaults, closure, isGenerator) {
assert((!globals) == (!f->source || f->source->scoping->areGlobalsFromModule())); assert((!globals) == (!f->source || f->source->scoping->areGlobalsFromModule()));
this->globals = globals; this->globals = globals;
...@@ -349,8 +346,8 @@ BoxedBuiltinFunctionOrMethod::BoxedBuiltinFunctionOrMethod(CLFunction* f, const ...@@ -349,8 +346,8 @@ BoxedBuiltinFunctionOrMethod::BoxedBuiltinFunctionOrMethod(CLFunction* f, const
BoxedBuiltinFunctionOrMethod::BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name, BoxedBuiltinFunctionOrMethod::BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name,
std::initializer_list<Box*> defaults, BoxedClosure* closure, std::initializer_list<Box*> defaults, BoxedClosure* closure,
bool isGenerator, const char* doc) const char* doc)
: BoxedFunctionBase(f, defaults, closure, isGenerator) { : BoxedFunctionBase(f, defaults, closure) {
assert(name); assert(name);
this->name = static_cast<BoxedString*>(boxString(name)); this->name = static_cast<BoxedString*>(boxString(name));
...@@ -429,12 +426,12 @@ extern "C" void moduleGCHandler(GCVisitor* v, Box* b) { ...@@ -429,12 +426,12 @@ extern "C" void moduleGCHandler(GCVisitor* v, Box* b) {
// This mustn't throw; our IR generator generates calls to it without "invoke" even when there are exception handlers / // This mustn't throw; our IR generator generates calls to it without "invoke" even when there are exception handlers /
// finally-blocks in scope. // finally-blocks in scope.
// TODO: should we use C++11 `noexcept' here? // TODO: should we use C++11 `noexcept' here?
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator, Box* globals, extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, Box* globals,
std::initializer_list<Box*> defaults) { std::initializer_list<Box*> defaults) {
if (closure) if (closure)
assert(closure->cls == closure_cls); assert(closure->cls == closure_cls);
return new BoxedFunction(f, defaults, closure, isGenerator, globals); return new BoxedFunction(f, defaults, closure, globals);
} }
extern "C" CLFunction* unboxCLFunction(Box* b) { extern "C" CLFunction* unboxCLFunction(Box* b) {
......
...@@ -129,8 +129,7 @@ char* getWriteableStringContents(BoxedString* s); ...@@ -129,8 +129,7 @@ char* getWriteableStringContents(BoxedString* s);
extern "C" void listAppendInternal(Box* self, Box* v); extern "C" void listAppendInternal(Box* self, Box* v);
extern "C" void listAppendArrayInternal(Box* self, Box** v, int nelts); extern "C" void listAppendArrayInternal(Box* self, Box** v, int nelts);
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator, Box* globals, extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, Box* globals, std::initializer_list<Box*> defaults);
std::initializer_list<Box*> defaults);
extern "C" CLFunction* unboxCLFunction(Box* b); extern "C" CLFunction* unboxCLFunction(Box* b);
extern "C" Box* createUserClass(const std::string* name, Box* base, Box* attr_dict); extern "C" Box* createUserClass(const std::string* name, Box* base, Box* attr_dict);
extern "C" double unboxFloat(Box* b); extern "C" double unboxFloat(Box* b);
...@@ -663,7 +662,6 @@ public: ...@@ -663,7 +662,6 @@ public:
BoxedClosure* closure; BoxedClosure* closure;
Box* globals; Box* globals;
bool isGenerator;
int ndefaults; int ndefaults;
GCdArray* defaults; GCdArray* defaults;
...@@ -675,8 +673,7 @@ public: ...@@ -675,8 +673,7 @@ public:
Box* doc; // __doc__ Box* doc; // __doc__
BoxedFunctionBase(CLFunction* f); BoxedFunctionBase(CLFunction* f);
BoxedFunctionBase(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure = NULL, BoxedFunctionBase(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure = NULL);
bool isGenerator = false);
}; };
class BoxedFunction : public BoxedFunctionBase { class BoxedFunction : public BoxedFunctionBase {
...@@ -685,7 +682,7 @@ public: ...@@ -685,7 +682,7 @@ public:
BoxedFunction(CLFunction* f); BoxedFunction(CLFunction* f);
BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure = NULL, BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure = NULL,
bool isGenerator = false, Box* globals = NULL); Box* globals = NULL);
DEFAULT_CLASS(function_cls); DEFAULT_CLASS(function_cls);
}; };
...@@ -694,7 +691,7 @@ class BoxedBuiltinFunctionOrMethod : public BoxedFunctionBase { ...@@ -694,7 +691,7 @@ class BoxedBuiltinFunctionOrMethod : public BoxedFunctionBase {
public: public:
BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name, const char* doc = NULL); BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name, const char* doc = NULL);
BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name, std::initializer_list<Box*> defaults, BoxedBuiltinFunctionOrMethod(CLFunction* f, const char* name, std::initializer_list<Box*> defaults,
BoxedClosure* closure = NULL, bool isGenerator = false, const char* doc = NULL); BoxedClosure* closure = NULL, const char* doc = NULL);
DEFAULT_CLASS(builtin_function_or_method_cls); DEFAULT_CLASS(builtin_function_or_method_cls);
}; };
......
...@@ -108,7 +108,7 @@ print callable(lambda: 1) ...@@ -108,7 +108,7 @@ print callable(lambda: 1)
print range(5L, 7L) print range(5L, 7L)
for n in [0, 1, 2, 3, 4, 5]: for n in [0, 1, 2, 3, 4, 5]:
print round(-1.1, n), round(-1.9, n), round(0.5, n), round(-0.5, n), round(-0.123456789, n) print round(-1.1, n), round(-1.9, n), round(0.5, n), round(-0.5, n), round(-0.123456789, n), round(1, n)
print list(iter(xrange(100).__iter__().next, 20)) print list(iter(xrange(100).__iter__().next, 20))
......
...@@ -8,3 +8,9 @@ def f2(): ...@@ -8,3 +8,9 @@ def f2():
print inspect.getargspec(f1) print inspect.getargspec(f1)
print inspect.getargspec(f2) print inspect.getargspec(f2)
def G():
yield 1
print inspect.isgenerator(f1)
print inspect.isgenerator(G)
print inspect.isgenerator(G())
...@@ -8,7 +8,7 @@ class C(object): ...@@ -8,7 +8,7 @@ class C(object):
def fset(self, val): def fset(self, val):
print 'in fset, val =', val print 'in fset, val =', val
x = property(fget, fset) x = property(fget, fset, None, "Doc String")
c = C() c = C()
print c.x print c.x
...@@ -16,6 +16,7 @@ print C.x.__get__(c, C) ...@@ -16,6 +16,7 @@ print C.x.__get__(c, C)
print type(C.x.__get__(None, C)) print type(C.x.__get__(None, C))
c.x = 7 c.x = 7
print c.x print c.x
print C.x.__doc__
class C2(object): class C2(object):
@property @property
......
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