Fix for nested if/elif/else statements

This commit is contained in:
Darryl Pogue
2010-12-31 21:45:06 -08:00
parent 132d62baf6
commit 5392ffc3e7

View File

@@ -24,10 +24,20 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
int opcode, operand;
int pos = 0;
bool else_pop = false;
while (!source.atEof()) {
bc_next(source, mod, opcode, operand, pos);
if (else_pop && opcode != Pyc::JUMP_FORWARD_A) {
else_pop = false;
PycRef<ASTBlock> prev = curblock;
blocks.pop();
curblock = blocks.top();
curblock->append(prev.cast<ASTNode>());
}
switch (opcode) {
case Pyc::BINARY_ADD:
{
@@ -339,39 +349,61 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
break;
case Pyc::JUMP_ABSOLUTE_A:
{
stack = FastStack(stack_hist.top());
stack = stack_hist.top();
stack_hist.pop();
if (curblock->blktype() != ASTBlock::BLK_WHILE
&& curblock->blktype() != ASTBlock::BLK_FOR)
if (curblock->blktype() == ASTBlock::BLK_WHILE
|| curblock->blktype() == ASTBlock::BLK_FOR)
{
PycRef<ASTBlock> prev = curblock;
blocks.pop();
blocks.top()->append(prev.cast<ASTNode>());
curblock = blocks.top();
break;
}
}
break;
case Pyc::JUMP_FORWARD_A:
{
stack = FastStack(stack_hist.top());
stack_hist.pop();
PycRef<ASTBlock> prev = curblock;
blocks.pop();
blocks.top()->append(prev.cast<ASTNode>());
if (operand > 1 && (prev->blktype() == ASTBlock::BLK_IF
|| prev->blktype() == ASTBlock::BLK_ELIF))
if (prev->blktype() == ASTBlock::BLK_IF
|| prev->blktype() == ASTBlock::BLK_ELIF)
{
PycRef<ASTBlock> next = new ASTBlock(ASTBlock::BLK_ELSE, pos+operand);
PycRef<ASTBlock> next = new ASTBlock(ASTBlock::BLK_ELSE, blocks.top()->end());
blocks.push(next.cast<ASTBlock>());
}
curblock = blocks.top();
}
break;
case Pyc::JUMP_FORWARD_A:
{
stack = stack_hist.top();
stack_hist.pop();
PycRef<ASTBlock> prev = curblock;
PycRef<ASTBlock> nil;
do {
blocks.pop();
blocks.top()->append(prev.cast<ASTNode>());
if (operand > 1 && (prev->blktype() == ASTBlock::BLK_IF
|| prev->blktype() == ASTBlock::BLK_ELIF))
{
PycRef<ASTBlock> next = new ASTBlock(ASTBlock::BLK_ELSE, pos+operand);
blocks.push(next.cast<ASTBlock>());
prev = nil;
}
else if (operand > 1 && prev->blktype() == ASTBlock::BLK_ELSE)
{
/* Special case */
prev = blocks.top();
} else {
prev = nil;
}
} while (prev != nil);
curblock = blocks.top();
}
break;
case Pyc::LOAD_ATTR_A:
{
PycRef<ASTNode> name = stack.top();
@@ -603,17 +635,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
return new ASTNodeList(defblock->nodes());
}
if (curblock->blktype() == ASTBlock::BLK_ELSE
&& curblock->end() == pos)
{
stack = FastStack(stack_hist.top());
stack_hist.pop();
PycRef<ASTBlock> prev = curblock;
blocks.pop();
curblock = blocks.top();
curblock->append(prev.cast<ASTNode>());
}
else_pop = curblock->blktype() == ASTBlock::BLK_ELSE && curblock->end() == pos;
}
if (stack_hist.size()) {
@@ -624,6 +646,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
}
}
if (blocks.size() > 1) {
fprintf(stderr, "Warning: block stack is not empty!\n");
while (blocks.size() > 1) {
PycRef<ASTBlock> tmp = blocks.top();
blocks.pop();
blocks.top()->append(tmp.cast<ASTNode>());
}
}
cleanBuild = true;
return new ASTNodeList(defblock->nodes());
}