Commit 0614be95 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Allow users to specify default arguments

parent 4c06ee4f
...@@ -60,6 +60,9 @@ public: ...@@ -60,6 +60,9 @@ public:
return true; return true;
} }
bool visit_functiondef(AST_FunctionDef* node) { bool visit_functiondef(AST_FunctionDef* node) {
for (auto* d : node->args->defaults)
d->accept(this);
_doStore(node->name); _doStore(node->name);
return true; return true;
} }
......
...@@ -65,7 +65,7 @@ struct GlobalState { ...@@ -65,7 +65,7 @@ struct GlobalState {
std::vector<llvm::JITEventListener*> jit_listeners; std::vector<llvm::JITEventListener*> jit_listeners;
FunctionAddressRegistry func_addr_registry; FunctionAddressRegistry func_addr_registry;
llvm::Type* llvm_value_type, *llvm_value_type_ptr; llvm::Type* llvm_value_type, *llvm_value_type_ptr, *llvm_value_type_ptr_ptr;
llvm::Type* llvm_class_type, *llvm_class_type_ptr; llvm::Type* llvm_class_type, *llvm_class_type_ptr;
llvm::Type* llvm_flavor_type, *llvm_flavor_type_ptr; llvm::Type* llvm_flavor_type, *llvm_flavor_type_ptr;
llvm::Type* llvm_opaque_type; llvm::Type* llvm_opaque_type;
......
...@@ -518,7 +518,8 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& ...@@ -518,7 +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,
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
...@@ -531,8 +532,24 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab ...@@ -531,8 +532,24 @@ 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* boxed = emitter.getBuilder()->CreateCall2(g.funcs.boxCLFunction, llvm::Value* scratch;
embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v); if (defaults.size()) {
scratch = emitter.getScratch(defaults.size() * sizeof(Box*));
scratch = emitter.getBuilder()->CreateBitCast(scratch, g.llvm_value_type_ptr_ptr);
int i = 0;
for (auto d : defaults) {
llvm::Value* v = d->getValue();
llvm::Value* p = emitter.getBuilder()->CreateConstGEP1_32(scratch, i);
emitter.getBuilder()->CreateStore(v, p);
i++;
}
} else {
scratch = embedConstantPtr(nullptr, g.llvm_value_type_ptr_ptr);
}
llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxCLFunction, std::vector<llvm::Value*>{ embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v,
scratch, getConstantInt(defaults.size(), g.i64) });
if (converted) if (converted)
converted->decvref(emitter); converted->decvref(emitter);
......
...@@ -316,7 +316,8 @@ ConcreteCompilerVariable* makeInt(int64_t); ...@@ -316,7 +316,8 @@ 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* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure,
const std::vector<ConcreteCompilerVariable*>& defaults);
ConcreteCompilerVariable* undefVariable(); ConcreteCompilerVariable* undefVariable();
CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts); CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts);
......
...@@ -65,6 +65,9 @@ public: ...@@ -65,6 +65,9 @@ public:
virtual GCBuilder* getGC() = 0; virtual GCBuilder* getGC() = 0;
virtual CompiledFunction* currentFunction() = 0; virtual CompiledFunction* currentFunction() = 0;
virtual llvm::Value* getScratch(int num_bytes) = 0;
virtual void releaseScratch(llvm::Value*) = 0;
virtual llvm::Function* getIntrinsic(llvm::Intrinsic::ID) = 0; virtual llvm::Function* getIntrinsic(llvm::Intrinsic::ID) = 0;
virtual llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) = 0; virtual llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) = 0;
......
...@@ -158,7 +158,6 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -158,7 +158,6 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
// args object can be NULL if this is a module scope // args object can be NULL if this is a module scope
assert(!args->vararg.size()); assert(!args->vararg.size());
assert(!args->kwarg.size()); assert(!args->kwarg.size());
assert(!args->defaults.size());
} }
if (VERBOSITY("irgen") >= 1) { if (VERBOSITY("irgen") >= 1) {
......
...@@ -50,18 +50,15 @@ llvm::Value* IRGenState::getScratchSpace(int min_bytes) { ...@@ -50,18 +50,15 @@ llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
return scratch_space; return scratch_space;
} }
// Not sure why, but LLVM wants to canonicalize an alloca into an array alloca (assuming
// the alloca is static); just to keep things straightforward, let's do that here:
llvm::Type* array_type = llvm::ArrayType::get(g.i8, min_bytes);
llvm::AllocaInst* new_scratch_space; llvm::AllocaInst* new_scratch_space;
// If the entry block is currently empty, we have to be more careful: // If the entry block is currently empty, we have to be more careful:
if (entry_block.begin() == entry_block.end()) { if (entry_block.begin() == entry_block.end()) {
new_scratch_space = new llvm::AllocaInst(array_type, getConstantInt(1, g.i64), "scratch", &entry_block); new_scratch_space = new llvm::AllocaInst(g.i8, getConstantInt(min_bytes, g.i64), "scratch", &entry_block);
} else { } else {
new_scratch_space new_scratch_space = new llvm::AllocaInst(g.i8, getConstantInt(min_bytes, g.i64), "scratch",
= new llvm::AllocaInst(array_type, getConstantInt(1, g.i64), "scratch", entry_block.getFirstInsertionPt()); entry_block.getFirstInsertionPt());
} }
assert(new_scratch_space->isStaticAlloca()); assert(new_scratch_space->isStaticAlloca());
if (scratch_space) if (scratch_space)
...@@ -119,6 +116,10 @@ public: ...@@ -119,6 +116,10 @@ public:
return llvm::Intrinsic::getDeclaration(g.cur_module, intrinsic_id); return llvm::Intrinsic::getDeclaration(g.cur_module, intrinsic_id);
} }
llvm::Value* getScratch(int num_bytes) override { return irstate->getScratchSpace(num_bytes); }
void releaseScratch(llvm::Value* scratch) override { assert(0); }
CompiledFunction* currentFunction() override { return irstate->getCurFunction(); } CompiledFunction* currentFunction() override { return irstate->getCurFunction(); }
llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) override { llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) override {
...@@ -1409,11 +1410,13 @@ private: ...@@ -1409,11 +1410,13 @@ private:
continue; continue;
} else if (type == AST_TYPE::FunctionDef) { } else if (type == AST_TYPE::FunctionDef) {
AST_FunctionDef* fdef = ast_cast<AST_FunctionDef>(node->body[i]); AST_FunctionDef* fdef = ast_cast<AST_FunctionDef>(node->body[i]);
assert(fdef->args->defaults.size() == 0);
assert(fdef->decorator_list.size() == 0);
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(fdef); ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(fdef);
CLFunction* cl = this->_wrapFunction(fdef); CLFunction* cl = this->_wrapFunction(fdef);
assert(!scope_info->takesClosure()); assert(!scope_info->takesClosure());
CompilerVariable* func = makeFunction(emitter, cl, NULL); CompilerVariable* func = makeFunction(emitter, cl, NULL, {});
cls->setattr(emitter, getEmptyOpInfo(exc_info), &fdef->name, func); cls->setattr(emitter, getEmptyOpInfo(exc_info), &fdef->name, func);
func->decvref(emitter); func->decvref(emitter);
} else { } else {
...@@ -1488,10 +1491,18 @@ private: ...@@ -1488,10 +1491,18 @@ private:
if (state == PARTIAL) if (state == PARTIAL)
return; return;
assert(!node->args->defaults.size()); assert(!node->decorator_list.size());
CLFunction* cl = this->_wrapFunction(node); CLFunction* cl = this->_wrapFunction(node);
std::vector<ConcreteCompilerVariable*> defaults;
for (auto d : node->args->defaults) {
CompilerVariable* e = evalExpr(d, exc_info);
ConcreteCompilerVariable* converted = e->makeConverted(emitter, e->getBoxType());
e->decvref(emitter);
defaults.push_back(converted);
}
CompilerVariable* created_closure = NULL; CompilerVariable* created_closure = NULL;
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node); ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
if (scope_info->takesClosure()) { if (scope_info->takesClosure()) {
...@@ -1499,7 +1510,11 @@ private: ...@@ -1499,7 +1510,11 @@ private:
assert(created_closure); assert(created_closure);
} }
CompilerVariable* func = makeFunction(emitter, cl, created_closure); CompilerVariable* func = makeFunction(emitter, cl, created_closure, defaults);
for (auto d : defaults) {
d->decvref(emitter);
}
// llvm::Type* boxCLFuncArgType = g.funcs.boxCLFunction->arg_begin()->getType(); // llvm::Type* boxCLFuncArgType = g.funcs.boxCLFunction->arg_begin()->getType();
// llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxCLFunction, embedConstantPtr(cl, // llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxCLFunction, embedConstantPtr(cl,
......
...@@ -121,6 +121,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -121,6 +121,7 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_value_type_ptr = lookupFunction("getattr")->getReturnType(); g.llvm_value_type_ptr = lookupFunction("getattr")->getReturnType();
g.llvm_value_type = g.llvm_value_type_ptr->getSequentialElementType(); g.llvm_value_type = g.llvm_value_type_ptr->getSequentialElementType();
g.llvm_value_type_ptr_ptr = g.llvm_value_type_ptr->getPointerTo();
// g.llvm_class_type_ptr = llvm::cast<llvm::StructType>(g.llvm_value_type)->getElementType(0); // g.llvm_class_type_ptr = llvm::cast<llvm::StructType>(g.llvm_value_type)->getElementType(0);
// g.llvm_class_type = g.llvm_class_type_ptr->getSequentialElementType(); // g.llvm_class_type = g.llvm_class_type_ptr->getSequentialElementType();
g.llvm_class_type = g.stdlib_module->getTypeByName("class.pyston::BoxedClass"); g.llvm_class_type = g.stdlib_module->getTypeByName("class.pyston::BoxedClass");
......
...@@ -845,8 +845,30 @@ public: ...@@ -845,8 +845,30 @@ public:
} }
virtual bool visit_functiondef(AST_FunctionDef* node) { virtual bool visit_functiondef(AST_FunctionDef* node) {
assert(node->args->defaults.size() == 0); if (node->args->defaults.size() == 0 && node->decorator_list.size() == 0) {
push_back(node); push_back(node);
} else {
AST_FunctionDef* remapped = new AST_FunctionDef();
remapped->name = node->name;
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->args = new AST_arguments();
remapped->body = node->body; // hmm shouldnt have to copy this
for (auto d : node->decorator_list) {
remapped->decorator_list.push_back(remapExpr(d));
}
remapped->args->args = node->args->args;
remapped->args->vararg = node->args->vararg;
remapped->args->kwarg = node->args->kwarg;
for (auto d : node->args->defaults) {
remapped->args->defaults.push_back(remapExpr(d));
}
push_back(remapped);
}
return true; return true;
} }
......
...@@ -135,11 +135,11 @@ std::string BoxedModule::name() { ...@@ -135,11 +135,11 @@ std::string BoxedModule::name() {
} }
} }
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure) { extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, std::initializer_list<Box*> defaults) {
if (closure) if (closure)
assert(closure->cls == closure_cls); assert(closure->cls == closure_cls);
return new BoxedFunction(f, {}, closure); return new BoxedFunction(f, defaults, closure);
} }
extern "C" CLFunction* unboxCLFunction(Box* b) { extern "C" CLFunction* unboxCLFunction(Box* b) {
......
...@@ -88,7 +88,7 @@ Box* boxString(const std::string& s); ...@@ -88,7 +88,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); extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, 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, BoxedModule* parent_module); extern "C" Box* createUserClass(std::string* name, Box* base, BoxedModule* parent_module);
extern "C" double unboxFloat(Box* b); extern "C" double unboxFloat(Box* b);
......
...@@ -12,3 +12,34 @@ print range(5, 10) ...@@ -12,3 +12,34 @@ print range(5, 10)
print list(xrange(5)) print list(xrange(5))
print list(xrange(5, 10)) print list(xrange(5, 10))
def f1(f):
def f(x=f):
return x
print f()
print f(2)
f1(1)
f1(3)
def f2():
x = 0
def f(x, y=1, z=x):
print x, y, z
f(1)
f(2, 3)
x = 2
f(4, 5, 6)
f2()
def f3():
def f(x, l=[]):
l.append(x)
print l
f(0)
f(1)
f(2)
f(4, [])
f(5, [])
f3()
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