Merge pull request #4037 from youknowone/dis-fmt

enhance dis output to print line numbers
This commit is contained in:
Jeong YunWon
2022-08-12 03:43:37 +09:00
committed by GitHub
8 changed files with 198 additions and 142 deletions

View File

@@ -2633,8 +2633,6 @@ class PEP626Tests(unittest.TestCase):
f.__code__ = f.__code__.replace(co_linetable=b'\x04\x80\xff\x80')
self.lineno_after_raise(f, None)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_lineno_after_raise_in_with_exit(self):
class ExitFails:
def __enter__(self):

View File

@@ -695,17 +695,39 @@ impl<C: Constant> CodeObject<C> {
level: usize,
) -> fmt::Result {
let label_targets = self.label_targets();
let line_digits = (3).max(self.locations.last().unwrap().row.to_string().len());
let offset_digits = (4).max(self.instructions.len().to_string().len());
let mut last_line = u32::MAX;
for (offset, instruction) in self.instructions.iter().enumerate() {
// optional line number
let line = self.locations[offset].row;
if line != last_line {
if last_line != u32::MAX {
writeln!(f)?;
}
last_line = line;
write!(f, "{line:line_digits$}")?;
} else {
for _ in 0..line_digits {
write!(f, " ")?;
}
}
write!(f, " ")?;
// level indent
for _ in 0..level {
write!(f, " ")?;
}
// arrow and offset
let arrow = if label_targets.contains(&Label(offset as u32)) {
">>"
} else {
" "
};
for _ in 0..level {
write!(f, " ")?;
}
write!(f, "{} {:5} ", arrow, offset)?;
write!(f, "{arrow} {offset:offset_digits$} ")?;
// instruction
instruction.fmt_dis(
f,
&self.constants,

View File

@@ -1393,54 +1393,69 @@ impl Compiler {
body: &[ast::Stmt],
is_async: bool,
) -> CompileResult<()> {
let end_blocks = items
.iter()
.map(|item| {
let end_block = self.new_block();
self.compile_expression(&item.context_expr)?;
let with_location = self.current_source_location;
if is_async {
self.emit(Instruction::BeforeAsyncWith);
self.emit(Instruction::GetAwaitable);
self.emit_constant(ConstantData::None);
self.emit(Instruction::YieldFrom);
self.emit(Instruction::SetupAsyncWith { end: end_block });
} else {
self.emit(Instruction::SetupWith { end: end_block });
}
let (item, items) = if let Some(parts) = items.split_first() {
parts
} else {
return Err(self.error(CompileErrorType::EmptyWithItems));
};
match &item.optional_vars {
Some(var) => {
self.compile_store(var)?;
}
None => {
self.emit(Instruction::Pop);
}
}
Ok(end_block)
})
.collect::<CompileResult<Vec<_>>>()?;
self.compile_statements(body)?;
// sort of "stack up" the layers of with blocks:
// with a, b: body -> start_with(a) start_with(b) body() end_with(b) end_with(a)
for end_block in end_blocks.into_iter().rev() {
self.emit(Instruction::PopBlock);
self.emit(Instruction::EnterFinally);
self.switch_to_block(end_block);
self.emit(Instruction::WithCleanupStart);
let final_block = {
let final_block = self.new_block();
self.compile_expression(&item.context_expr)?;
self.set_source_location(with_location);
if is_async {
self.emit(Instruction::BeforeAsyncWith);
self.emit(Instruction::GetAwaitable);
self.emit_constant(ConstantData::None);
self.emit(Instruction::YieldFrom);
self.emit(Instruction::SetupAsyncWith { end: final_block });
} else {
self.emit(Instruction::SetupWith { end: final_block });
}
self.emit(Instruction::WithCleanupFinish);
match &item.optional_vars {
Some(var) => {
self.set_source_location(var.location);
self.compile_store(var)?;
}
None => {
self.emit(Instruction::Pop);
}
}
final_block
};
if items.is_empty() {
if body.is_empty() {
return Err(self.error(CompileErrorType::EmptyWithBody));
}
self.compile_statements(body)?;
} else {
self.set_source_location(with_location);
self.compile_with(items, body, is_async)?;
}
// sort of "stack up" the layers of with blocks:
// with a, b: body -> start_with(a) start_with(b) body() end_with(b) end_with(a)
self.set_source_location(with_location);
self.emit(Instruction::PopBlock);
self.emit(Instruction::EnterFinally);
self.switch_to_block(final_block);
self.emit(Instruction::WithCleanupStart);
if is_async {
self.emit(Instruction::GetAwaitable);
self.emit_constant(ConstantData::None);
self.emit(Instruction::YieldFrom);
}
self.emit(Instruction::WithCleanupFinish);
Ok(())
}

View File

@@ -35,6 +35,8 @@ pub enum CompileErrorType {
InvalidFutureFeature(String),
FunctionImportStar,
TooManyStarUnpack,
EmptyWithItems,
EmptyWithBody,
}
impl fmt::Display for CompileErrorType {
@@ -70,6 +72,12 @@ impl fmt::Display for CompileErrorType {
CompileErrorType::TooManyStarUnpack => {
write!(f, "too many expressions in star-unpacking assignment")
}
CompileErrorType::EmptyWithItems => {
write!(f, "empty items on With")
}
CompileErrorType::EmptyWithBody => {
write!(f, "empty body on With")
}
}
}
}

View File

@@ -2,12 +2,13 @@
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif True and False and False:\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfFalse (6)
2 LoadConst (False)
3 JumpIfFalse (6)
4 LoadConst (False)
5 JumpIfFalse (6)
>> 6 LoadConst (None)
7 ReturnValue
1 0 LoadConst (True)
1 JumpIfFalse (6)
2 LoadConst (False)
3 JumpIfFalse (6)
4 LoadConst (False)
5 JumpIfFalse (6)
2 >> 6 LoadConst (None)
7 ReturnValue

View File

@@ -2,14 +2,15 @@
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif (True and False) or (False and True):\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfFalse (4)
2 LoadConst (False)
3 JumpIfTrue (8)
>> 4 LoadConst (False)
5 JumpIfFalse (8)
6 LoadConst (True)
7 JumpIfFalse (8)
>> 8 LoadConst (None)
9 ReturnValue
1 0 LoadConst (True)
1 JumpIfFalse (4)
2 LoadConst (False)
3 JumpIfTrue (8)
>> 4 LoadConst (False)
5 JumpIfFalse (8)
6 LoadConst (True)
7 JumpIfFalse (8)
2 >> 8 LoadConst (None)
9 ReturnValue

View File

@@ -2,12 +2,13 @@
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif True or False or False:\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfTrue (6)
2 LoadConst (False)
3 JumpIfTrue (6)
4 LoadConst (False)
5 JumpIfFalse (6)
>> 6 LoadConst (None)
7 ReturnValue
1 0 LoadConst (True)
1 JumpIfTrue (6)
2 LoadConst (False)
3 JumpIfTrue (6)
4 LoadConst (False)
5 JumpIfFalse (6)
2 >> 6 LoadConst (None)
7 ReturnValue

View File

@@ -1,77 +1,87 @@
---
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with woohoo():\n raise stop_exc\n except Exception as ex:\n self.assertIs(ex, stop_exc)\n else:\n self.fail(f'{stop_exc} was suppressed')\n\")"
---
0 SetupLoop (69)
1 LoadNameAny (0, StopIteration)
2 LoadConst ("spam")
3 CallFunctionPositional (1)
4 LoadNameAny (1, StopAsyncIteration)
5 LoadConst ("ham")
6 CallFunctionPositional (1)
7 BuildTuple (2, false)
8 GetIter
>> 9 ForIter (68)
10 StoreLocal (2, stop_exc)
11 LoadNameAny (3, self)
12 LoadMethod (subTest)
13 LoadNameAny (5, type)
14 LoadNameAny (2, stop_exc)
15 CallFunctionPositional (1)
16 LoadConst (("type"))
17 CallMethodKeyword (1)
18 SetupWith (65)
19 Pop
20 SetupExcept (40)
21 LoadNameAny (6, woohoo)
22 CallFunctionPositional (0)
23 BeforeAsyncWith
24 GetAwaitable
25 LoadConst (None)
26 YieldFrom
27 SetupAsyncWith (33)
28 Pop
29 LoadNameAny (2, stop_exc)
30 Raise (Raise)
31 PopBlock
32 EnterFinally
>> 33 WithCleanupStart
34 GetAwaitable
35 LoadConst (None)
36 YieldFrom
37 WithCleanupFinish
38 PopBlock
39 Jump (54)
>> 40 Duplicate
41 LoadNameAny (7, Exception)
42 TestOperation (ExceptionMatch)
43 JumpIfFalse (53)
44 StoreLocal (8, ex)
45 LoadNameAny (3, self)
46 LoadMethod (assertIs)
47 LoadNameAny (8, ex)
48 LoadNameAny (2, stop_exc)
49 CallMethodPositional (2)
50 Pop
51 PopException
52 Jump (63)
>> 53 Raise (Reraise)
>> 54 LoadNameAny (3, self)
55 LoadMethod (fail)
56 LoadConst ("")
57 LoadNameAny (2, stop_exc)
58 FormatValue (None)
59 LoadConst (" was suppressed")
60 BuildString (2)
61 CallMethodPositional (1)
62 Pop
>> 63 PopBlock
64 EnterFinally
>> 65 WithCleanupStart
66 WithCleanupFinish
67 Jump (9)
>> 68 PopBlock
>> 69 LoadConst (None)
70 ReturnValue
1 0 SetupLoop (69)
1 LoadNameAny (0, StopIteration)
2 LoadConst ("spam")
3 CallFunctionPositional (1)
4 LoadNameAny (1, StopAsyncIteration)
5 LoadConst ("ham")
6 CallFunctionPositional (1)
7 BuildTuple (2, false)
8 GetIter
>> 9 ForIter (68)
10 StoreLocal (2, stop_exc)
2 11 LoadNameAny (3, self)
12 LoadMethod (subTest)
13 LoadNameAny (5, type)
14 LoadNameAny (2, stop_exc)
15 CallFunctionPositional (1)
16 LoadConst (("type"))
17 CallMethodKeyword (1)
18 SetupWith (65)
19 Pop
3 20 SetupExcept (40)
4 21 LoadNameAny (6, woohoo)
22 CallFunctionPositional (0)
23 BeforeAsyncWith
24 GetAwaitable
25 LoadConst (None)
26 YieldFrom
27 SetupAsyncWith (33)
28 Pop
5 29 LoadNameAny (2, stop_exc)
30 Raise (Raise)
4 31 PopBlock
32 EnterFinally
>> 33 WithCleanupStart
34 GetAwaitable
35 LoadConst (None)
36 YieldFrom
37 WithCleanupFinish
38 PopBlock
39 Jump (54)
>> 40 Duplicate
6 41 LoadNameAny (7, Exception)
42 TestOperation (ExceptionMatch)
43 JumpIfFalse (53)
44 StoreLocal (8, ex)
7 45 LoadNameAny (3, self)
46 LoadMethod (assertIs)
47 LoadNameAny (8, ex)
48 LoadNameAny (2, stop_exc)
49 CallMethodPositional (2)
50 Pop
51 PopException
52 Jump (63)
>> 53 Raise (Reraise)
9 >> 54 LoadNameAny (3, self)
55 LoadMethod (fail)
56 LoadConst ("")
1 57 LoadNameAny (2, stop_exc)
58 FormatValue (None)
9 59 LoadConst (" was suppressed")
60 BuildString (2)
61 CallMethodPositional (1)
62 Pop
2 >> 63 PopBlock
64 EnterFinally
>> 65 WithCleanupStart
66 WithCleanupFinish
67 Jump (9)
>> 68 PopBlock
>> 69 LoadConst (None)
70 ReturnValue