AST_expr* remapBoolOp(AST_BoolOp* node) { std::string name = nodeName(node); CFGBlock *starting_block = curblock; CFGBlock *exit_block = cfg->addDeferredBlock(); for (int i = 0; i < node->values.size() - 1; i++) { AST_expr* val = remapExpr(node->values[i]); push_back(makeAssign(name, val)); AST_Branch *br = new AST_Branch(); br->test = val; push_back(br); CFGBlock *was_block = curblock; CFGBlock *next_block = cfg->addBlock(); CFGBlock *crit_break_block = cfg->addBlock(); was_block->connectTo(next_block); was_block->connectTo(crit_break_block); if (node->op_type == AST_TYPE::Or) { br->iftrue = crit_break_block; br->iffalse = next_block; } else { br->iffalse = crit_break_block; br->iftrue = next_block; } curblock = crit_break_block; AST_Jump* j = new AST_Jump(); j->target = exit_block; push_back(j); crit_break_block->connectTo(exit_block); curblock = next_block; } AST_expr* final_val = remapExpr(node->values[node->values.size()-1]); push_back(makeAssign(name, final_val)); AST_Jump* j = new AST_Jump(); push_back(j); j->target = exit_block; curblock->connectTo(exit_block); cfg->placeBlock(exit_block); curblock = exit_block; return makeName(name, AST_TYPE::Load); }
/* Create and return a list that is ready for use with the sentence forms. For each node in the settings.wordFiles list, create a node whose left is the settings left (for example, %m) and whose right is the associated word list. */ list_t *loadWords(settings_t settings) { /* Variables used to create the list */ list_t *wordList = createList(); assignment_t *wordAssignment; list_t *wordFile; FILE *f; /* Variables from settings */ node_t *settingNode = settings.wordFiles->head; assignment_t *settingAssignment; char *settingFile; /* Load every node in settings.wordFiles */ while (settingNode != NULL) { settingAssignment = settingNode->datum; settingFile = settingAssignment->right; f = locateFile(settings, settingFile); wordFile = loadWordFile(f); fclose(f); wordAssignment = makeAssign(settingAssignment->left, wordFile); addDatum(wordList, wordAssignment); settingNode = settingNode->next; printf("Loaded %s\n", settingFile); } printf("Loaded the word files.\n\n"); return wordList; }
AST_expr* remapIfExp(AST_IfExp* node) { std::string rtn_name = nodeName(node); AST_expr* test = remapExpr(node->test); CFGBlock *starting_block = curblock; AST_Branch *br = new AST_Branch(); br->col_offset = node->col_offset; br->lineno = node->lineno; br->test = node->test; push_back(br); CFGBlock* iftrue = cfg->addBlock(); iftrue->info = "iftrue"; br->iftrue = iftrue; starting_block->connectTo(iftrue); curblock = iftrue; push_back(makeAssign(rtn_name, remapExpr(node->body))); AST_Jump* jtrue = new AST_Jump(); push_back(jtrue); CFGBlock* endtrue = curblock; CFGBlock* iffalse = cfg->addBlock(); iffalse->info = "iffalse"; br->iffalse = iffalse; starting_block->connectTo(iffalse); curblock = iffalse; push_back(makeAssign(rtn_name, remapExpr(node->orelse))); AST_Jump* jfalse = new AST_Jump(); push_back(jfalse); CFGBlock* endfalse = curblock; CFGBlock* exit_block = cfg->addBlock(); jtrue->target = exit_block; endtrue->connectTo(exit_block); jfalse->target = exit_block; endfalse->connectTo(exit_block); curblock = exit_block; return makeName(rtn_name, AST_TYPE::Load); }
void doReturn(AST_expr* value) { assert(value); CFGBlock *rtn_dest = getReturn(); if (rtn_dest != NULL) { push_back(makeAssign("#rtnval", value)); AST_Jump *j = makeJump(); j->target = rtn_dest; curblock->connectTo(rtn_dest); push_back(j); } else { AST_Return *node = new AST_Return(); node->value = value; node->col_offset = value->col_offset; node->lineno = value->lineno; push_back(node); } curblock = NULL; }
AST_expr* remapExpr(AST_expr* node, bool wrap_with_assign=true) { if (node == NULL) return NULL; AST_expr* rtn; switch (node->type) { case AST_TYPE::Attribute: rtn = remapAttribute(static_cast<AST_Attribute*>(node)); break; case AST_TYPE::BinOp: rtn = remapBinOp(static_cast<AST_BinOp*>(node)); break; case AST_TYPE::BoolOp: rtn = remapBoolOp(static_cast<AST_BoolOp*>(node)); break; case AST_TYPE::Call: rtn = remapCall(static_cast<AST_Call*>(node)); break; case AST_TYPE::Compare: rtn = remapCompare(static_cast<AST_Compare*>(node)); break; case AST_TYPE::Dict: rtn = remapDict(static_cast<AST_Dict*>(node)); break; case AST_TYPE::IfExp: rtn = remapIfExp(static_cast<AST_IfExp*>(node)); break; case AST_TYPE::Index: rtn = remapIndex(static_cast<AST_Index*>(node)); break; case AST_TYPE::List: rtn = remapList(static_cast<AST_List*>(node)); break; case AST_TYPE::ListComp: rtn = remapListComp(static_cast<AST_ListComp*>(node)); break; case AST_TYPE::Name: return node; case AST_TYPE::Num: return node; case AST_TYPE::Slice: rtn = remapSlice(static_cast<AST_Slice*>(node)); break; case AST_TYPE::Str: return node; case AST_TYPE::Subscript: rtn = remapSubscript(static_cast<AST_Subscript*>(node)); break; case AST_TYPE::Tuple: rtn = remapTuple(static_cast<AST_Tuple*>(node)); break; case AST_TYPE::UnaryOp: rtn = remapUnaryOp(static_cast<AST_UnaryOp*>(node)); break; default: RELEASE_ASSERT(0, "%d", node->type); } if (wrap_with_assign && rtn->type != AST_TYPE::Name) { std::string name = nodeName(node); push_back(makeAssign(name, rtn)); return makeName(name, AST_TYPE::Load); } else { 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 = 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_stmt* makeAssign(const std::string &id, AST_expr *val) { assert(val); AST_expr *name = makeName(id, AST_TYPE::Store, val->lineno, 0); return makeAssign(name, val); }