Commit aa2ed8d4 authored by Michael Arntzenius's avatar Michael Arntzenius

add MakeClass, MakeFunction AST psuedo-exprs

This lets class & function definitions become ordinary assignments in
the CFG, which simplifies our invariants and fixes problems with the
interaction between definedness analysis and block-terminating
"invoke"s.
parent 7b9c4682
...@@ -511,7 +511,9 @@ private: ...@@ -511,7 +511,9 @@ private:
} }
} }
void visit_classdef(AST_ClassDef* node) override { void* visit_makeclass(AST_MakeClass* mkclass) override {
AST_ClassDef* node = mkclass->class_def;
for (auto d : node->decorator_list) { for (auto d : node->decorator_list) {
getType(d); getType(d);
} }
...@@ -521,9 +523,8 @@ private: ...@@ -521,9 +523,8 @@ private:
} }
// TODO should we speculate that classdefs will generally return a class? // TODO should we speculate that classdefs will generally return a class?
// CompilerType* t = typeFromClass(type_cls); // return typeFromClass(type_cls);
CompilerType* t = UNKNOWN; return UNKNOWN;
_doSet(scope_info->mangleName(node->name), t);
} }
void visit_delete(AST_Delete* node) override { void visit_delete(AST_Delete* node) override {
...@@ -551,7 +552,9 @@ private: ...@@ -551,7 +552,9 @@ private:
} }
} }
void visit_functiondef(AST_FunctionDef* node) override { void* visit_makefunction(AST_MakeFunction* mkfn) override {
AST_FunctionDef* node = mkfn->function_def;
for (auto d : node->decorator_list) { for (auto d : node->decorator_list) {
getType(d); getType(d);
} }
...@@ -563,7 +566,7 @@ private: ...@@ -563,7 +566,7 @@ private:
CompilerType* t = UNKNOWN; CompilerType* t = UNKNOWN;
if (node->decorator_list.empty()) if (node->decorator_list.empty())
t = typeFromClass(function_cls); t = typeFromClass(function_cls);
_doSet(scope_info->mangleName(node->name), t); return t;
} }
void visit_global(AST_Global* node) override {} void visit_global(AST_Global* node) override {}
......
...@@ -88,10 +88,8 @@ private: ...@@ -88,10 +88,8 @@ private:
Value visit_assign(AST_Assign* node); Value visit_assign(AST_Assign* node);
Value visit_binop(AST_BinOp* node); Value visit_binop(AST_BinOp* node);
Value visit_call(AST_Call* node); Value visit_call(AST_Call* node);
Value visit_classDef(AST_ClassDef* node);
Value visit_compare(AST_Compare* node); Value visit_compare(AST_Compare* node);
Value visit_delete(AST_Delete* node); Value visit_delete(AST_Delete* node);
Value visit_functionDef(AST_FunctionDef* node);
Value visit_global(AST_Global* node); Value visit_global(AST_Global* node);
Value visit_module(AST_Module* node); Value visit_module(AST_Module* node);
Value visit_print(AST_Print* node); Value visit_print(AST_Print* node);
...@@ -117,6 +115,8 @@ private: ...@@ -117,6 +115,8 @@ private:
Value visit_tuple(AST_Tuple* node); Value visit_tuple(AST_Tuple* node);
Value visit_yield(AST_Yield* node); Value visit_yield(AST_Yield* node);
Value visit_makeClass(AST_MakeClass* node);
Value visit_makeFunction(AST_MakeFunction* node);
// pseudo // pseudo
Value visit_augBinOp(AST_AugBinOp* node); Value visit_augBinOp(AST_AugBinOp* node);
...@@ -606,14 +606,10 @@ Value ASTInterpreter::visit_stmt(AST_stmt* node) { ...@@ -606,14 +606,10 @@ Value ASTInterpreter::visit_stmt(AST_stmt* node) {
return visit_assert((AST_Assert*)node); return visit_assert((AST_Assert*)node);
case AST_TYPE::Assign: case AST_TYPE::Assign:
return visit_assign((AST_Assign*)node); return visit_assign((AST_Assign*)node);
case AST_TYPE::ClassDef:
return visit_classDef((AST_ClassDef*)node);
case AST_TYPE::Delete: case AST_TYPE::Delete:
return visit_delete((AST_Delete*)node); return visit_delete((AST_Delete*)node);
case AST_TYPE::Expr: case AST_TYPE::Expr:
return visit_expr((AST_Expr*)node); return visit_expr((AST_Expr*)node);
case AST_TYPE::FunctionDef:
return visit_functionDef((AST_FunctionDef*)node);
case AST_TYPE::Pass: case AST_TYPE::Pass:
return Value(); // nothing todo return Value(); // nothing todo
case AST_TYPE::Print: case AST_TYPE::Print:
...@@ -691,7 +687,8 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v ...@@ -691,7 +687,8 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
return boxCLFunction(cl, closure, is_generator, u.il); return boxCLFunction(cl, closure, is_generator, u.il);
} }
Value ASTInterpreter::visit_functionDef(AST_FunctionDef* node) { Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) {
AST_FunctionDef* node = mkfn->function_def;
AST_arguments* args = node->args; AST_arguments* args = node->args;
std::vector<Box*, StlCompatAllocator<Box*>> decorators; std::vector<Box*, StlCompatAllocator<Box*>> decorators;
...@@ -703,11 +700,11 @@ Value ASTInterpreter::visit_functionDef(AST_FunctionDef* node) { ...@@ -703,11 +700,11 @@ Value ASTInterpreter::visit_functionDef(AST_FunctionDef* node) {
for (int i = decorators.size() - 1; i >= 0; i--) for (int i = decorators.size() - 1; i >= 0; i--)
func = runtimeCall(decorators[i], ArgPassSpec(1), func, 0, 0, 0, 0); func = runtimeCall(decorators[i], ArgPassSpec(1), func, 0, 0, 0, 0);
doStore(source_info->mangleName(node->name), func); return Value(func);
return Value();
} }
Value ASTInterpreter::visit_classDef(AST_ClassDef* node) { Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
AST_ClassDef* node = mkclass->class_def;
ScopeInfo* scope_info = source_info->scoping->getScopeInfoForNode(node); ScopeInfo* scope_info = source_info->scoping->getScopeInfoForNode(node);
assert(scope_info); assert(scope_info);
...@@ -730,8 +727,7 @@ Value ASTInterpreter::visit_classDef(AST_ClassDef* node) { ...@@ -730,8 +727,7 @@ Value ASTInterpreter::visit_classDef(AST_ClassDef* node) {
for (int i = decorators.size() - 1; i >= 0; i--) for (int i = decorators.size() - 1; i >= 0; i--)
classobj = runtimeCall(decorators[i], ArgPassSpec(1), classobj, 0, 0, 0, 0); classobj = runtimeCall(decorators[i], ArgPassSpec(1), classobj, 0, 0, 0, 0);
doStore(source_info->mangleName(node->name), classobj); return Value(classobj);
return Value();
} }
Value ASTInterpreter::visit_raise(AST_Raise* node) { Value ASTInterpreter::visit_raise(AST_Raise* node) {
...@@ -897,6 +893,10 @@ Value ASTInterpreter::visit_expr(AST_expr* node) { ...@@ -897,6 +893,10 @@ Value ASTInterpreter::visit_expr(AST_expr* node) {
return visit_clsAttribute((AST_ClsAttribute*)node); return visit_clsAttribute((AST_ClsAttribute*)node);
case AST_TYPE::LangPrimitive: case AST_TYPE::LangPrimitive:
return visit_langPrimitive((AST_LangPrimitive*)node); return visit_langPrimitive((AST_LangPrimitive*)node);
case AST_TYPE::MakeClass:
return visit_makeClass((AST_MakeClass*)node);
case AST_TYPE::MakeFunction:
return visit_makeFunction((AST_MakeFunction*)node);
default: default:
RELEASE_ASSERT(0, ""); RELEASE_ASSERT(0, "");
}; };
......
...@@ -1091,6 +1091,133 @@ private: ...@@ -1091,6 +1091,133 @@ private:
return new ConcreteCompilerVariable(UNKNOWN, rtn, true); return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
} }
CompilerVariable* evalMakeClass(AST_MakeClass* mkclass, UnwindInfo unw_info) {
assert(mkclass->type == AST_TYPE::MakeClass && mkclass->class_def->type == AST_TYPE::ClassDef);
AST_ClassDef* node = mkclass->class_def;
ScopeInfo* scope_info = irstate->getScopeInfoForNode(node);
assert(scope_info);
std::vector<CompilerVariable*> bases;
for (auto b : node->bases) {
CompilerVariable* base = evalExpr(b, unw_info);
bases.push_back(base);
}
CompilerVariable* _bases_tuple = makeTuple(bases);
for (auto b : bases) {
b->decvref(emitter);
}
ConcreteCompilerVariable* bases_tuple = _bases_tuple->makeConverted(emitter, _bases_tuple->getBoxType());
_bases_tuple->decvref(emitter);
std::vector<CompilerVariable*> decorators;
for (auto d : node->decorator_list) {
decorators.push_back(evalExpr(d, unw_info));
}
CLFunction* cl = wrapFunction(node, nullptr, node->body, irstate->getSourceInfo());
// TODO duplication with _createFunction:
CompilerVariable* created_closure = NULL;
if (scope_info->takesClosure()) {
created_closure = symbol_table[internString(CREATED_CLOSURE_NAME)];
assert(created_closure);
}
// TODO kind of silly to create the function just to usually-delete it afterwards;
// 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
// create that scope to pass the closure through.
CompilerVariable* func = makeFunction(emitter, cl, created_closure, false, {});
CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(unw_info), ArgPassSpec(0), {}, NULL);
func->decvref(emitter);
ConcreteCompilerVariable* converted_attr_dict = attr_dict->makeConverted(emitter, attr_dict->getBoxType());
attr_dict->decvref(emitter);
llvm::Value* classobj = emitter.createCall3(unw_info, g.funcs.createUserClass,
embedConstantPtr(&node->name.str(), g.llvm_str_type_ptr),
bases_tuple->getValue(), converted_attr_dict->getValue());
// Note: createuserClass is free to manufacture non-class objects
CompilerVariable* cls = new ConcreteCompilerVariable(UNKNOWN, classobj, true);
for (int i = decorators.size() - 1; i >= 0; i--) {
cls = decorators[i]->call(emitter, getOpInfoForNode(node, unw_info), ArgPassSpec(1), { cls }, NULL);
decorators[i]->decvref(emitter);
}
// do we need to decvref this?
return cls;
}
CompilerVariable* _createFunction(AST* node, UnwindInfo unw_info, AST_arguments* args,
const std::vector<AST_stmt*>& body) {
CLFunction* cl = wrapFunction(node, args, body, irstate->getSourceInfo());
std::vector<ConcreteCompilerVariable*> defaults;
for (auto d : args->defaults) {
CompilerVariable* e = evalExpr(d, unw_info);
ConcreteCompilerVariable* converted = e->makeConverted(emitter, e->getBoxType());
e->decvref(emitter);
defaults.push_back(converted);
}
CompilerVariable* created_closure = NULL;
bool takes_closure;
// Optimization: when compiling a module, it's nice to not have to run analyses into the
// entire module's source code.
// If we call getScopeInfoForNode, that will trigger an analysis of that function tree,
// but we're only using it here to figure out if that function takes a closure.
// Top level functions never take a closure, so we can skip the analysis.
if (irstate->getSourceInfo()->ast->type == AST_TYPE::Module)
takes_closure = false;
else {
takes_closure = irstate->getScopeInfoForNode(node)->takesClosure();
}
bool is_generator = cl->source->is_generator;
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
created_closure = symbol_table[internString(CREATED_CLOSURE_NAME)];
} else {
assert(irstate->getScopeInfo()->passesThroughClosure());
created_closure = symbol_table[internString(PASSED_CLOSURE_NAME)];
}
assert(created_closure);
}
CompilerVariable* func = makeFunction(emitter, cl, created_closure, is_generator, defaults);
for (auto d : defaults) {
d->decvref(emitter);
}
return func;
}
CompilerVariable* evalMakeFunction(AST_MakeFunction* mkfn, UnwindInfo unw_info) {
AST_FunctionDef* node = mkfn->function_def;
std::vector<CompilerVariable*> decorators;
for (auto d : node->decorator_list) {
decorators.push_back(evalExpr(d, unw_info));
}
CompilerVariable* func = _createFunction(node, unw_info, node->args, node->body);
for (int i = decorators.size() - 1; i >= 0; i--) {
func = decorators[i]->call(emitter, getOpInfoForNode(node, unw_info), ArgPassSpec(1), { func }, NULL);
decorators[i]->decvref(emitter);
}
return func;
}
ConcreteCompilerVariable* unboxVar(ConcreteCompilerType* t, llvm::Value* v, bool grabbed) { ConcreteCompilerVariable* unboxVar(ConcreteCompilerType* t, llvm::Value* v, bool grabbed) {
if (t == BOXED_INT) { if (t == BOXED_INT) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v); llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v);
...@@ -1176,12 +1303,19 @@ private: ...@@ -1176,12 +1303,19 @@ private:
rtn = evalYield(ast_cast<AST_Yield>(node), unw_info); rtn = evalYield(ast_cast<AST_Yield>(node), unw_info);
break; break;
// pseudo-nodes
case AST_TYPE::ClsAttribute: case AST_TYPE::ClsAttribute:
rtn = evalClsAttribute(ast_cast<AST_ClsAttribute>(node), unw_info); rtn = evalClsAttribute(ast_cast<AST_ClsAttribute>(node), unw_info);
break; break;
case AST_TYPE::LangPrimitive: case AST_TYPE::LangPrimitive:
rtn = evalLangPrimitive(ast_cast<AST_LangPrimitive>(node), unw_info); rtn = evalLangPrimitive(ast_cast<AST_LangPrimitive>(node), unw_info);
break; break;
case AST_TYPE::MakeClass:
rtn = evalMakeClass(ast_cast<AST_MakeClass>(node), unw_info);
break;
case AST_TYPE::MakeFunction:
rtn = evalMakeFunction(ast_cast<AST_MakeFunction>(node), unw_info);
break;
default: default:
printf("Unhandled expr type: %d (irgenerator.cpp:" STRINGIFY(__LINE__) ")\n", node->type); printf("Unhandled expr type: %d (irgenerator.cpp:" STRINGIFY(__LINE__) ")\n", node->type);
exit(1); exit(1);
...@@ -1394,69 +1528,6 @@ private: ...@@ -1394,69 +1528,6 @@ private:
val->decvref(emitter); val->decvref(emitter);
} }
void doClassDef(AST_ClassDef* node, UnwindInfo unw_info) {
assert(node->type == AST_TYPE::ClassDef);
ScopeInfo* scope_info = irstate->getScopeInfoForNode(node);
assert(scope_info);
std::vector<CompilerVariable*> bases;
for (auto b : node->bases) {
CompilerVariable* base = evalExpr(b, unw_info);
bases.push_back(base);
}
CompilerVariable* _bases_tuple = makeTuple(bases);
for (auto b : bases) {
b->decvref(emitter);
}
ConcreteCompilerVariable* bases_tuple = _bases_tuple->makeConverted(emitter, _bases_tuple->getBoxType());
_bases_tuple->decvref(emitter);
std::vector<CompilerVariable*> decorators;
for (auto d : node->decorator_list) {
decorators.push_back(evalExpr(d, unw_info));
}
CLFunction* cl = wrapFunction(node, nullptr, node->body, irstate->getSourceInfo());
// TODO duplication with _createFunction:
CompilerVariable* created_closure = NULL;
if (scope_info->takesClosure()) {
created_closure = symbol_table[internString(CREATED_CLOSURE_NAME)];
assert(created_closure);
}
// TODO kind of silly to create the function just to usually-delete it afterwards;
// 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
// create that scope to pass the closure through.
CompilerVariable* func = makeFunction(emitter, cl, created_closure, false, {});
CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(unw_info), ArgPassSpec(0), {}, NULL);
func->decvref(emitter);
ConcreteCompilerVariable* converted_attr_dict = attr_dict->makeConverted(emitter, attr_dict->getBoxType());
attr_dict->decvref(emitter);
llvm::Value* classobj = emitter.createCall3(unw_info, g.funcs.createUserClass,
embedConstantPtr(&node->name.str(), g.llvm_str_type_ptr),
bases_tuple->getValue(), converted_attr_dict->getValue());
// Note: createuserClass is free to manufacture non-class objects
CompilerVariable* cls = new ConcreteCompilerVariable(UNKNOWN, classobj, true);
for (int i = decorators.size() - 1; i >= 0; i--) {
cls = decorators[i]->call(emitter, getOpInfoForNode(node, unw_info), ArgPassSpec(1), { cls }, NULL);
decorators[i]->decvref(emitter);
}
_doSet(irstate->getSourceInfo()->mangleName(node->name), cls, unw_info);
cls->decvref(emitter);
}
void doDelete(AST_Delete* node, UnwindInfo unw_info) { void doDelete(AST_Delete* node, UnwindInfo unw_info) {
for (AST_expr* target : node->targets) { for (AST_expr* target : node->targets) {
switch (target->type) { switch (target->type) {
...@@ -1548,70 +1619,6 @@ private: ...@@ -1548,70 +1619,6 @@ private:
symbol_table.erase(target->id); symbol_table.erase(target->id);
} }
CompilerVariable* _createFunction(AST* node, UnwindInfo unw_info, AST_arguments* args,
const std::vector<AST_stmt*>& body) {
CLFunction* cl = wrapFunction(node, args, body, irstate->getSourceInfo());
std::vector<ConcreteCompilerVariable*> defaults;
for (auto d : args->defaults) {
CompilerVariable* e = evalExpr(d, unw_info);
ConcreteCompilerVariable* converted = e->makeConverted(emitter, e->getBoxType());
e->decvref(emitter);
defaults.push_back(converted);
}
CompilerVariable* created_closure = NULL;
bool takes_closure;
// Optimization: when compiling a module, it's nice to not have to run analyses into the
// entire module's source code.
// If we call getScopeInfoForNode, that will trigger an analysis of that function tree,
// but we're only using it here to figure out if that function takes a closure.
// Top level functions never take a closure, so we can skip the analysis.
if (irstate->getSourceInfo()->ast->type == AST_TYPE::Module)
takes_closure = false;
else {
takes_closure = irstate->getScopeInfoForNode(node)->takesClosure();
}
bool is_generator = cl->source->is_generator;
if (takes_closure) {
if (irstate->getScopeInfo()->createsClosure()) {
created_closure = symbol_table[internString(CREATED_CLOSURE_NAME)];
} else {
assert(irstate->getScopeInfo()->passesThroughClosure());
created_closure = symbol_table[internString(PASSED_CLOSURE_NAME)];
}
assert(created_closure);
}
CompilerVariable* func = makeFunction(emitter, cl, created_closure, is_generator, defaults);
for (auto d : defaults) {
d->decvref(emitter);
}
return func;
}
void doFunctionDef(AST_FunctionDef* node, UnwindInfo unw_info) {
std::vector<CompilerVariable*> decorators;
for (auto d : node->decorator_list) {
decorators.push_back(evalExpr(d, unw_info));
}
CompilerVariable* func = _createFunction(node, unw_info, node->args, node->body);
for (int i = decorators.size() - 1; i >= 0; i--) {
func = decorators[i]->call(emitter, getOpInfoForNode(node, unw_info), ArgPassSpec(1), { func }, NULL);
decorators[i]->decvref(emitter);
}
_doSet(irstate->getSourceInfo()->mangleName(node->name), func, unw_info);
func->decvref(emitter);
}
void doPrint(AST_Print* node, UnwindInfo unw_info) { void doPrint(AST_Print* node, UnwindInfo unw_info) {
ConcreteCompilerVariable* dest = NULL; ConcreteCompilerVariable* dest = NULL;
if (node->dest) { if (node->dest) {
...@@ -1980,18 +1987,12 @@ private: ...@@ -1980,18 +1987,12 @@ private:
case AST_TYPE::Assign: case AST_TYPE::Assign:
doAssign(ast_cast<AST_Assign>(node), unw_info); doAssign(ast_cast<AST_Assign>(node), unw_info);
break; break;
case AST_TYPE::ClassDef:
doClassDef(ast_cast<AST_ClassDef>(node), unw_info);
break;
case AST_TYPE::Delete: case AST_TYPE::Delete:
doDelete(ast_cast<AST_Delete>(node), unw_info); doDelete(ast_cast<AST_Delete>(node), unw_info);
break; break;
case AST_TYPE::Expr: case AST_TYPE::Expr:
doExpr(ast_cast<AST_Expr>(node), unw_info); doExpr(ast_cast<AST_Expr>(node), unw_info);
break; break;
case AST_TYPE::FunctionDef:
doFunctionDef(ast_cast<AST_FunctionDef>(node), unw_info);
break;
// case AST_TYPE::If: // case AST_TYPE::If:
// doIf(ast_cast<AST_If>(node)); // doIf(ast_cast<AST_If>(node));
// break; // break;
......
...@@ -953,7 +953,6 @@ void AST_Branch::accept_stmt(StmtVisitor* v) { ...@@ -953,7 +953,6 @@ void AST_Branch::accept_stmt(StmtVisitor* v) {
v->visit_branch(this); v->visit_branch(this);
} }
void AST_Jump::accept(ASTVisitor* v) { void AST_Jump::accept(ASTVisitor* v) {
bool skip = v->visit_jump(this); bool skip = v->visit_jump(this);
if (skip) if (skip)
...@@ -976,7 +975,29 @@ void* AST_ClsAttribute::accept_expr(ExprVisitor* v) { ...@@ -976,7 +975,29 @@ void* AST_ClsAttribute::accept_expr(ExprVisitor* v) {
return v->visit_clsattribute(this); return v->visit_clsattribute(this);
} }
void AST_MakeFunction::accept(ASTVisitor* v) {
bool skip = v->visit_makefunction(this);
if (skip)
return;
function_def->accept(v);
}
void* AST_MakeFunction::accept_expr(ExprVisitor* v) {
return v->visit_makefunction(this);
}
void AST_MakeClass::accept(ASTVisitor* v) {
bool skip = v->visit_makeclass(this);
if (skip)
return;
class_def->accept(v);
}
void* AST_MakeClass::accept_expr(ExprVisitor* v) {
return v->visit_makeclass(this);
}
void print_ast(AST* ast) { void print_ast(AST* ast) {
PrintVisitor v; PrintVisitor v;
...@@ -1851,6 +1872,16 @@ bool PrintVisitor::visit_clsattribute(AST_ClsAttribute* node) { ...@@ -1851,6 +1872,16 @@ bool PrintVisitor::visit_clsattribute(AST_ClsAttribute* node) {
return true; return true;
} }
bool PrintVisitor::visit_makefunction(AST_MakeFunction* node) {
printf("make_");
return false;
}
bool PrintVisitor::visit_makeclass(AST_MakeClass* node) {
printf("make_");
return false;
}
class FlattenVisitor : public ASTVisitor { class FlattenVisitor : public ASTVisitor {
private: private:
std::vector<AST*>* output; std::vector<AST*>* output;
...@@ -2098,6 +2129,15 @@ public: ...@@ -2098,6 +2129,15 @@ public:
output->push_back(node); output->push_back(node);
return false; return false;
} }
virtual bool visit_makeclass(AST_MakeClass* node) {
output->push_back(node);
return false;
}
virtual bool visit_makefunction(AST_MakeFunction* node) {
output->push_back(node);
return false;
}
}; };
void flatten(const std::vector<AST_stmt*>& roots, std::vector<AST*>& output, bool expand_scopes) { void flatten(const std::vector<AST_stmt*>& roots, std::vector<AST*>& output, bool expand_scopes) {
......
...@@ -128,6 +128,8 @@ enum AST_TYPE { ...@@ -128,6 +128,8 @@ enum AST_TYPE {
AugBinOp = 203, AugBinOp = 203,
Invoke = 204, Invoke = 204,
LangPrimitive = 205, LangPrimitive = 205,
MakeClass = 206, // wraps a ClassDef to make it an expr
MakeFunction = 207, // wraps a FunctionDef to make it an expr
// These aren't real AST types, but since we use AST types to represent binexp types // These aren't real AST types, but since we use AST types to represent binexp types
// and divmod+truediv are essentially types of binops, we add them here (at least for now): // and divmod+truediv are essentially types of binops, we add them here (at least for now):
...@@ -951,6 +953,31 @@ public: ...@@ -951,6 +953,31 @@ public:
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Yield; static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Yield;
}; };
class AST_MakeFunction : public AST_expr {
public:
AST_FunctionDef* function_def;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_MakeFunction(AST_FunctionDef* fd)
: AST_expr(AST_TYPE::MakeFunction, fd->lineno, fd->col_offset), function_def(fd) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::MakeFunction;
};
class AST_MakeClass : public AST_expr {
public:
AST_ClassDef* class_def;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_MakeClass(AST_ClassDef* cd) : AST_expr(AST_TYPE::MakeClass, cd->lineno, cd->col_offset), class_def(cd) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::MakeClass;
};
// AST pseudo-nodes that will get added during CFG-construction. These don't exist in the input AST, but adding them in // AST pseudo-nodes that will get added during CFG-construction. These don't exist in the input AST, but adding them in
// lets us avoid creating a completely new IR for this phase // lets us avoid creating a completely new IR for this phase
...@@ -1116,6 +1143,8 @@ public: ...@@ -1116,6 +1143,8 @@ public:
virtual bool visit_with(AST_With* node) { RELEASE_ASSERT(0, ""); } virtual bool visit_with(AST_With* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_yield(AST_Yield* node) { RELEASE_ASSERT(0, ""); } virtual bool visit_yield(AST_Yield* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_makeclass(AST_MakeClass* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_makefunction(AST_MakeFunction* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_branch(AST_Branch* node) { RELEASE_ASSERT(0, ""); } virtual bool visit_branch(AST_Branch* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_jump(AST_Jump* node) { RELEASE_ASSERT(0, ""); } virtual bool visit_jump(AST_Jump* node) { RELEASE_ASSERT(0, ""); }
}; };
...@@ -1188,6 +1217,8 @@ public: ...@@ -1188,6 +1217,8 @@ public:
virtual bool visit_branch(AST_Branch* node) { return false; } virtual bool visit_branch(AST_Branch* node) { return false; }
virtual bool visit_jump(AST_Jump* node) { return false; } virtual bool visit_jump(AST_Jump* node) { return false; }
virtual bool visit_makeclass(AST_MakeClass* node) { return false; }
virtual bool visit_makefunction(AST_MakeFunction* node) { return false; }
}; };
class ExprVisitor { class ExprVisitor {
...@@ -1224,6 +1255,8 @@ public: ...@@ -1224,6 +1255,8 @@ public:
virtual void* visit_tuple(AST_Tuple* node) { RELEASE_ASSERT(0, ""); } virtual void* visit_tuple(AST_Tuple* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_unaryop(AST_UnaryOp* node) { RELEASE_ASSERT(0, ""); } virtual void* visit_unaryop(AST_UnaryOp* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_yield(AST_Yield* node) { RELEASE_ASSERT(0, ""); } virtual void* visit_yield(AST_Yield* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_makeclass(AST_MakeClass* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_makefunction(AST_MakeFunction* node) { RELEASE_ASSERT(0, ""); }
}; };
class StmtVisitor { class StmtVisitor {
...@@ -1333,6 +1366,8 @@ public: ...@@ -1333,6 +1366,8 @@ public:
virtual bool visit_branch(AST_Branch* node); virtual bool visit_branch(AST_Branch* node);
virtual bool visit_jump(AST_Jump* node); virtual bool visit_jump(AST_Jump* node);
virtual bool visit_makefunction(AST_MakeFunction* node);
virtual bool visit_makeclass(AST_MakeClass* node);
}; };
// Given an AST node, return a vector of the node plus all its descendents. // Given an AST node, return a vector of the node plus all its descendents.
......
...@@ -799,7 +799,7 @@ private: ...@@ -799,7 +799,7 @@ private:
// Generates a FunctionDef which produces scope for `node'. The function produced is empty, so you'd better fill it. // Generates a FunctionDef which produces scope for `node'. The function produced is empty, so you'd better fill it.
// `node' had better be a kind of node that scoping_analysis thinks can carry scope (see the switch (node->type) // `node' had better be a kind of node that scoping_analysis thinks can carry scope (see the switch (node->type)
// block in ScopingAnalysis::processNameUsages in analysis/scoping_analysis.cpp); e.g. a Lambda or GeneratorExp. // block in ScopingAnalysis::processNameUsages in analysis/scoping_analysis.cpp); e.g. a Lambda or GeneratorExp.
AST_FunctionDef* makeFunctionForScope(AST* node) { AST_MakeFunction* makeFunctionForScope(AST* node) {
AST_FunctionDef* func = new AST_FunctionDef(); AST_FunctionDef* func = new AST_FunctionDef();
func->lineno = node->lineno; func->lineno = node->lineno;
func->col_offset = node->col_offset; func->col_offset = node->col_offset;
...@@ -809,7 +809,7 @@ private: ...@@ -809,7 +809,7 @@ private:
func->args->vararg = internString(""); func->args->vararg = internString("");
func->args->kwarg = internString(""); func->args->kwarg = internString("");
scoping_analysis->registerScopeReplacement(node, func); // critical bit scoping_analysis->registerScopeReplacement(node, func); // critical bit
return func; return new AST_MakeFunction(func);
} }
// This is a helper function used for generator expressions and comprehensions. // This is a helper function used for generator expressions and comprehensions.
...@@ -851,18 +851,18 @@ private: ...@@ -851,18 +851,18 @@ private:
AST_expr* first = remapExpr(node->generators[0]->iter); AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]); InternedString first_generator_name = nodeName(node->generators[0]);
AST_FunctionDef* func = makeFunctionForScope(node); AST_MakeFunction* func = makeFunctionForScope(node);
func->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno)); func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
emitComprehensionLoops(&func->body, node->generators, emitComprehensionLoops(&func->function_def->body, node->generators,
makeName(first_generator_name, AST_TYPE::Load, node->lineno), makeName(first_generator_name, AST_TYPE::Load, node->lineno),
[this, node](std::vector<AST_stmt*>* insert_point) { [this, node](std::vector<AST_stmt*>* insert_point) {
auto y = new AST_Yield(); auto y = new AST_Yield();
y->value = node->elt; y->value = node->elt;
insert_point->push_back(makeExpr(y)); insert_point->push_back(makeExpr(y));
}); });
push_back(func); pushAssign(func->function_def->name, func);
return makeCall(makeName(func->name, AST_TYPE::Load, node->lineno), first); return makeCall(makeName(func->function_def->name, AST_TYPE::Load, node->lineno), first);
} }
void emitComprehensionYield(AST_DictComp* node, InternedString dict_name, std::vector<AST_stmt*>* insert_point) { void emitComprehensionYield(AST_DictComp* node, InternedString dict_name, std::vector<AST_stmt*>* insert_point) {
...@@ -883,27 +883,27 @@ private: ...@@ -883,27 +883,27 @@ private:
AST_expr* first = remapExpr(node->generators[0]->iter); AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]); InternedString first_generator_name = nodeName(node->generators[0]);
AST_FunctionDef* func = makeFunctionForScope(node); AST_MakeFunction* func = makeFunctionForScope(node);
func->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno)); func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
InternedString rtn_name = nodeName(node); InternedString rtn_name = nodeName(node);
auto asgn = new AST_Assign(); auto asgn = new AST_Assign();
asgn->targets.push_back(makeName(rtn_name, AST_TYPE::Store, node->lineno)); asgn->targets.push_back(makeName(rtn_name, AST_TYPE::Store, node->lineno));
asgn->value = new ResultType(); asgn->value = new ResultType();
func->body.push_back(asgn); func->function_def->body.push_back(asgn);
auto lambda = auto lambda =
[&](std::vector<AST_stmt*>* insert_point) { emitComprehensionYield(node, rtn_name, insert_point); }; [&](std::vector<AST_stmt*>* insert_point) { emitComprehensionYield(node, rtn_name, insert_point); };
AST_Name* first_name = makeName(first_generator_name, AST_TYPE::Load, node->lineno); AST_Name* first_name = makeName(first_generator_name, AST_TYPE::Load, node->lineno);
emitComprehensionLoops(&func->body, node->generators, first_name, lambda); emitComprehensionLoops(&func->function_def->body, node->generators, first_name, lambda);
auto rtn = new AST_Return(); auto rtn = new AST_Return();
rtn->value = makeName(rtn_name, AST_TYPE::Load, node->lineno); rtn->value = makeName(rtn_name, AST_TYPE::Load, node->lineno);
func->body.push_back(rtn); func->function_def->body.push_back(rtn);
push_back(func); pushAssign(func->function_def->name, func);
return makeCall(makeName(func->name, AST_TYPE::Load, node->lineno), first); return makeCall(makeName(func->function_def->name, AST_TYPE::Load, node->lineno), first);
} }
AST_expr* remapIfExp(AST_IfExp* node) { AST_expr* remapIfExp(AST_IfExp* node) {
...@@ -957,14 +957,25 @@ private: ...@@ -957,14 +957,25 @@ private:
return rtn; return rtn;
} }
AST_expr* remapLambda(AST_Lambda* node) { AST_arguments* remapArguments(AST_arguments* args) {
// Remap in place: see note in visit_functiondef for why. auto rtn = new AST_arguments();
rtn = new AST_arguments();
for (int i = 0; i < node->args->defaults.size(); i++) { // don't remap args, they're not evaluated. NB. expensive vector copy.
node->args->defaults[i] = remapExpr(node->args->defaults[i]); rtn->args = args->args;
rtn->kwarg = args->kwarg;
rtn->vararg = args->vararg;
for (auto expr : args->defaults)
rtn->defaults.push_back(remapExpr(expr));
return rtn;
} }
return node; AST_expr* remapLambda(AST_Lambda* node) {
auto rtn = new AST_Lambda();
rtn->body = node->body; // don't remap now; will be CFG'ed later
rtn->args = remapArguments(node->args);
// lambdas create scope, need to register as replacement
scoping_analysis->registerScopeReplacement(node, rtn);
return rtn;
} }
AST_expr* remapLangPrimitive(AST_LangPrimitive* node) { AST_expr* remapLangPrimitive(AST_LangPrimitive* node) {
...@@ -1277,42 +1288,47 @@ public: ...@@ -1277,42 +1288,47 @@ public:
} }
bool visit_classdef(AST_ClassDef* node) override { bool visit_classdef(AST_ClassDef* node) override {
// Remap in place: see note in visit_functiondef for why. // waitaminute, who deallocates `node'?
auto def = new AST_ClassDef();
// Decorators are evaluated before the defaults: def->lineno = node->lineno;
for (int i = 0; i < node->decorator_list.size(); i++) { def->col_offset = node->col_offset;
node->decorator_list[i] = remapExpr(node->decorator_list[i]); def->name = node->name;
} def->body = node->body; // expensive vector copy
// Decorators are evaluated before bases:
for (auto expr : node->decorator_list)
def->decorator_list.push_back(remapExpr(expr));
for (auto expr : node->bases)
def->bases.push_back(remapExpr(expr));
scoping_analysis->registerScopeReplacement(node, def);
auto tmp = nodeName(node);
pushAssign(tmp, new AST_MakeClass(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno));
for (int i = 0; i < node->bases.size(); i++) {
node->bases[i] = remapExpr(node->bases[i]);
}
push_back(node);
return true; return true;
} }
// FIXME: make this use MakeFunction
bool visit_functiondef(AST_FunctionDef* node) override { bool visit_functiondef(AST_FunctionDef* node) override {
// As much as I don't like it, for now we're remapping these in place. auto def = new AST_FunctionDef();
// This is because we do certain analyses pre-remapping, and associate the def->name = node->name;
// results with the node. We can either do some refactoring and have a way def->body = node->body; // expensive vector copy
// of associating the new node with the same results, or just do the remapping // Decorators are evaluated before the defaults, so this *must* go before remapArguments().
// in-place. // TODO(rntz): do we have a test for this
// Doing it in-place seems ugly, but I can't think of anything it should break, for (auto expr : node->decorator_list)
// so just do that for now. def->decorator_list.push_back(remapExpr(expr));
// TODO If we remap these (functiondefs, lambdas, classdefs) in place, we should probably def->args = remapArguments(node->args);
// remap everything in place?
scoping_analysis->registerScopeReplacement(node, def);
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) { auto tmp = nodeName(node);
node->decorator_list[i] = remapExpr(node->decorator_list[i]); pushAssign(tmp, new AST_MakeFunction(def));
} // is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno));
for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
}
push_back(node);
return true; return true;
} }
......
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