Commit bc512baf authored by Marius Wachtler's avatar Marius Wachtler

Generators: remove single instance restriction and handle generators inside closures

parent 5a645879
...@@ -24,6 +24,8 @@ class YieldVisitor : public NoopASTVisitor { ...@@ -24,6 +24,8 @@ class YieldVisitor : public NoopASTVisitor {
public: public:
YieldVisitor() : containsYield(false) {} YieldVisitor() : containsYield(false) {}
virtual bool visit_functiondef(AST_FunctionDef*) { return true; }
virtual bool visit_yield(AST_Yield*) { virtual bool visit_yield(AST_Yield*) {
containsYield = true; containsYield = true;
return true; return true;
...@@ -34,7 +36,16 @@ public: ...@@ -34,7 +36,16 @@ public:
bool containsYield(AST* ast) { bool containsYield(AST* ast) {
YieldVisitor visitor; YieldVisitor visitor;
ast->accept(&visitor); if (ast->type == AST_TYPE::FunctionDef) {
AST_FunctionDef* funcDef = static_cast<AST_FunctionDef*>(ast);
for (auto& e : funcDef->body) {
e->accept(&visitor);
if (visitor.containsYield)
return true;
}
} else {
ast->accept(&visitor);
}
return visitor.containsYield; return visitor.containsYield;
} }
...@@ -387,9 +398,12 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { ...@@ -387,9 +398,12 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
switch (node->type) { switch (node->type) {
case AST_TYPE::ClassDef: case AST_TYPE::ClassDef:
case AST_TYPE::FunctionDef: case AST_TYPE::FunctionDef:
case AST_TYPE::Lambda: case AST_TYPE::Lambda: {
this->scopes[node] = new ScopeInfoBase(parent_info, usage); ScopeInfoBase* scopInfo = new ScopeInfoBase(parent_info, usage);
scopInfo->setTakesGenerator(containsYield(node));
this->scopes[node] = scopInfo;
break; break;
}
default: default:
RELEASE_ASSERT(0, "%d", usage->node->type); RELEASE_ASSERT(0, "%d", usage->node->type);
break; break;
......
...@@ -518,8 +518,8 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& ...@@ -518,8 +518,8 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo&
return new ConcreteCompilerVariable(BOOL, rtn_val, true); return new ConcreteCompilerVariable(BOOL, rtn_val, true);
} }
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, bool isGenerator,
CompilerVariable* generator, 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
...@@ -532,18 +532,6 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab ...@@ -532,18 +532,6 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
closure_v = embedConstantPtr(nullptr, g.llvm_closure_type_ptr); closure_v = embedConstantPtr(nullptr, g.llvm_closure_type_ptr);
} }
llvm::Value* generator_v;
ConcreteCompilerVariable* convertedGenerator = NULL;
if (generator && generator != (CompilerVariable*)1) {
convertedGenerator = generator->makeConverted(emitter, generator->getConcreteType());
generator_v = convertedGenerator->getValue();
// ugly hack to allow to pass a BoxedFunction* instead of a BoxedGenerator*
generator_v = emitter.getBuilder()->CreateBitCast(generator_v, g.llvm_generator_type_ptr);
} else {
generator_v = embedConstantPtr(nullptr, g.llvm_generator_type_ptr);
}
llvm::Value* scratch; llvm::Value* scratch;
if (defaults.size()) { if (defaults.size()) {
scratch = emitter.getScratch(defaults.size() * sizeof(Box*)); scratch = emitter.getScratch(defaults.size() * sizeof(Box*));
...@@ -559,15 +547,15 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab ...@@ -559,15 +547,15 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
scratch = embedConstantPtr(nullptr, g.llvm_value_type_ptr_ptr); scratch = embedConstantPtr(nullptr, g.llvm_value_type_ptr_ptr);
} }
llvm::Value* isGenerator_v = llvm::ConstantInt::get(g.i1, isGenerator, false);
llvm::Value* boxed = emitter.getBuilder()->CreateCall( llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxCLFunction, g.funcs.boxCLFunction,
std::vector<llvm::Value*>{ embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v, generator_v, scratch, std::vector<llvm::Value*>{ embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v, isGenerator_v, scratch,
getConstantInt(defaults.size(), g.i64) }); getConstantInt(defaults.size(), g.i64) });
if (convertedClosure) if (convertedClosure)
convertedClosure->decvref(emitter); convertedClosure->decvref(emitter);
if (convertedGenerator)
convertedGenerator->decvref(emitter);
return new ConcreteCompilerVariable(typeFromClass(function_cls), boxed, true); return new ConcreteCompilerVariable(typeFromClass(function_cls), boxed, true);
} }
......
...@@ -316,7 +316,7 @@ ConcreteCompilerVariable* makeInt(int64_t); ...@@ -316,7 +316,7 @@ ConcreteCompilerVariable* makeInt(int64_t);
ConcreteCompilerVariable* makeFloat(double); ConcreteCompilerVariable* makeFloat(double);
ConcreteCompilerVariable* makeBool(bool); ConcreteCompilerVariable* makeBool(bool);
CompilerVariable* makeStr(std::string*); CompilerVariable* makeStr(std::string*);
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, CompilerVariable* generator, CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, bool isGenerator,
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);
......
...@@ -1474,7 +1474,7 @@ private: ...@@ -1474,7 +1474,7 @@ private:
// one reason to do this is to pass the closure through if necessary, // one reason to do this is to pass the closure through if necessary,
// 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.
CompilerVariable* func = makeFunction(emitter, cl, created_closure, 0, {}); CompilerVariable* func = makeFunction(emitter, cl, created_closure, false, {});
CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(0), {}, NULL); CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(exc_info), ArgPassSpec(0), {}, NULL);
...@@ -1575,16 +1575,7 @@ private: ...@@ -1575,16 +1575,7 @@ private:
assert(created_closure); assert(created_closure);
} }
CompilerVariable* func = makeFunction(emitter, cl, created_closure, CompilerVariable* func = makeFunction(emitter, cl, created_closure, scope_info->takesGenerator(), defaults);
(ConcreteCompilerVariable*)scope_info->takesGenerator(), defaults);
if (scope_info->takesGenerator()) {
ConcreteCompilerVariable* converted = func->makeConverted(emitter, func->getBoxType());
CLFunction* clFunc = boxRTFunction((void*)createGenerator, UNKNOWN, args->args.size(),
args->defaults.size(), args->vararg.size(), args->kwarg.size());
func = makeFunction(emitter, clFunc, NULL, (CompilerVariable*)converted, defaults);
converted->decvref(emitter);
}
for (auto d : defaults) { for (auto d : defaults) {
d->decvref(emitter); d->decvref(emitter);
...@@ -1915,7 +1906,7 @@ private: ...@@ -1915,7 +1906,7 @@ private:
llvm::BasicBlock* target = entry_blocks[node->target]; llvm::BasicBlock* target = entry_blocks[node->target];
if (ENABLE_OSR && node->target->idx < myblock->idx && irstate->getEffortLevel() < EffortLevel::MAXIMAL if (ENABLE_OSR && node->target->idx < myblock->idx && irstate->getEffortLevel() < EffortLevel::MAXIMAL
&& !containsYield(irstate->getSourceInfo()->ast)) { && !irstate->getScopeInfo()->takesGenerator()) {
assert(node->target->predecessors.size() > 1); assert(node->target->predecessors.size() > 1);
doOSRExit(target, node); doOSRExit(target, node);
} else { } else {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <ucontext.h> #include <ucontext.h>
#include "codegen/compvars.h" #include "codegen/compvars.h"
#include "codegen/llvm_interpreter.h"
#include "core/ast.h" #include "core/ast.h"
#include "core/common.h" #include "core/common.h"
#include "core/stats.h" #include "core/stats.h"
...@@ -33,23 +34,24 @@ ...@@ -33,23 +34,24 @@
namespace pyston { namespace pyston {
static void generatorEntry(BoxedGenerator* self) { static void generatorEntry(BoxedGenerator* g) {
assert(self->cls == generator_cls); assert(g->cls == generator_cls);
assert(self->function->cls == function_cls); assert(g->function->cls == function_cls);
try { try {
// call body of the generator // call body of the generator
ArgPassSpec argPassSpec(self->function->f->num_args, 0, self->function->f->takes_varargs, BoxedFunction* func = g->function;
self->function->f->takes_kwargs);
runtimeCall(self->function, argPassSpec, self->arg1, self->arg2, self->arg3, self->args, 0); Box** args = g->args ? &g->args->elts[0] : nullptr;
callCLFunc(func->f, nullptr, func->f->num_args, func->closure, g, g->arg1, g->arg2, g->arg3, args);
} catch (Box* e) { } catch (Box* e) {
// unhandled exception: propagate the exception to the caller // unhandled exception: propagate the exception to the caller
self->exception = e; g->exception = e;
} }
// we returned from the body of the generator. next/send/throw will notify the caller // we returned from the body of the generator. next/send/throw will notify the caller
self->entryExited = true; g->entryExited = true;
swapcontext(&self->context, &self->returnContext); swapcontext(&g->context, &g->returnContext);
} }
Box* generatorIter(Box* s) { Box* generatorIter(Box* s) {
...@@ -126,13 +128,18 @@ extern "C" BoxedGenerator* createGenerator(BoxedFunction* function, Box* arg1, B ...@@ -126,13 +128,18 @@ extern "C" BoxedGenerator* createGenerator(BoxedFunction* function, Box* arg1, B
extern "C" BoxedGenerator::BoxedGenerator(BoxedFunction* function, Box* arg1, Box* arg2, Box* arg3, Box** args) extern "C" BoxedGenerator::BoxedGenerator(BoxedFunction* function, Box* arg1, Box* arg2, Box* arg3, Box** args)
: Box(&generator_flavor, generator_cls), function(function), arg1(arg1), arg2(arg2), arg3(arg3), args(args), : Box(&generator_flavor, generator_cls), function(function), arg1(arg1), arg2(arg2), arg3(arg3), args(nullptr),
entryExited(false), returnValue(nullptr), exception(nullptr) { entryExited(false), returnValue(nullptr), exception(nullptr) {
function->generator = this; // HACK: this only alows one active generator
giveAttr("__name__", boxString(function->f->source->getName())); giveAttr("__name__", boxString(function->f->source->getName()));
int numArgs = function->f->num_args;
if (numArgs > 3) {
numArgs -= 3;
this->args = new (numArgs) GCdArray();
memcpy(&this->args->elts[0], args, numArgs * sizeof(Box*));
}
getcontext(&context); getcontext(&context);
context.uc_link = 0; context.uc_link = 0;
context.uc_stack.ss_sp = stack; context.uc_stack.ss_sp = stack;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "runtime/capi.h" #include "runtime/capi.h"
#include "runtime/float.h" #include "runtime/float.h"
#include "runtime/gc_runtime.h" #include "runtime/gc_runtime.h"
#include "runtime/generator.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -1717,7 +1718,6 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1717,7 +1718,6 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
int num_passed_args = argspec.totalPassed(); int num_passed_args = argspec.totalPassed();
BoxedClosure* closure = func->closure; BoxedClosure* closure = func->closure;
BoxedGenerator* generator = (BoxedGenerator*)func->generator;
if (argspec.has_starargs || argspec.has_kwargs || f->takes_kwargs) if (argspec.has_starargs || argspec.has_kwargs || f->takes_kwargs)
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1754,25 +1754,25 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1754,25 +1754,25 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (rewrite_args) { if (rewrite_args) {
int closure_indicator = closure ? 1 : 0; int closure_indicator = closure ? 1 : 0;
int generator_indicator = generator ? 1 : 0; int generator_indicator = func->isGenerator ? 1 : 0;
int argOffset = closure_indicator + generator_indicator; int arg_offset = closure_indicator + generator_indicator;
if (num_passed_args >= 1) if (num_passed_args >= 1)
rewrite_args->arg1 = rewrite_args->arg1.move(0 + argOffset); rewrite_args->arg1 = rewrite_args->arg1.move(0 + arg_offset);
if (num_passed_args >= 2) if (num_passed_args >= 2)
rewrite_args->arg2 = rewrite_args->arg2.move(1 + argOffset); rewrite_args->arg2 = rewrite_args->arg2.move(1 + arg_offset);
if (num_passed_args >= 3) if (num_passed_args >= 3)
rewrite_args->arg3 = rewrite_args->arg3.move(2 + argOffset); rewrite_args->arg3 = rewrite_args->arg3.move(2 + arg_offset);
if (num_passed_args >= 4) if (num_passed_args >= 4)
rewrite_args->args = rewrite_args->args.move(3 + argOffset); rewrite_args->args = rewrite_args->args.move(3 + arg_offset);
// TODO this kind of embedded reference needs to be tracked by the GC somehow? // TODO this kind of embedded reference needs to be tracked by the GC somehow?
// Or maybe it's ok, since we've guarded on the function object? // Or maybe it's ok, since we've guarded on the function object?
if (closure) if (closure)
rewrite_args->rewriter->loadConst(0, (intptr_t)closure); rewrite_args->rewriter->loadConst(0, (intptr_t)closure);
if (generator) if (func->isGenerator)
rewrite_args->rewriter->loadConst(0, (intptr_t)generator); rewrite_args->rewriter->loadConst(0, (intptr_t)0 /*generator*/);
// We might have trouble if we have more output args than input args, // We might have trouble if we have more output args than input args,
// such as if we need more space to pass defaults. // such as if we need more space to pass defaults.
...@@ -1957,37 +1957,45 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -1957,37 +1957,45 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
getArg(i, oarg1, oarg2, oarg3, oargs) = default_obj; getArg(i, oarg1, oarg2, oarg3, oargs) = default_obj;
} }
// special handling for generators:
// the call to function containing a yield should just create a new generator object.
if (func->isGenerator) {
return createGenerator(func, oarg1, oarg2, oarg3, oargs);
}
return callCLFunc(f, rewrite_args, num_output_args, closure, NULL, oarg1, oarg2, oarg3, oargs);
}
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) {
CompiledFunction* chosen_cf = pickVersion(f, num_output_args, oarg1, oarg2, oarg3, oargs); CompiledFunction* chosen_cf = pickVersion(f, num_output_args, oarg1, oarg2, oarg3, oargs);
assert(chosen_cf->is_interpreted == (chosen_cf->code == NULL)); assert(chosen_cf->is_interpreted == (chosen_cf->code == NULL));
if (chosen_cf->is_interpreted) { if (chosen_cf->is_interpreted) {
return interpretFunction(chosen_cf->func, num_output_args, func->closure, generator, oarg1, oarg2, oarg3, return interpretFunction(chosen_cf->func, num_output_args, closure, generator, oarg1, oarg2, oarg3, oargs);
oargs); }
} else {
if (rewrite_args) {
rewrite_args->rewriter->addDependenceOn(chosen_cf->dependent_callsites);
RewriterVar var = rewrite_args->rewriter->call((void*)chosen_cf->call);
rewrite_args->out_rtn = var; if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->rewriter->addDependenceOn(chosen_cf->dependent_callsites);
}
RewriterVar var = rewrite_args->rewriter->call((void*)chosen_cf->call);
if (closure && generator) rewrite_args->out_rtn = var;
return chosen_cf->closure_generator_call(closure, generator, oarg1, oarg2, oarg3, oargs); rewrite_args->out_success = true;
else if (closure)
return chosen_cf->closure_call(closure, oarg1, oarg2, oarg3, oargs);
else if (generator)
return chosen_cf->generator_call(generator, oarg1, oarg2, oarg3, oargs);
else
return chosen_cf->call(oarg1, oarg2, oarg3, oargs);
} }
if (closure && generator)
return chosen_cf->closure_generator_call(closure, generator, oarg1, oarg2, oarg3, oargs);
else if (closure)
return chosen_cf->closure_call(closure, oarg1, oarg2, oarg3, oargs);
else if (generator)
return chosen_cf->generator_call(generator, oarg1, oarg2, oarg3, oargs);
else
return chosen_cf->call(oarg1, oarg2, oarg3, oargs);
} }
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<const std::string*>* keyword_names) { Box** args, const std::vector<const std::string*>* keyword_names) {
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
......
...@@ -103,5 +103,8 @@ extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__nor ...@@ -103,5 +103,8 @@ extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__nor
Box* typeCall(Box*, BoxedList*); Box* typeCall(Box*, BoxedList*);
Box* typeNew(Box*, Box*); Box* typeNew(Box*, Box*);
bool isUserDefined(BoxedClass* cls); bool isUserDefined(BoxedClass* cls);
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs);
} }
#endif #endif
...@@ -77,7 +77,7 @@ llvm::iterator_range<BoxIterator> Box::pyElements() { ...@@ -77,7 +77,7 @@ llvm::iterator_range<BoxIterator> Box::pyElements() {
} }
extern "C" BoxedFunction::BoxedFunction(CLFunction* f) extern "C" BoxedFunction::BoxedFunction(CLFunction* f)
: Box(&function_flavor, function_cls), f(f), closure(NULL), generator(nullptr), ndefaults(0), defaults(NULL) { : Box(&function_flavor, function_cls), f(f), closure(NULL), isGenerator(false), ndefaults(0), defaults(NULL) {
if (f->source) { if (f->source) {
assert(f->source->ast); assert(f->source->ast);
// this->giveAttr("__name__", boxString(&f->source->ast->name)); // this->giveAttr("__name__", boxString(&f->source->ast->name));
...@@ -91,8 +91,9 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f) ...@@ -91,8 +91,9 @@ extern "C" BoxedFunction::BoxedFunction(CLFunction* f)
} }
extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure, extern "C" BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure,
BoxedGenerator* generator) bool isGenerator)
: Box(&function_flavor, function_cls), f(f), closure(closure), generator(generator), ndefaults(0), defaults(NULL) { : Box(&function_flavor, function_cls), f(f), closure(closure), isGenerator(isGenerator), ndefaults(0),
defaults(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:
...@@ -148,12 +149,12 @@ std::string BoxedModule::name() { ...@@ -148,12 +149,12 @@ std::string BoxedModule::name() {
} }
} }
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, BoxedGenerator* generator, extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator,
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, generator); return new BoxedFunction(f, defaults, closure, isGenerator);
} }
extern "C" CLFunction* unboxCLFunction(Box* b) { extern "C" CLFunction* unboxCLFunction(Box* b) {
...@@ -279,12 +280,30 @@ extern "C" void generatorGCHandler(GCVisitor* v, void* p) { ...@@ -279,12 +280,30 @@ extern "C" void generatorGCHandler(GCVisitor* v, void* p) {
boxGCHandler(v, p); boxGCHandler(v, p);
BoxedGenerator* g = (BoxedGenerator*)p; BoxedGenerator* g = (BoxedGenerator*)p;
if (g->function)
if (g->function) {
v->visit(g->function); v->visit(g->function);
if (g->function->f) {
int num_args = g->function->f->num_args;
if (num_args >= 1)
v->visit(g->arg1);
if (num_args >= 2)
v->visit(g->arg2);
if (num_args >= 3)
v->visit(g->arg3);
if (num_args > 3)
v->visitPotentialRange(reinterpret_cast<void* const*>(&g->args->elts[0]),
reinterpret_cast<void* const*>(&g->args->elts[num_args - 3]));
}
}
if (g->returnValue) if (g->returnValue)
v->visit(g->returnValue); v->visit(g->returnValue);
if (g->exception) if (g->exception)
v->visit(g->exception); v->visit(g->exception);
v->visitPotentialRange((void**)&g->context, ((void**)&g->context) + sizeof(g->context) / sizeof(void*)); v->visitPotentialRange((void**)&g->context, ((void**)&g->context) + sizeof(g->context) / sizeof(void*));
v->visitPotentialRange((void**)&g->returnContext, v->visitPotentialRange((void**)&g->returnContext,
((void**)&g->returnContext) + sizeof(g->returnContext) / sizeof(void*)); ((void**)&g->returnContext) + sizeof(g->returnContext) / sizeof(void*));
......
...@@ -92,7 +92,7 @@ Box* boxString(const std::string& s); ...@@ -92,7 +92,7 @@ Box* boxString(const std::string& s);
extern "C" BoxedString* boxStrConstant(const char* chars); extern "C" BoxedString* boxStrConstant(const char* chars);
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, BoxedGenerator* generator, extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator,
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(std::string* name, Box* base, Box* attr_dict); extern "C" Box* createUserClass(std::string* name, Box* base, Box* attr_dict);
...@@ -280,14 +280,14 @@ public: ...@@ -280,14 +280,14 @@ public:
HCAttrs attrs; HCAttrs attrs;
CLFunction* f; CLFunction* f;
BoxedClosure* closure; BoxedClosure* closure;
BoxedGenerator* generator;
bool isGenerator;
int ndefaults; int ndefaults;
GCdArray* defaults; GCdArray* defaults;
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,
BoxedGenerator* generator = nullptr); bool isGenerator = false);
}; };
class BoxedModule : public Box { class BoxedModule : public Box {
...@@ -332,7 +332,8 @@ public: ...@@ -332,7 +332,8 @@ public:
HCAttrs attrs; HCAttrs attrs;
BoxedFunction* function; BoxedFunction* function;
Box* arg1, *arg2, *arg3, **args; Box* arg1, *arg2, *arg3;
GCdArray* args;
bool entryExited; bool entryExited;
Box* returnValue; Box* returnValue;
......
...@@ -13,9 +13,12 @@ def G2(): ...@@ -13,9 +13,12 @@ def G2():
yield 1 yield 1
yield 2 yield 2
yield 3 yield 3
g2 = G2() g2a = G2()
print list(g2) g2b = G2()
print list(g2) print g2b.next()
print list(g2a)
print list(g2b)
print list(g2a)
print list(G2()) print list(G2())
...@@ -67,3 +70,10 @@ def G6(a=[]): ...@@ -67,3 +70,10 @@ def G6(a=[]):
print list(G6()) print list(G6())
print list(G6()) print list(G6())
def G7(p):
a = p
b = 2
def G():
yield a+b
return G()
print list(G7(1))
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