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:
}
}
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) {
getType(d);
}
......@@ -521,9 +523,8 @@ private:
}
// TODO should we speculate that classdefs will generally return a class?
// CompilerType* t = typeFromClass(type_cls);
CompilerType* t = UNKNOWN;
_doSet(scope_info->mangleName(node->name), t);
// return typeFromClass(type_cls);
return UNKNOWN;
}
void visit_delete(AST_Delete* node) override {
......@@ -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) {
getType(d);
}
......@@ -563,7 +566,7 @@ private:
CompilerType* t = UNKNOWN;
if (node->decorator_list.empty())
t = typeFromClass(function_cls);
_doSet(scope_info->mangleName(node->name), t);
return t;
}
void visit_global(AST_Global* node) override {}
......
......@@ -88,10 +88,8 @@ private:
Value visit_assign(AST_Assign* node);
Value visit_binop(AST_BinOp* node);
Value visit_call(AST_Call* node);
Value visit_classDef(AST_ClassDef* node);
Value visit_compare(AST_Compare* node);
Value visit_delete(AST_Delete* node);
Value visit_functionDef(AST_FunctionDef* node);
Value visit_global(AST_Global* node);
Value visit_module(AST_Module* node);
Value visit_print(AST_Print* node);
......@@ -117,6 +115,8 @@ private:
Value visit_tuple(AST_Tuple* node);
Value visit_yield(AST_Yield* node);
Value visit_makeClass(AST_MakeClass* node);
Value visit_makeFunction(AST_MakeFunction* node);
// pseudo
Value visit_augBinOp(AST_AugBinOp* node);
......@@ -606,14 +606,10 @@ Value ASTInterpreter::visit_stmt(AST_stmt* node) {
return visit_assert((AST_Assert*)node);
case AST_TYPE::Assign:
return visit_assign((AST_Assign*)node);
case AST_TYPE::ClassDef:
return visit_classDef((AST_ClassDef*)node);
case AST_TYPE::Delete:
return visit_delete((AST_Delete*)node);
case AST_TYPE::Expr:
return visit_expr((AST_Expr*)node);
case AST_TYPE::FunctionDef:
return visit_functionDef((AST_FunctionDef*)node);
case AST_TYPE::Pass:
return Value(); // nothing todo
case AST_TYPE::Print:
......@@ -691,7 +687,8 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
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;
std::vector<Box*, StlCompatAllocator<Box*>> decorators;
......@@ -703,11 +700,11 @@ Value ASTInterpreter::visit_functionDef(AST_FunctionDef* node) {
for (int i = decorators.size() - 1; i >= 0; i--)
func = runtimeCall(decorators[i], ArgPassSpec(1), func, 0, 0, 0, 0);
doStore(source_info->mangleName(node->name), func);
return Value();
return Value(func);
}
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);
assert(scope_info);
......@@ -730,8 +727,7 @@ Value ASTInterpreter::visit_classDef(AST_ClassDef* node) {
for (int i = decorators.size() - 1; i >= 0; i--)
classobj = runtimeCall(decorators[i], ArgPassSpec(1), classobj, 0, 0, 0, 0);
doStore(source_info->mangleName(node->name), classobj);
return Value();
return Value(classobj);
}
Value ASTInterpreter::visit_raise(AST_Raise* node) {
......@@ -897,6 +893,10 @@ Value ASTInterpreter::visit_expr(AST_expr* node) {
return visit_clsAttribute((AST_ClsAttribute*)node);
case AST_TYPE::LangPrimitive:
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:
RELEASE_ASSERT(0, "");
};
......
......@@ -1091,6 +1091,133 @@ private:
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) {
if (t == BOXED_INT) {
llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v);
......@@ -1176,12 +1303,19 @@ private:
rtn = evalYield(ast_cast<AST_Yield>(node), unw_info);
break;
// pseudo-nodes
case AST_TYPE::ClsAttribute:
rtn = evalClsAttribute(ast_cast<AST_ClsAttribute>(node), unw_info);
break;
case AST_TYPE::LangPrimitive:
rtn = evalLangPrimitive(ast_cast<AST_LangPrimitive>(node), unw_info);
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:
printf("Unhandled expr type: %d (irgenerator.cpp:" STRINGIFY(__LINE__) ")\n", node->type);
exit(1);
......@@ -1394,69 +1528,6 @@ private:
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) {
for (AST_expr* target : node->targets) {
switch (target->type) {
......@@ -1548,70 +1619,6 @@ private:
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) {
ConcreteCompilerVariable* dest = NULL;
if (node->dest) {
......@@ -1980,18 +1987,12 @@ private:
case AST_TYPE::Assign:
doAssign(ast_cast<AST_Assign>(node), unw_info);
break;
case AST_TYPE::ClassDef:
doClassDef(ast_cast<AST_ClassDef>(node), unw_info);
break;
case AST_TYPE::Delete:
doDelete(ast_cast<AST_Delete>(node), unw_info);
break;
case AST_TYPE::Expr:
doExpr(ast_cast<AST_Expr>(node), unw_info);
break;
case AST_TYPE::FunctionDef:
doFunctionDef(ast_cast<AST_FunctionDef>(node), unw_info);
break;
// case AST_TYPE::If:
// doIf(ast_cast<AST_If>(node));
// break;
......
......@@ -953,7 +953,6 @@ void AST_Branch::accept_stmt(StmtVisitor* v) {
v->visit_branch(this);
}
void AST_Jump::accept(ASTVisitor* v) {
bool skip = v->visit_jump(this);
if (skip)
......@@ -976,7 +975,29 @@ void* AST_ClsAttribute::accept_expr(ExprVisitor* v) {
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) {
PrintVisitor v;
......@@ -1851,6 +1872,16 @@ bool PrintVisitor::visit_clsattribute(AST_ClsAttribute* node) {
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 {
private:
std::vector<AST*>* output;
......@@ -2098,6 +2129,15 @@ public:
output->push_back(node);
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) {
......
......@@ -128,6 +128,8 @@ enum AST_TYPE {
AugBinOp = 203,
Invoke = 204,
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
// and divmod+truediv are essentially types of binops, we add them here (at least for now):
......@@ -951,6 +953,31 @@ public:
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
// lets us avoid creating a completely new IR for this phase
......@@ -1116,6 +1143,8 @@ public:
virtual bool visit_with(AST_With* 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_jump(AST_Jump* node) { RELEASE_ASSERT(0, ""); }
};
......@@ -1188,6 +1217,8 @@ public:
virtual bool visit_branch(AST_Branch* 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 {
......@@ -1224,6 +1255,8 @@ public:
virtual void* visit_tuple(AST_Tuple* 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_makeclass(AST_MakeClass* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_makefunction(AST_MakeFunction* node) { RELEASE_ASSERT(0, ""); }
};
class StmtVisitor {
......@@ -1333,6 +1366,8 @@ public:
virtual bool visit_branch(AST_Branch* 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.
......
......@@ -799,7 +799,7 @@ private:
// 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)
// 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();
func->lineno = node->lineno;
func->col_offset = node->col_offset;
......@@ -809,7 +809,7 @@ private:
func->args->vararg = internString("");
func->args->kwarg = internString("");
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.
......@@ -851,18 +851,18 @@ private:
AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]);
AST_FunctionDef* func = makeFunctionForScope(node);
func->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
emitComprehensionLoops(&func->body, node->generators,
AST_MakeFunction* func = makeFunctionForScope(node);
func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
emitComprehensionLoops(&func->function_def->body, node->generators,
makeName(first_generator_name, AST_TYPE::Load, node->lineno),
[this, node](std::vector<AST_stmt*>* insert_point) {
auto y = new AST_Yield();
y->value = node->elt;
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) {
......@@ -883,27 +883,27 @@ private:
AST_expr* first = remapExpr(node->generators[0]->iter);
InternedString first_generator_name = nodeName(node->generators[0]);
AST_FunctionDef* func = makeFunctionForScope(node);
func->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
AST_MakeFunction* func = makeFunctionForScope(node);
func->function_def->args->args.push_back(makeName(first_generator_name, AST_TYPE::Param, node->lineno));
InternedString rtn_name = nodeName(node);
auto asgn = new AST_Assign();
asgn->targets.push_back(makeName(rtn_name, AST_TYPE::Store, node->lineno));
asgn->value = new ResultType();
func->body.push_back(asgn);
func->function_def->body.push_back(asgn);
auto lambda =
[&](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);
emitComprehensionLoops(&func->body, node->generators, first_name, lambda);
emitComprehensionLoops(&func->function_def->body, node->generators, first_name, lambda);
auto rtn = new AST_Return();
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) {
......@@ -957,14 +957,25 @@ private:
return rtn;
}
AST_expr* remapLambda(AST_Lambda* node) {
// Remap in place: see note in visit_functiondef for why.
for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
}
AST_arguments* remapArguments(AST_arguments* args) {
auto rtn = new AST_arguments();
rtn = new AST_arguments();
// don't remap args, they're not evaluated. NB. expensive vector copy.
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) {
......@@ -1277,42 +1288,47 @@ public:
}
bool visit_classdef(AST_ClassDef* node) override {
// Remap in place: see note in visit_functiondef for why.
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) {
node->decorator_list[i] = remapExpr(node->decorator_list[i]);
}
for (int i = 0; i < node->bases.size(); i++) {
node->bases[i] = remapExpr(node->bases[i]);
}
// waitaminute, who deallocates `node'?
auto def = new AST_ClassDef();
def->lineno = node->lineno;
def->col_offset = node->col_offset;
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));
push_back(node);
return true;
}
// FIXME: make this use MakeFunction
bool visit_functiondef(AST_FunctionDef* node) override {
// As much as I don't like it, for now we're remapping these in place.
// This is because we do certain analyses pre-remapping, and associate the
// results with the node. We can either do some refactoring and have a way
// of associating the new node with the same results, or just do the remapping
// in-place.
// Doing it in-place seems ugly, but I can't think of anything it should break,
// so just do that for now.
// TODO If we remap these (functiondefs, lambdas, classdefs) in place, we should probably
// remap everything in place?
auto def = new AST_FunctionDef();
def->name = node->name;
def->body = node->body; // expensive vector copy
// Decorators are evaluated before the defaults, so this *must* go before remapArguments().
// TODO(rntz): do we have a test for this
for (auto expr : node->decorator_list)
def->decorator_list.push_back(remapExpr(expr));
def->args = remapArguments(node->args);
scoping_analysis->registerScopeReplacement(node, def);
auto tmp = nodeName(node);
pushAssign(tmp, new AST_MakeFunction(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno));
// Decorators are evaluated before the defaults:
for (int i = 0; i < node->decorator_list.size(); i++) {
node->decorator_list[i] = remapExpr(node->decorator_list[i]);
}
for (int i = 0; i < node->args->defaults.size(); i++) {
node->args->defaults[i] = remapExpr(node->args->defaults[i]);
}
push_back(node);
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