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

Allow users to specify default arguments

parent 4c06ee4f
......@@ -60,6 +60,9 @@ public:
return true;
}
bool visit_functiondef(AST_FunctionDef* node) {
for (auto* d : node->args->defaults)
d->accept(this);
_doStore(node->name);
return true;
}
......
......@@ -65,7 +65,7 @@ struct GlobalState {
std::vector<llvm::JITEventListener*> jit_listeners;
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_flavor_type, *llvm_flavor_type_ptr;
llvm::Type* llvm_opaque_type;
......
......@@ -518,7 +518,8 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo&
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
// should be created anew every time the functiondef is encountered
......@@ -531,8 +532,24 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
closure_v = embedConstantPtr(nullptr, g.llvm_closure_type_ptr);
}
llvm::Value* boxed = emitter.getBuilder()->CreateCall2(g.funcs.boxCLFunction,
embedConstantPtr(f, g.llvm_clfunction_type_ptr), closure_v);
llvm::Value* scratch;
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)
converted->decvref(emitter);
......
......@@ -316,7 +316,8 @@ ConcreteCompilerVariable* makeInt(int64_t);
ConcreteCompilerVariable* makeFloat(double);
ConcreteCompilerVariable* makeBool(bool);
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();
CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts);
......
......@@ -65,6 +65,9 @@ public:
virtual GCBuilder* getGC() = 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::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
// args object can be NULL if this is a module scope
assert(!args->vararg.size());
assert(!args->kwarg.size());
assert(!args->defaults.size());
}
if (VERBOSITY("irgen") >= 1) {
......
......@@ -50,18 +50,15 @@ llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
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;
// If the entry block is currently empty, we have to be more careful:
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 {
new_scratch_space
= new llvm::AllocaInst(array_type, getConstantInt(1, g.i64), "scratch", entry_block.getFirstInsertionPt());
new_scratch_space = new llvm::AllocaInst(g.i8, getConstantInt(min_bytes, g.i64), "scratch",
entry_block.getFirstInsertionPt());
}
assert(new_scratch_space->isStaticAlloca());
if (scratch_space)
......@@ -119,6 +116,10 @@ public:
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(); }
llvm::CallSite createCall(ExcInfo exc_info, llvm::Value* callee, const std::vector<llvm::Value*>& args) override {
......@@ -1409,11 +1410,13 @@ private:
continue;
} else if (type == AST_TYPE::FunctionDef) {
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);
CLFunction* cl = this->_wrapFunction(fdef);
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);
func->decvref(emitter);
} else {
......@@ -1488,10 +1491,18 @@ private:
if (state == PARTIAL)
return;
assert(!node->args->defaults.size());
assert(!node->decorator_list.size());
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;
ScopeInfo* scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node);
if (scope_info->takesClosure()) {
......@@ -1499,7 +1510,11 @@ private:
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::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxCLFunction, embedConstantPtr(cl,
......
......@@ -121,6 +121,7 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_value_type_ptr = lookupFunction("getattr")->getReturnType();
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 = g.llvm_class_type_ptr->getSequentialElementType();
g.llvm_class_type = g.stdlib_module->getTypeByName("class.pyston::BoxedClass");
......
......@@ -845,8 +845,30 @@ public:
}
virtual bool visit_functiondef(AST_FunctionDef* node) {
assert(node->args->defaults.size() == 0);
push_back(node);
if (node->args->defaults.size() == 0 && node->decorator_list.size() == 0) {
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;
}
......
......@@ -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)
assert(closure->cls == closure_cls);
return new BoxedFunction(f, {}, closure);
return new BoxedFunction(f, defaults, closure);
}
extern "C" CLFunction* unboxCLFunction(Box* b) {
......
......@@ -88,7 +88,7 @@ Box* boxString(const std::string& s);
extern "C" BoxedString* boxStrConstant(const char* chars);
extern "C" void listAppendInternal(Box* self, Box* v);
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" Box* createUserClass(std::string* name, Box* base, BoxedModule* parent_module);
extern "C" double unboxFloat(Box* b);
......
......@@ -12,3 +12,34 @@ print range(5, 10)
print list(xrange(5))
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