Skip to content

Commit 70160f8

Browse files
committed
Basic handling of try/except/finally blocks.
1 parent ac4d254 commit 70160f8

File tree

4 files changed

+102
-3
lines changed

4 files changed

+102
-3
lines changed

ASTNode.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void ASTBlock::removeFirst()
7878
const char* ASTBlock::type_str() const
7979
{
8080
static const char* s_type_strings[] = {
81-
"", "if", "else", "elif", "try", "EXCEPT CONTAINER", "except",
81+
"", "if", "else", "elif", "try", "CONTAINER", "except",
8282
"finally", "while", "for"
8383
};
8484
return s_type_strings[blktype()];

ASTNode.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ class ASTBlock : public ASTNode {
408408

409409
enum BlkType {
410410
BLK_MAIN, BLK_IF, BLK_ELSE, BLK_ELIF, BLK_TRY,
411-
BLK_EXCEPT_CONTAINER, BLK_EXCEPT, BLK_FINALLY,
411+
BLK_CONTAINER, BLK_EXCEPT, BLK_FINALLY,
412412
BLK_WHILE, BLK_FOR
413413
};
414414

@@ -471,4 +471,19 @@ class ASTIterBlock : public ASTBlock {
471471
PycRef<ASTNode> m_idx;
472472
};
473473

474+
class ASTContainerBlock : public ASTBlock {
475+
public:
476+
ASTContainerBlock(bool hasFinally, bool hasExcept = false)
477+
: ASTBlock(ASTBlock::BLK_CONTAINER, 0), m_hasFinally(hasFinally), m_hasExcept(hasExcept) { }
478+
479+
bool hasFinally() const { return m_hasFinally; }
480+
bool hasExcept() const { return m_hasExcept; }
481+
482+
void setHasExcept(bool hasExcept) { m_hasExcept = hasExcept; }
483+
484+
private:
485+
bool m_hasFinally;
486+
bool m_hasExcept;
487+
};
488+
474489
#endif

ASTree.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
2929
bool else_pop = false;
3030

3131
while (!source.atEof()) {
32+
#ifdef BLOCK_DEBUG
33+
fprintf(stderr, "%02d", pos);
34+
for (unsigned int i = 0; i < blocks.size(); i++) fprintf(stderr, " ");
35+
fprintf(stderr, "%s\n", curblock->type_str());
36+
#endif
37+
3238
bc_next(source, mod, opcode, operand, pos);
3339

3440
if (else_pop && opcode != Pyc::JUMP_FORWARD_A) {
@@ -439,6 +445,43 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
439445
break;
440446
case Pyc::END_FINALLY:
441447
{
448+
bool isFinally = false;
449+
if (curblock->blktype() == ASTBlock::BLK_FINALLY) {
450+
PycRef<ASTBlock> final = curblock;
451+
blocks.pop();
452+
453+
curblock = blocks.top();
454+
curblock->append(final.cast<ASTNode>());
455+
isFinally = true;
456+
} else if (curblock->blktype() == ASTBlock::BLK_ELSE) {
457+
/* All except statements have an else block that
458+
* bubbles the exception up.
459+
* If it's empty, we'll ignore it.
460+
*/
461+
if (curblock->size() == 0) {
462+
blocks.pop();
463+
}
464+
465+
curblock = blocks.top();
466+
}
467+
468+
if (curblock->blktype() == ASTBlock::BLK_CONTAINER) {
469+
/* This marks the end of the except block(s). */
470+
PycRef<ASTContainerBlock> cont = curblock.cast<ASTContainerBlock>();
471+
if (!cont->hasFinally() || isFinally) {
472+
/* If there's no finally block, pop the container. */
473+
blocks.pop();
474+
curblock = blocks.top();
475+
curblock->append(cont.cast<ASTNode>());
476+
} else {
477+
/* If we need a finally block, add it here */
478+
PycRef<ASTBlock> final = new ASTBlock(ASTBlock::BLK_FINALLY);
479+
blocks.push(final);
480+
curblock = blocks.top();
481+
}
482+
} else {
483+
fprintf(stderr, "Something TERRIBLE happened.\n");
484+
}
442485
}
443486
break;
444487
case Pyc::EXEC_STMT:
@@ -757,6 +800,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
757800
stack = stack_hist.top();
758801
stack_hist.pop();
759802

803+
if (curblock->blktype() == ASTBlock::BLK_CONTAINER) {
804+
break;
805+
}
806+
760807
PycRef<ASTBlock> prev = curblock;
761808
PycRef<ASTBlock> nil;
762809

@@ -839,6 +886,12 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
839886
break;
840887
case Pyc::POP_BLOCK:
841888
{
889+
if (curblock->blktype() == ASTBlock::BLK_CONTAINER ||
890+
curblock->blktype() == ASTBlock::BLK_FINALLY) {
891+
/* These should only be popped by an END_FINALLY */
892+
break;
893+
}
894+
842895
PycRef<ASTBlock> tmp;
843896

844897
if (curblock->nodes().back()->type() == ASTNode::NODE_KEYWORD) {
@@ -965,10 +1018,25 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
9651018
break;
9661019
case Pyc::SETUP_EXCEPT_A:
9671020
{
1021+
if (curblock->blktype() == ASTBlock::BLK_CONTAINER) {
1022+
curblock.cast<ASTContainerBlock>()->setHasExcept(true);
1023+
} else {
1024+
PycRef<ASTBlock> next = new ASTContainerBlock(false, true);
1025+
blocks.push(next.cast<ASTBlock>());
1026+
}
1027+
1028+
/* Store the current stack for the except/finally statement(s) */
1029+
stack_hist.push(stack);
1030+
PycRef<ASTBlock> tryblock = new ASTBlock(ASTBlock::BLK_TRY, pos+operand);
1031+
blocks.push(tryblock.cast<ASTBlock>());
1032+
curblock = blocks.top();
9681033
}
9691034
break;
9701035
case Pyc::SETUP_FINALLY_A:
9711036
{
1037+
PycRef<ASTBlock> next = new ASTContainerBlock(true);
1038+
blocks.push(next.cast<ASTBlock>());
1039+
curblock = blocks.top();
9721040
}
9731041
break;
9741042
case Pyc::SETUP_LOOP_A:
@@ -1525,6 +1593,22 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
15251593
&& node.cast<ASTBlock>()->size() == 0)
15261594
break;
15271595

1596+
if (node.cast<ASTBlock>()->blktype() == ASTBlock::BLK_CONTAINER) {
1597+
end_line();
1598+
PycRef<ASTBlock> blk = node.cast<ASTBlock>();
1599+
ASTBlock::list_t lines = blk->nodes();
1600+
for (ASTBlock::list_t::const_iterator ln = lines.begin(); ln != lines.end();) {
1601+
if ((*ln).cast<ASTNode>()->type() != ASTNode::NODE_NODELIST) {
1602+
start_line(cur_indent);
1603+
}
1604+
print_src(*ln, mod);
1605+
if (++ln != lines.end()) {
1606+
end_line();
1607+
}
1608+
}
1609+
end_line();
1610+
break;
1611+
}
15281612
inPrint = false;
15291613

15301614
printf("%s", node.cast<ASTBlock>()->type_str());

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CXX = g++
22
CXXFLAGS = -g -Wall
3-
#CXXFLAGS += -fprofile-arcs -ftest-coverage
3+
#CXXFLAGS += -fprofile-arcs -ftest-coverage -DBLOCK_DEBUG
44
LDFLAGS =
55
#LDFLAGS += -lgcov
66

0 commit comments

Comments
 (0)