Support Python 3.11 exception table try/except flow

This commit is contained in:
daiche330-png 2026-04-06 09:30:16 +09:00
commit 413fbd83c9
4 changed files with 113 additions and 8 deletions

View file

@ -93,6 +93,12 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
bool else_pop = false;
bool need_try = false;
bool variable_annotations = false;
std::vector<PycExceptionTableEntry> exception_entries;
size_t next_exception_entry = 0;
if (mod->verCompare(3, 11) >= 0) {
exception_entries = code->exceptionTableEntries();
}
while (!source.atEof()) {
#if defined(BLOCK_DEBUG) || defined(STACK_DEBUG)
@ -108,6 +114,84 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
fprintf(stderr, "\n");
#endif
while (next_exception_entry < exception_entries.size()
&& exception_entries[next_exception_entry].start_offset < pos) {
next_exception_entry++;
}
if (next_exception_entry < exception_entries.size()) {
const auto& entry = exception_entries[next_exception_entry];
if (entry.start_offset == pos
&& entry.stack_depth == 0
&& !entry.push_lasti) {
if (curblock->blktype() == ASTBlock::BLK_CONTAINER) {
curblock.cast<ASTContainerBlock>()->setExcept(entry.target);
} else {
PycRef<ASTBlock> next = new ASTContainerBlock(0, entry.target);
blocks.push(next.cast<ASTBlock>());
curblock = blocks.top();
}
stack_hist.push(stack);
PycRef<ASTBlock> tryblock = new ASTBlock(ASTBlock::BLK_TRY, entry.target, true);
blocks.push(tryblock.cast<ASTBlock>());
curblock = blocks.top();
next_exception_entry++;
}
}
if (curblock->blktype() == ASTBlock::BLK_TRY
&& curblock->end() == pos
&& blocks.size() > 1) {
PycRef<ASTBlock> prev = curblock;
blocks.pop();
curblock = blocks.top();
if (curblock->blktype() == ASTBlock::BLK_CONTAINER
&& curblock.cast<ASTContainerBlock>()->hasExcept()) {
if (!stack_hist.empty()) {
stack = stack_hist.top();
stack_hist.pop();
}
curblock->append(prev.cast<ASTNode>());
stack_hist.push(stack);
PycRef<ASTBlock> except = new ASTCondBlock(ASTBlock::BLK_EXCEPT, 0, NULL, false);
except->init();
blocks.push(except);
curblock = blocks.top();
} else {
blocks.push(prev);
curblock = prev;
}
}
if (curblock->blktype() == ASTBlock::BLK_EXCEPT
&& curblock->end() == pos
&& blocks.size() > 1) {
PycRef<ASTBlock> prev = curblock;
blocks.pop();
curblock = blocks.top();
if (!stack_hist.empty()) {
stack = stack_hist.top();
stack_hist.pop();
}
if (prev->size() != 0) {
curblock->append(prev.cast<ASTNode>());
}
if (curblock->blktype() == ASTBlock::BLK_CONTAINER
&& !curblock.cast<ASTContainerBlock>()->hasFinally()) {
PycRef<ASTBlock> cont = curblock;
blocks.pop();
curblock = blocks.top();
curblock->append(cont.cast<ASTNode>());
}
}
curpos = pos;
bc_next(source, mod, opcode, operand, pos);
@ -1093,15 +1177,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
if (cond.type() == ASTNode::NODE_COMPARE
&& cond.cast<ASTCompare>()->op() == ASTCompare::CMP_EXCEPTION) {
int except_end = offs;
if (curblock->blktype() == ASTBlock::BLK_EXCEPT
&& curblock.cast<ASTCondBlock>()->cond() == NULL) {
except_end = curblock->end();
blocks.pop();
curblock = blocks.top();
stack_hist.pop();
}
ifblk = new ASTCondBlock(ASTBlock::BLK_EXCEPT, offs, cond.cast<ASTCompare>()->right(), false);
ifblk = new ASTCondBlock(ASTBlock::BLK_EXCEPT, except_end, cond.cast<ASTCompare>()->right(), false);
} else if (curblock->blktype() == ASTBlock::BLK_ELSE
&& curblock->size() == 0) {
/* Collapse into elif statement */
@ -1370,8 +1456,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
} else if (prev->blktype() == ASTBlock::BLK_TRY
&& prev->end() < pos+offs) {
/* Need to add an except/finally block */
stack = stack_hist.top();
stack.pop();
if (!stack_hist.empty()) {
stack = stack_hist.top();
stack_hist.pop();
}
if (blocks.top()->blktype() == ASTBlock::BLK_CONTAINER) {
PycRef<ASTContainerBlock> cont = blocks.top().cast<ASTContainerBlock>();
@ -1845,11 +1933,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
break;
case Pyc::RERAISE:
case Pyc::RERAISE_A:
{
/* Re-raise current exception; treat like 'raise' without args. */
ASTRaise::param_t paramList;
curblock->append(new ASTRaise(paramList));
}
/* Python 3.11 cleanup opcode. */
break;
case Pyc::RETURN_VALUE:
case Pyc::INSTRUMENTED_RETURN_VALUE_A:

Binary file not shown.

View file

@ -0,0 +1,7 @@
def handle_specific(flag):
try:
if flag:
raise ValueError('boom')
except ValueError:
return 'value'
return 'ok'

View file

@ -0,0 +1,14 @@
def handle_specific ( flag ) : <EOL>
<INDENT>
try : <EOL>
<INDENT>
if flag : <EOL>
<INDENT>
raise ValueError ( 'boom' ) <EOL>
<OUTDENT>
<OUTDENT>
except ValueError : <EOL>
<INDENT>
return 'value' <EOL>
<OUTDENT>
return 'ok' <EOL>