Commit cdab74dc authored by Vinzenz Feenstra's avatar Vinzenz Feenstra

Refactored dict and list comprehension remapping

Signed-off-by: default avatarVinzenz Feenstra <evilissimo@gmail.com>
parent ae1e15a0
......@@ -117,6 +117,146 @@ private:
return NULL;
}
AST_expr* applyComprehensionCall(AST_DictComp * node, AST_Name* name) {
AST_expr* key = remapExpr(node->key);
AST_expr* value = remapExpr(node->value);
return makeCall(makeLoadAttribute(name, "__setitem__", true), key, value);
}
AST_expr* applyComprehensionCall(AST_ListComp * node, AST_Name* name) {
AST_expr* elt = remapExpr(node->elt);
return makeCall(makeLoadAttribute(name, "append", true), elt);
}
template<typename ResultASTType, typename CompType>
AST_expr* remapComprehension(CompType * node) {
std::string rtn_name = nodeName(node);
push_back(makeAssign(rtn_name, new ResultASTType()));
std::vector<CFGBlock*> exit_blocks;
// Where the current level should jump to after finishing its iteration.
// For the outermost comprehension, this is NULL, and it doesn't jump anywhere;
// for the inner comprehensions, they should jump to the next-outer comprehension
// when they are done iterating.
CFGBlock* finished_block = NULL;
for (int i = 0, n = node->generators.size(); i < n; i++) {
AST_comprehension* c = node->generators[i];
bool is_innermost = (i == n - 1);
AST_expr* remapped_iter = remapExpr(c->iter);
AST_expr* iter_attr = makeLoadAttribute(remapped_iter, "__iter__", true);
AST_expr* iter_call = makeCall(iter_attr);
std::string iter_name = nodeName(node, "iter", i);
AST_stmt* iter_assign = makeAssign(iter_name, iter_call);
push_back(iter_assign);
// TODO bad to save these like this?
AST_expr* hasnext_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "__hasnext__", true);
AST_expr* next_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "next", true);
AST_Jump* j;
CFGBlock* test_block = cfg->addBlock();
test_block->info = "comprehension_test";
// printf("Test block for comp %d is %d\n", i, test_block->idx);
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block);
push_back(j);
curblock = test_block;
AST_expr* test_call = remapExpr(makeCall(hasnext_attr));
CFGBlock* body_block = cfg->addBlock();
body_block->info = "comprehension_body";
CFGBlock* exit_block = cfg->addDeferredBlock();
exit_block->info = "comprehension_exit";
exit_blocks.push_back(exit_block);
// printf("Body block for comp %d is %d\n", i, body_block->idx);
AST_Branch* br = new AST_Branch();
br->col_offset = node->col_offset;
br->lineno = node->lineno;
br->test = test_call;
br->iftrue = body_block;
br->iffalse = exit_block;
curblock->connectTo(body_block);
curblock->connectTo(exit_block);
push_back(br);
curblock = body_block;
push_back(makeAssign(c->target, makeCall(next_attr)));
for (AST_expr* if_condition : c->ifs) {
AST_expr* remapped = remapExpr(if_condition);
AST_Branch* br = new AST_Branch();
br->test = remapped;
push_back(br);
// Put this below the entire body?
CFGBlock* body_tramp = cfg->addBlock();
body_tramp->info = "comprehension_if_trampoline";
// printf("body_tramp for %d is %d\n", i, body_tramp->idx);
CFGBlock* body_continue = cfg->addBlock();
body_continue->info = "comprehension_if_continue";
// printf("body_continue for %d is %d\n", i, body_continue->idx);
br->iffalse = body_tramp;
curblock->connectTo(body_tramp);
br->iftrue = body_continue;
curblock->connectTo(body_continue);
curblock = body_tramp;
j = new AST_Jump();
j->target = test_block;
push_back(j);
curblock->connectTo(test_block, true);
curblock = body_continue;
}
CFGBlock* body_end = curblock;
assert((finished_block != NULL) == (i != 0));
if (finished_block) {
curblock = exit_block;
j = new AST_Jump();
j->target = finished_block;
curblock->connectTo(finished_block, true);
push_back(j);
}
finished_block = test_block;
curblock = body_end;
if (is_innermost) {
push_back(
makeExpr(applyComprehensionCall(node, makeName(rtn_name, AST_TYPE::Load)))
);
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block, true);
push_back(j);
assert(exit_blocks.size());
curblock = exit_blocks[0];
} else {
// continue onto the next comprehension and add to this body
}
}
// Wait until the end to place the end blocks, so that
// we get a nice nesting structure, that looks similar to what
// you'd get with a nested for loop:
for (int i = exit_blocks.size() - 1; i >= 0; i--) {
cfg->placeBlock(exit_blocks[i]);
// printf("Exit block for comp %d is %d\n", i, exit_blocks[i]->idx);
}
return makeName(rtn_name, AST_TYPE::Load);
}
AST_expr* makeNum(int n) {
......@@ -381,137 +521,6 @@ private:
return rtn;
};
AST_expr* remapDictComp(AST_DictComp* node) {
std::string rtn_name = nodeName(node);
push_back(makeAssign(rtn_name, new AST_Dict()));
std::vector<CFGBlock*> exit_blocks;
// Where the current level should jump to after finishing its iteration.
// For the outermost comprehension, this is NULL, and it doesn't jump anywhere;
// for the inner comprehensions, they should jump to the next-outer comprehension
// when they are done iterating.
CFGBlock* finished_block = NULL;
for (int i = 0, n = node->generators.size(); i < n; i++) {
AST_comprehension* c = node->generators[i];
bool is_innermost = (i == n - 1);
AST_expr* remapped_iter = remapExpr(c->iter);
AST_expr* iter_attr = makeLoadAttribute(remapped_iter, "__iter__", true);
AST_expr* iter_call = makeCall(iter_attr);
std::string iter_name = nodeName(node, "iter", i);
AST_stmt* iter_assign = makeAssign(iter_name, iter_call);
push_back(iter_assign);
// TODO bad to save these like this?
AST_expr* hasnext_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "__hasnext__", true);
AST_expr* next_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "next", true);
AST_Jump* j;
CFGBlock* test_block = cfg->addBlock();
test_block->info = "dictcomp_test";
// printf("Test block for comp %d is %d\n", i, test_block->idx);
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block);
push_back(j);
curblock = test_block;
AST_expr* test_call = remapExpr(makeCall(hasnext_attr));
CFGBlock* body_block = cfg->addBlock();
body_block->info = "dictcomp_body";
CFGBlock* exit_block = cfg->addDeferredBlock();
exit_block->info = "dictcomp_exit";
exit_blocks.push_back(exit_block);
// printf("Body block for comp %d is %d\n", i, body_block->idx);
AST_Branch* br = new AST_Branch();
br->col_offset = node->col_offset;
br->lineno = node->lineno;
br->test = test_call;
br->iftrue = body_block;
br->iffalse = exit_block;
curblock->connectTo(body_block);
curblock->connectTo(exit_block);
push_back(br);
curblock = body_block;
push_back(makeAssign(c->target, makeCall(next_attr)));
for (AST_expr* if_condition : c->ifs) {
AST_expr* remapped = remapExpr(if_condition);
AST_Branch* br = new AST_Branch();
br->test = remapped;
push_back(br);
// Put this below the entire body?
CFGBlock* body_tramp = cfg->addBlock();
body_tramp->info = "dictcomp_if_trampoline";
// printf("body_tramp for %d is %d\n", i, body_tramp->idx);
CFGBlock* body_continue = cfg->addBlock();
body_continue->info = "dictcomp_if_continue";
// printf("body_continue for %d is %d\n", i, body_continue->idx);
br->iffalse = body_tramp;
curblock->connectTo(body_tramp);
br->iftrue = body_continue;
curblock->connectTo(body_continue);
curblock = body_tramp;
j = new AST_Jump();
j->target = test_block;
push_back(j);
curblock->connectTo(test_block, true);
curblock = body_continue;
}
CFGBlock* body_end = curblock;
assert((finished_block != NULL) == (i != 0));
if (finished_block) {
curblock = exit_block;
j = new AST_Jump();
j->target = finished_block;
curblock->connectTo(finished_block, true);
push_back(j);
}
finished_block = test_block;
curblock = body_end;
if (is_innermost) {
AST_expr* key = remapExpr(node->key);
AST_expr* value = remapExpr(node->value);
push_back(
makeExpr(makeCall(makeLoadAttribute(makeName(rtn_name, AST_TYPE::Load), "__setitem__", true), key, value)));
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block, true);
push_back(j);
assert(exit_blocks.size());
curblock = exit_blocks[0];
} else {
// continue onto the next comprehension and add to this body
}
}
// Wait until the end to place the end blocks, so that
// we get a nice nesting structure, that looks similar to what
// you'd get with a nested for loop:
for (int i = exit_blocks.size() - 1; i >= 0; i--) {
cfg->placeBlock(exit_blocks[i]);
// printf("Exit block for comp %d is %d\n", i, exit_blocks[i]->idx);
}
return makeName(rtn_name, AST_TYPE::Load);
};
AST_expr* remapIfExp(AST_IfExp* node) {
std::string rtn_name = nodeName(node);
......@@ -584,136 +593,6 @@ private:
return rtn;
}
AST_expr* remapListComp(AST_ListComp* node) {
std::string rtn_name = nodeName(node);
push_back(makeAssign(rtn_name, new AST_List()));
std::vector<CFGBlock*> exit_blocks;
// Where the current level should jump to after finishing its iteration.
// For the outermost comprehension, this is NULL, and it doesn't jump anywhere;
// for the inner comprehensions, they should jump to the next-outer comprehension
// when they are done iterating.
CFGBlock* finished_block = NULL;
for (int i = 0, n = node->generators.size(); i < n; i++) {
AST_comprehension* c = node->generators[i];
bool is_innermost = (i == n - 1);
AST_expr* remapped_iter = remapExpr(c->iter);
AST_expr* iter_attr = makeLoadAttribute(remapped_iter, "__iter__", true);
AST_expr* iter_call = makeCall(iter_attr);
std::string iter_name = nodeName(node, "iter", i);
AST_stmt* iter_assign = makeAssign(iter_name, iter_call);
push_back(iter_assign);
// TODO bad to save these like this?
AST_expr* hasnext_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "__hasnext__", true);
AST_expr* next_attr = makeLoadAttribute(makeName(iter_name, AST_TYPE::Load), "next", true);
AST_Jump* j;
CFGBlock* test_block = cfg->addBlock();
test_block->info = "listcomp_test";
// printf("Test block for comp %d is %d\n", i, test_block->idx);
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block);
push_back(j);
curblock = test_block;
AST_expr* test_call = remapExpr(makeCall(hasnext_attr));
CFGBlock* body_block = cfg->addBlock();
body_block->info = "listcomp_body";
CFGBlock* exit_block = cfg->addDeferredBlock();
exit_block->info = "listcomp_exit";
exit_blocks.push_back(exit_block);
// printf("Body block for comp %d is %d\n", i, body_block->idx);
AST_Branch* br = new AST_Branch();
br->col_offset = node->col_offset;
br->lineno = node->lineno;
br->test = test_call;
br->iftrue = body_block;
br->iffalse = exit_block;
curblock->connectTo(body_block);
curblock->connectTo(exit_block);
push_back(br);
curblock = body_block;
push_back(makeAssign(c->target, makeCall(next_attr)));
for (AST_expr* if_condition : c->ifs) {
AST_expr* remapped = remapExpr(if_condition);
AST_Branch* br = new AST_Branch();
br->test = remapped;
push_back(br);
// Put this below the entire body?
CFGBlock* body_tramp = cfg->addBlock();
body_tramp->info = "listcomp_if_trampoline";
// printf("body_tramp for %d is %d\n", i, body_tramp->idx);
CFGBlock* body_continue = cfg->addBlock();
body_continue->info = "listcomp_if_continue";
// printf("body_continue for %d is %d\n", i, body_continue->idx);
br->iffalse = body_tramp;
curblock->connectTo(body_tramp);
br->iftrue = body_continue;
curblock->connectTo(body_continue);
curblock = body_tramp;
j = new AST_Jump();
j->target = test_block;
push_back(j);
curblock->connectTo(test_block, true);
curblock = body_continue;
}
CFGBlock* body_end = curblock;
assert((finished_block != NULL) == (i != 0));
if (finished_block) {
curblock = exit_block;
j = new AST_Jump();
j->target = finished_block;
curblock->connectTo(finished_block, true);
push_back(j);
}
finished_block = test_block;
curblock = body_end;
if (is_innermost) {
AST_expr* elt = remapExpr(node->elt);
push_back(
makeExpr(makeCall(makeLoadAttribute(makeName(rtn_name, AST_TYPE::Load), "append", true), elt)));
j = new AST_Jump();
j->target = test_block;
curblock->connectTo(test_block, true);
push_back(j);
assert(exit_blocks.size());
curblock = exit_blocks[0];
} else {
// continue onto the next comprehension and add to this body
}
}
// Wait until the end to place the end blocks, so that
// we get a nice nesting structure, that looks similar to what
// you'd get with a nested for loop:
for (int i = exit_blocks.size() - 1; i >= 0; i--) {
cfg->placeBlock(exit_blocks[i]);
// printf("Exit block for comp %d is %d\n", i, exit_blocks[i]->idx);
}
return makeName(rtn_name, AST_TYPE::Load);
};
AST_expr* remapRepr(AST_Repr* node) {
AST_Repr* rtn = new AST_Repr();
rtn->lineno = node->lineno;
......@@ -795,7 +674,7 @@ private:
rtn = remapDict(ast_cast<AST_Dict>(node));
break;
case AST_TYPE::DictComp:
rtn = remapDictComp(ast_cast<AST_DictComp>(node));
rtn = remapComprehension<AST_Dict>(ast_cast<AST_DictComp>(node));
break;
case AST_TYPE::IfExp:
rtn = remapIfExp(ast_cast<AST_IfExp>(node));
......@@ -810,7 +689,7 @@ private:
rtn = remapList(ast_cast<AST_List>(node));
break;
case AST_TYPE::ListComp:
rtn = remapListComp(ast_cast<AST_ListComp>(node));
rtn = remapComprehension<AST_List>(ast_cast<AST_ListComp>(node));
break;
case AST_TYPE::Name:
rtn = node;
......
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