mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Remove unused rust impl for formatting dis output (#7660)
* Remove unused rust impl for formatting dis output
* remove `examples/dis.rs`
* Added tests
* Update lock
* Try to set snapshot dir
* Remove verbose flag
* Regenerate snapshots after #7711
* Revert "Bump insta from 1.46.3 to 1.47.2 (#7706)"
This reverts commit e6d9ea6bfe.
* Debug info
* Show diff as well
* Show debug faster
* CI: true env
* Recert CI
* Add `CI: true` in ci emv
* Reapply "Bump insta from 1.46.3 to 1.47.2 (#7706)"
This reverts commit 693ca8cbe4d7885a81162a9be31e8bb567db885a.
* simplify macro
* trim on function side
* Force insta workspace root
* fix merge
This commit is contained in:
5
.github/workflows/ci.yaml
vendored
5
.github/workflows/ci.yaml
vendored
@@ -34,6 +34,7 @@ env:
|
||||
CARGO_PROFILE_RELEASE_DEBUG: 0
|
||||
CARGO_TERM_COLOR: always
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true # TODO: Remove on 2026/06/02
|
||||
CI: true
|
||||
|
||||
jobs:
|
||||
determine_changes:
|
||||
@@ -111,7 +112,9 @@ jobs:
|
||||
uses: ./.github/actions/install-macos-deps
|
||||
|
||||
- name: run rust tests
|
||||
run: cargo test --workspace ${{ env.WORKSPACE_EXCLUDES }} --verbose --features threading ${{ env.CARGO_ARGS }}
|
||||
run: cargo test --workspace ${{ env.WORKSPACE_EXCLUDES }} --features threading ${{ env.CARGO_ARGS }}
|
||||
env:
|
||||
INSTA_WORKSPACE_ROOT: ${{ github.workspace }}
|
||||
|
||||
- run: cargo doc --locked
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -3158,7 +3158,6 @@ dependencies = [
|
||||
"ahash",
|
||||
"bitflags 2.11.0",
|
||||
"indexmap",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"log",
|
||||
"malachite-bigint",
|
||||
@@ -3427,6 +3426,7 @@ dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
"indexmap",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"libc",
|
||||
"liblzma",
|
||||
@@ -3464,6 +3464,7 @@ dependencies = [
|
||||
"rustpython-common",
|
||||
"rustpython-derive",
|
||||
"rustpython-host_env",
|
||||
"rustpython-pylib",
|
||||
"rustpython-ruff_python_ast",
|
||||
"rustpython-ruff_python_parser",
|
||||
"rustpython-ruff_source_file",
|
||||
|
||||
@@ -33,7 +33,6 @@ unicode_names2 = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_python_parser = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -12275,26 +12275,6 @@ def f(sys, os, file):
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! assert_dis_snapshot {
|
||||
($value:expr) => {
|
||||
insta::assert_snapshot!(
|
||||
insta::internals::AutoName,
|
||||
$value.display_expand_code_objects().to_string(),
|
||||
stringify!($value)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_ors() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
if True or False or False:
|
||||
pass
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trace_assert_true_try_pair() {
|
||||
let trace = compile_exec_late_cfg_trace(
|
||||
@@ -12529,44 +12509,6 @@ def f(self):
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_ands() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
if True and False and False:
|
||||
pass
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_mixed() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
if (True and False) or (False and True):
|
||||
pass
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_bool_op() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
x = Test() and False or False
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_bool_not_op() {
|
||||
assert_dis_snapshot!(compile_exec_optimized(
|
||||
"\
|
||||
x = not True
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plain_constant_bool_op_folds_to_selected_operand() {
|
||||
let code = compile_exec(
|
||||
@@ -12840,24 +12782,6 @@ def f(self, mod):
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_double_async_with() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
async def test():
|
||||
for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
|
||||
with self.subTest(type=type(stop_exc)):
|
||||
try:
|
||||
async with egg():
|
||||
raise stop_exc
|
||||
except Exception as ex:
|
||||
self.assertIs(ex, stop_exc)
|
||||
else:
|
||||
self.fail(f'{stop_exc} was suppressed')
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scope_exit_instructions_keep_line_numbers() {
|
||||
let code = compile_exec(
|
||||
@@ -14006,20 +13930,6 @@ def f(expected_ns, namespace):
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bare_function_annotations_check_attribute_and_subscript_expressions() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
def f(one: int):
|
||||
int.new_attr: int
|
||||
[list][0].new_attr: [int, str]
|
||||
my_lst = [1]
|
||||
my_lst[one]: int
|
||||
return my_lst
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_simple_bare_name_annotation_does_not_create_local_binding() {
|
||||
let code = compile_exec(
|
||||
@@ -14052,16 +13962,6 @@ def f2bad():
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_constant_true_if_pass_keeps_line_anchor_nop() {
|
||||
assert_dis_snapshot!(compile_exec(
|
||||
"\
|
||||
if 1:
|
||||
pass
|
||||
"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_constant_binop_folds_after_unary_folding() {
|
||||
let code = compile_exec(
|
||||
|
||||
@@ -9378,8 +9378,7 @@ impl CodeInfo {
|
||||
} else {
|
||||
OpArg::new(ins.target.0)
|
||||
};
|
||||
let instr_display = instr.display(display_arg, self);
|
||||
eprint!("{instr_display}: {depth} {effect:+} => ");
|
||||
eprint!("{display_arg:?}: {depth} {effect:+} => ");
|
||||
}
|
||||
let new_depth = depth.checked_add_signed(effect).ok_or({
|
||||
if effect < 0 {
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 12138
|
||||
expression: "compile_exec(\"\\\ndef f(one: int):\n int.new_attr: int\n [list][0].new_attr: [int, str]\n my_lst = [1]\n my_lst[one]: int\n return my_lst\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_CONST (<code object __annotate__ at ??? file "source_path", line 1>): 1 0 RESUME (0)
|
||||
1 LOAD_FAST_BORROW (0, format)
|
||||
2 LOAD_SMALL_INT (2)
|
||||
>> 3 COMPARE_OP (>)
|
||||
4 CACHE
|
||||
5 POP_JUMP_IF_FALSE (3)
|
||||
6 CACHE
|
||||
7 NOT_TAKEN
|
||||
8 LOAD_COMMON_CONSTANT (NotImplementedError)
|
||||
9 RAISE_VARARGS (Raise)
|
||||
10 LOAD_CONST ("one")
|
||||
11 LOAD_GLOBAL (0, int)
|
||||
12 CACHE
|
||||
13 CACHE
|
||||
14 CACHE
|
||||
15 CACHE
|
||||
16 BUILD_MAP (1)
|
||||
17 RETURN_VALUE
|
||||
|
||||
2 MAKE_FUNCTION
|
||||
3 LOAD_CONST (<code object f at ??? file "source_path", line 1>): 1 0 RESUME (0)
|
||||
|
||||
2 1 LOAD_GLOBAL (0, int)
|
||||
2 CACHE
|
||||
3 CACHE
|
||||
4 CACHE
|
||||
5 CACHE
|
||||
6 POP_TOP
|
||||
|
||||
3 7 LOAD_GLOBAL (2, list)
|
||||
8 CACHE
|
||||
9 CACHE
|
||||
10 CACHE
|
||||
11 CACHE
|
||||
12 BUILD_LIST (1)
|
||||
13 LOAD_SMALL_INT (0)
|
||||
14 BINARY_OP ([])
|
||||
15 CACHE
|
||||
16 CACHE
|
||||
17 CACHE
|
||||
18 CACHE
|
||||
19 CACHE
|
||||
20 POP_TOP
|
||||
|
||||
4 21 LOAD_SMALL_INT (1)
|
||||
22 BUILD_LIST (1)
|
||||
23 STORE_FAST (1, my_lst)
|
||||
|
||||
5 24 LOAD_FAST_BORROW (1, my_lst)
|
||||
25 POP_TOP
|
||||
26 LOAD_FAST_BORROW (0, one)
|
||||
27 POP_TOP
|
||||
|
||||
6 28 LOAD_FAST_BORROW (1, my_lst)
|
||||
29 RETURN_VALUE
|
||||
|
||||
4 MAKE_FUNCTION
|
||||
5 SET_FUNCTION_ATTRIBUTE(Annotate)
|
||||
6 STORE_NAME (0, f)
|
||||
7 LOAD_CONST (None)
|
||||
8 RETURN_VALUE
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
expression: "compile_exec_optimized(\"\\\nx = not True\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_CONST (False)
|
||||
2 STORE_NAME (0, x)
|
||||
3 LOAD_CONST (None)
|
||||
4 RETURN_VALUE
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 12222
|
||||
expression: "compile_exec(\"\\\nif 1:\n pass\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 NOP
|
||||
|
||||
2 2 LOAD_CONST (None)
|
||||
3 RETURN_VALUE
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 11413
|
||||
expression: "compile_exec(\"\\\nif True and False and False:\n pass\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_CONST (None)
|
||||
2 RETURN_VALUE
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 11423
|
||||
expression: "compile_exec(\"\\\nif (True and False) or (False and True):\n pass\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_CONST (None)
|
||||
2 RETURN_VALUE
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 11039
|
||||
expression: "compile_exec(\"\\\nif True or False or False:\n pass\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 NOP
|
||||
|
||||
2 2 LOAD_CONST (None)
|
||||
3 RETURN_VALUE
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 11769
|
||||
expression: "compile_exec(\"\\\nx = Test() and False or False\n\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_NAME (0, Test)
|
||||
2 PUSH_NULL
|
||||
>> 3 CALL (0)
|
||||
4 CACHE
|
||||
5 CACHE
|
||||
6 CACHE
|
||||
7 COPY (1)
|
||||
8 TO_BOOL
|
||||
9 CACHE
|
||||
10 CACHE
|
||||
>> 11 CACHE
|
||||
12 POP_JUMP_IF_FALSE (11)
|
||||
13 CACHE
|
||||
14 NOT_TAKEN
|
||||
15 POP_TOP
|
||||
16 LOAD_CONST (False)
|
||||
17 COPY (1)
|
||||
18 TO_BOOL
|
||||
19 CACHE
|
||||
20 CACHE
|
||||
21 CACHE
|
||||
22 POP_JUMP_IF_TRUE (3)
|
||||
23 CACHE
|
||||
24 NOT_TAKEN
|
||||
25 POP_TOP
|
||||
26 LOAD_CONST (False)
|
||||
27 STORE_NAME (1, x)
|
||||
28 LOAD_CONST (None)
|
||||
29 RETURN_VALUE
|
||||
@@ -1,258 +0,0 @@
|
||||
---
|
||||
source: crates/codegen/src/compile.rs
|
||||
assertion_line: 11847
|
||||
expression: "compile_exec(\"\\\nasync def test():\n for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with egg():\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\")"
|
||||
---
|
||||
1 0 RESUME (0)
|
||||
1 LOAD_CONST (<code object test at ??? file "source_path", line 1>): 1 0 RETURN_GENERATOR
|
||||
1 POP_TOP
|
||||
>> 2 RESUME (0)
|
||||
|
||||
2 >> 3 LOAD_GLOBAL (1, NULL + StopIteration)
|
||||
>> 4 CACHE
|
||||
>> 5 CACHE
|
||||
6 CACHE
|
||||
7 CACHE
|
||||
>> 8 LOAD_CONST ("spam")
|
||||
9 CALL (1)
|
||||
>> 10 CACHE
|
||||
11 CACHE
|
||||
12 CACHE
|
||||
13 LOAD_GLOBAL (3, NULL + StopAsyncIteration)
|
||||
14 CACHE
|
||||
15 CACHE
|
||||
16 CACHE
|
||||
17 CACHE
|
||||
18 LOAD_CONST ("ham")
|
||||
19 CALL (1)
|
||||
20 CACHE
|
||||
21 CACHE
|
||||
22 CACHE
|
||||
23 BUILD_TUPLE (2)
|
||||
24 GET_ITER
|
||||
25 FOR_ITER (71)
|
||||
26 CACHE
|
||||
27 STORE_FAST (0, stop_exc)
|
||||
|
||||
3 28 LOAD_GLOBAL (4, self)
|
||||
29 CACHE
|
||||
30 CACHE
|
||||
31 CACHE
|
||||
>> 32 CACHE
|
||||
33 LOAD_ATTR (7, subTest, method=true)
|
||||
34 CACHE
|
||||
35 CACHE
|
||||
36 CACHE
|
||||
37 CACHE
|
||||
38 CACHE
|
||||
39 CACHE
|
||||
40 CACHE
|
||||
41 CACHE
|
||||
42 CACHE
|
||||
43 LOAD_GLOBAL (9, NULL + type)
|
||||
44 CACHE
|
||||
>> 45 CACHE
|
||||
46 CACHE
|
||||
47 CACHE
|
||||
48 LOAD_FAST_BORROW (0, stop_exc)
|
||||
49 CALL (1)
|
||||
50 CACHE
|
||||
51 CACHE
|
||||
52 CACHE
|
||||
53 LOAD_CONST (("type"))
|
||||
54 CALL_KW (1)
|
||||
55 CACHE
|
||||
56 CACHE
|
||||
57 CACHE
|
||||
58 COPY (1)
|
||||
59 LOAD_SPECIAL (__exit__)
|
||||
60 SWAP (2)
|
||||
61 SWAP (3)
|
||||
62 LOAD_SPECIAL (__enter__)
|
||||
63 CALL (0)
|
||||
64 CACHE
|
||||
65 CACHE
|
||||
66 CACHE
|
||||
67 POP_TOP
|
||||
|
||||
4 68 NOP
|
||||
|
||||
5 69 LOAD_GLOBAL (11, NULL + egg)
|
||||
70 CACHE
|
||||
>> 71 CACHE
|
||||
72 CACHE
|
||||
73 CACHE
|
||||
74 CALL (0)
|
||||
75 CACHE
|
||||
76 CACHE
|
||||
77 CACHE
|
||||
78 COPY (1)
|
||||
79 LOAD_SPECIAL (__aexit__)
|
||||
80 SWAP (2)
|
||||
81 SWAP (3)
|
||||
82 LOAD_SPECIAL (__aenter__)
|
||||
83 CALL (0)
|
||||
84 CACHE
|
||||
85 CACHE
|
||||
86 CACHE
|
||||
87 GET_AWAITABLE (1)
|
||||
88 LOAD_CONST (None)
|
||||
89 SEND (3)
|
||||
90 CACHE
|
||||
91 YIELD_VALUE (1)
|
||||
92 RESUME (3)
|
||||
93 JUMP_BACKWARD_NO_INTERRUPT(5)
|
||||
94 END_SEND
|
||||
95 POP_TOP
|
||||
|
||||
6 96 LOAD_FAST_BORROW (0, stop_exc)
|
||||
97 RAISE_VARARGS (Raise)
|
||||
|
||||
2 98 END_FOR
|
||||
99 POP_ITER
|
||||
100 LOAD_CONST (None)
|
||||
101 RETURN_VALUE
|
||||
|
||||
5 102 CLEANUP_THROW
|
||||
103 JUMP_BACKWARD_NO_INTERRUPT(10)
|
||||
104 PUSH_EXC_INFO
|
||||
105 WITH_EXCEPT_START
|
||||
106 GET_AWAITABLE (2)
|
||||
107 LOAD_CONST (None)
|
||||
108 SEND (4)
|
||||
109 CACHE
|
||||
110 YIELD_VALUE (1)
|
||||
111 RESUME (3)
|
||||
112 JUMP_BACKWARD_NO_INTERRUPT(5)
|
||||
113 CLEANUP_THROW
|
||||
114 END_SEND
|
||||
115 TO_BOOL
|
||||
116 CACHE
|
||||
117 CACHE
|
||||
118 CACHE
|
||||
119 POP_JUMP_IF_TRUE (2)
|
||||
120 CACHE
|
||||
121 NOT_TAKEN
|
||||
122 RERAISE (2)
|
||||
123 POP_TOP
|
||||
124 POP_EXCEPT
|
||||
125 POP_TOP
|
||||
126 POP_TOP
|
||||
127 POP_TOP
|
||||
128 JUMP_FORWARD (3)
|
||||
129 COPY (3)
|
||||
130 POP_EXCEPT
|
||||
131 RERAISE (1)
|
||||
132 NOP
|
||||
|
||||
10 133 LOAD_GLOBAL (4, self)
|
||||
134 CACHE
|
||||
135 CACHE
|
||||
136 CACHE
|
||||
137 CACHE
|
||||
138 LOAD_ATTR (13, fail, method=true)
|
||||
139 CACHE
|
||||
140 CACHE
|
||||
141 CACHE
|
||||
142 CACHE
|
||||
143 CACHE
|
||||
144 CACHE
|
||||
145 CACHE
|
||||
146 CACHE
|
||||
147 CACHE
|
||||
148 LOAD_FAST (0, stop_exc)
|
||||
149 FORMAT_SIMPLE
|
||||
150 LOAD_CONST (" was suppressed")
|
||||
151 BUILD_STRING (2)
|
||||
152 CALL (1)
|
||||
153 CACHE
|
||||
154 CACHE
|
||||
155 CACHE
|
||||
156 POP_TOP
|
||||
157 JUMP_FORWARD (45)
|
||||
158 PUSH_EXC_INFO
|
||||
|
||||
7 159 LOAD_GLOBAL (14, Exception)
|
||||
160 CACHE
|
||||
161 CACHE
|
||||
162 CACHE
|
||||
163 CACHE
|
||||
164 CHECK_EXC_MATCH
|
||||
165 POP_JUMP_IF_FALSE (32)
|
||||
166 CACHE
|
||||
167 NOT_TAKEN
|
||||
168 STORE_FAST (1, ex)
|
||||
|
||||
8 169 LOAD_GLOBAL (4, self)
|
||||
170 CACHE
|
||||
171 CACHE
|
||||
172 CACHE
|
||||
173 CACHE
|
||||
174 LOAD_ATTR (17, assertIs, method=true)
|
||||
175 CACHE
|
||||
176 CACHE
|
||||
177 CACHE
|
||||
178 CACHE
|
||||
179 CACHE
|
||||
180 CACHE
|
||||
181 CACHE
|
||||
182 CACHE
|
||||
183 CACHE
|
||||
184 LOAD_FAST_LOAD_FAST (ex, stop_exc)
|
||||
185 CALL (2)
|
||||
186 CACHE
|
||||
187 CACHE
|
||||
>> 188 CACHE
|
||||
189 POP_TOP
|
||||
190 POP_EXCEPT
|
||||
191 LOAD_CONST (None)
|
||||
192 STORE_FAST (1, ex)
|
||||
193 DELETE_FAST (1, ex)
|
||||
194 JUMP_FORWARD (8)
|
||||
195 LOAD_CONST (None)
|
||||
196 STORE_FAST (1, ex)
|
||||
197 DELETE_FAST (1, ex)
|
||||
198 RERAISE (1)
|
||||
|
||||
7 199 RERAISE (0)
|
||||
200 COPY (3)
|
||||
201 POP_EXCEPT
|
||||
202 RERAISE (1)
|
||||
|
||||
3 203 LOAD_CONST (None)
|
||||
204 LOAD_CONST (None)
|
||||
>> 205 LOAD_CONST (None)
|
||||
206 CALL (3)
|
||||
207 CACHE
|
||||
208 CACHE
|
||||
209 CACHE
|
||||
210 POP_TOP
|
||||
211 JUMP_BACKWARD (188)
|
||||
212 CACHE
|
||||
213 PUSH_EXC_INFO
|
||||
214 WITH_EXCEPT_START
|
||||
215 TO_BOOL
|
||||
216 CACHE
|
||||
217 CACHE
|
||||
218 CACHE
|
||||
219 POP_JUMP_IF_TRUE (2)
|
||||
220 CACHE
|
||||
221 NOT_TAKEN
|
||||
222 RERAISE (2)
|
||||
223 POP_TOP
|
||||
224 POP_EXCEPT
|
||||
225 POP_TOP
|
||||
226 POP_TOP
|
||||
227 POP_TOP
|
||||
228 JUMP_BACKWARD (205)
|
||||
229 CACHE
|
||||
230 COPY (3)
|
||||
231 POP_EXCEPT
|
||||
232 RERAISE (1)
|
||||
233 CALL_INTRINSIC_1 (StopIterationError)
|
||||
234 RERAISE (1)
|
||||
|
||||
2 MAKE_FUNCTION
|
||||
3 STORE_NAME (0, test)
|
||||
4 LOAD_CONST (None)
|
||||
5 RETURN_VALUE
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
source: compiler/src/compile.rs
|
||||
expression: "compile_exec(\"\\\nif True and False and False:\n pass\n\")"
|
||||
---
|
||||
1 0 LoadConst (True)
|
||||
1 PopJumpIfFalse (6)
|
||||
2 LoadConst (False)
|
||||
3 PopJumpIfFalse (6)
|
||||
4 LoadConst (False)
|
||||
5 PopJumpIfFalse (6)
|
||||
|
||||
2 >> 6 LoadConst (None)
|
||||
7 ReturnValue
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
source: compiler/src/compile.rs
|
||||
expression: "compile_exec(\"\\\nif (True and False) or (False and True):\n pass\n\")"
|
||||
---
|
||||
1 0 LoadConst (True)
|
||||
1 PopJumpIfFalse (4)
|
||||
2 LoadConst (False)
|
||||
3 PopJumpIfTrue (8)
|
||||
>> 4 LoadConst (False)
|
||||
5 PopJumpIfFalse (8)
|
||||
6 LoadConst (True)
|
||||
7 PopJumpIfFalse (8)
|
||||
|
||||
2 >> 8 LoadConst (None)
|
||||
9 ReturnValue
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
source: compiler/src/compile.rs
|
||||
expression: "compile_exec(\"\\\nif True or False or False:\n pass\n\")"
|
||||
---
|
||||
1 0 LoadConst (True)
|
||||
1 PopJumpIfTrue (6)
|
||||
2 LoadConst (False)
|
||||
3 PopJumpIfTrue (6)
|
||||
4 LoadConst (False)
|
||||
5 PopJumpIfFalse (6)
|
||||
|
||||
2 >> 6 LoadConst (None)
|
||||
7 ReturnValue
|
||||
|
||||
@@ -1151,65 +1151,6 @@ impl<C: Constant> CodeObject<C> {
|
||||
label_targets
|
||||
}
|
||||
|
||||
fn display_inner(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
expand_code_objects: bool,
|
||||
level: usize,
|
||||
) -> fmt::Result {
|
||||
let label_targets = self.label_targets();
|
||||
let line_digits = (3).max(self.locations.last().unwrap().0.line.digits().get());
|
||||
let offset_digits = (4).max(1 + self.instructions.len().ilog10() as usize);
|
||||
let mut last_line = OneIndexed::MAX;
|
||||
let mut arg_state = OpArgState::default();
|
||||
for (offset, &instruction) in self.instructions.iter().enumerate() {
|
||||
let (instruction, arg) = arg_state.get(instruction);
|
||||
// optional line number
|
||||
let line = self.locations[offset].0.line;
|
||||
if line != last_line {
|
||||
if last_line != OneIndexed::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::from_u32(offset as u32)) {
|
||||
">>"
|
||||
} else {
|
||||
" "
|
||||
};
|
||||
write!(f, "{arrow} {offset:offset_digits$} ")?;
|
||||
|
||||
// instruction
|
||||
instruction.fmt_dis(arg, f, self, expand_code_objects, 21, level)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Recursively display this CodeObject
|
||||
pub fn display_expand_code_objects(&self) -> impl fmt::Display + '_ {
|
||||
struct Display<'a, C: Constant>(&'a CodeObject<C>);
|
||||
impl<C: Constant> fmt::Display for Display<'_, C> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.display_inner(f, true, 1)
|
||||
}
|
||||
}
|
||||
Display(self)
|
||||
}
|
||||
|
||||
/// Map this CodeObject to one that holds a Bag::Constant
|
||||
pub fn map_bag<Bag: ConstantBag>(self, bag: Bag) -> CodeObject<Bag::Constant> {
|
||||
let map_names = |names: Box<[C::Name]>| {
|
||||
@@ -1279,19 +1220,6 @@ impl<C: Constant> CodeObject<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Constant> fmt::Display for CodeObject<C> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.display_inner(f, false, 1)?;
|
||||
for constant in &*self.constants {
|
||||
if let BorrowedConstant::Code { code } = constant.borrow_constant() {
|
||||
writeln!(f, "\nDisassembly of {code:?}")?;
|
||||
code.fmt(f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InstrDisplayContext {
|
||||
type Constant: Constant;
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
use core::{fmt, marker::PhantomData};
|
||||
|
||||
use crate::{
|
||||
bytecode::{
|
||||
BorrowedConstant, Constant, InstrDisplayContext,
|
||||
oparg::{
|
||||
self, BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator,
|
||||
ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr,
|
||||
LoadSuperAttr, MakeFunctionFlag, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
|
||||
SpecialMethod, UnpackExArgs,
|
||||
},
|
||||
bytecode::oparg::{
|
||||
self, BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator,
|
||||
ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr,
|
||||
LoadSuperAttr, MakeFunctionFlag, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
|
||||
SpecialMethod, UnpackExArgs,
|
||||
},
|
||||
marshal::MarshalError,
|
||||
};
|
||||
@@ -1025,262 +1022,6 @@ impl InstructionMetadata for Instruction {
|
||||
// In CPython 3.14 the metadata-based stack_effect is the same for both
|
||||
// fallthrough and branch paths for all real instructions.
|
||||
// Only pseudo-instructions (SETUP_*) differ — see PseudoInstruction.
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn fmt_dis(
|
||||
&self,
|
||||
arg: OpArg,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
ctx: &impl InstrDisplayContext,
|
||||
expand_code_objects: bool,
|
||||
pad: usize,
|
||||
level: usize,
|
||||
) -> fmt::Result {
|
||||
let opcode = self.opcode();
|
||||
|
||||
macro_rules! w {
|
||||
// No oparg. Show only opcode name.
|
||||
() => {
|
||||
write!(f, "{}", opcode)
|
||||
};
|
||||
|
||||
// Oparg needs to be passed into a function.
|
||||
($map:ident = $arg_marker:expr) => {{
|
||||
let arg = $arg_marker.get(arg);
|
||||
write!(f, "{:pad$}({}, {})", opcode, arg, $map(arg))
|
||||
}};
|
||||
|
||||
// Oparg to be shown via `fmt::Display`
|
||||
($arg_marker:expr) => {
|
||||
write!(f, "{:pad$}({})", opcode, $arg_marker.get(arg))
|
||||
};
|
||||
|
||||
// Oparg to be shown via `fmt::Debug`
|
||||
(?$arg_marker:expr) => {
|
||||
write!(f, "{:pad$}({:?})", opcode, $arg_marker.get(arg))
|
||||
};
|
||||
}
|
||||
|
||||
let varname = |var_num: oparg::VarNum| ctx.get_varname(var_num);
|
||||
let name = |i: u32| ctx.get_name(i as usize);
|
||||
let cell_name = |i: oparg::VarNum| ctx.get_localsplus_name(i);
|
||||
|
||||
match self {
|
||||
Self::BinarySlice => w!(),
|
||||
Self::BinaryOp { op } => w!(op),
|
||||
Self::BinaryOpInplaceAddUnicode => w!(),
|
||||
Self::BuildList { count } => w!(count),
|
||||
Self::BuildMap { count } => w!(count),
|
||||
Self::BuildSet { count } => w!(count),
|
||||
Self::BuildSlice { argc } => w!(?argc),
|
||||
Self::BuildString { count } => w!(count),
|
||||
Self::BuildTuple { count } => w!(count),
|
||||
Self::Call { argc } => w!(argc),
|
||||
Self::CallFunctionEx => w!(),
|
||||
Self::CallKw { argc } => w!(argc),
|
||||
Self::CallIntrinsic1 { func } => w!(?func),
|
||||
Self::CallIntrinsic2 { func } => w!(?func),
|
||||
Self::Cache => w!(),
|
||||
Self::CheckEgMatch => w!(),
|
||||
Self::CheckExcMatch => w!(),
|
||||
Self::CleanupThrow => w!(),
|
||||
Self::CompareOp { opname } => {
|
||||
let op = opname.get(arg);
|
||||
if u32::from(arg) & oparg::COMPARE_OP_BOOL_MASK != 0 {
|
||||
write!(f, "{:pad$}(bool({}))", opcode, op)
|
||||
} else {
|
||||
write!(f, "{:pad$}({})", opcode, op)
|
||||
}
|
||||
}
|
||||
Self::ContainsOp { invert } => w!(invert),
|
||||
Self::ConvertValue { oparg } => {
|
||||
let oparg = oparg.get(arg);
|
||||
write!(f, "{:pad$} {} ({})", opcode, oparg.as_u8(), oparg)
|
||||
}
|
||||
Self::Copy { i } => w!(i),
|
||||
Self::CopyFreeVars { n } => w!(n),
|
||||
Self::DeleteAttr { namei } => w!(name = namei),
|
||||
Self::DeleteDeref { i } => w!(cell_name = i),
|
||||
Self::DeleteFast { var_num } => w!(varname = var_num),
|
||||
Self::DeleteGlobal { namei } => w!(name = namei),
|
||||
Self::DeleteName { namei } => w!(name = namei),
|
||||
Self::DeleteSubscr => w!(),
|
||||
Self::DictMerge { i } => w!(i),
|
||||
Self::DictUpdate { i } => w!(i),
|
||||
Self::EndAsyncFor => w!(),
|
||||
Self::EndSend => w!(),
|
||||
Self::ExtendedArg => w!(Arg::<u32>::marker()),
|
||||
Self::ExitInitCheck => w!(),
|
||||
Self::ForIter { delta } => w!(delta),
|
||||
Self::FormatSimple => w!(),
|
||||
Self::FormatWithSpec => w!(),
|
||||
Self::GetAIter => w!(),
|
||||
Self::GetANext => w!(),
|
||||
Self::GetAwaitable { r#where } => w!(r#where),
|
||||
Self::Reserved => w!(),
|
||||
Self::GetIter => w!(),
|
||||
Self::GetLen => w!(),
|
||||
Self::ImportFrom { namei } => w!(name = namei),
|
||||
Self::ImportName { namei } => w!(name = namei),
|
||||
Self::InterpreterExit => w!(),
|
||||
Self::IsOp { invert } => w!(invert),
|
||||
Self::JumpBackward { delta } => w!(delta),
|
||||
Self::JumpBackwardNoInterrupt { delta } => w!(delta),
|
||||
Self::JumpForward { delta } => w!(delta),
|
||||
Self::ListAppend { i } => w!(i),
|
||||
Self::ListExtend { i } => w!(i),
|
||||
Self::LoadAttr { namei } => {
|
||||
let oparg = namei.get(arg);
|
||||
let oparg_u32 = u32::from(oparg);
|
||||
let attr_name = name(oparg.name_idx());
|
||||
if oparg.is_method() {
|
||||
write!(f, "{opcode:pad$}({oparg_u32}, {attr_name}, method=true)",)
|
||||
} else {
|
||||
write!(f, "{opcode:pad$}({oparg_u32}, {attr_name})")
|
||||
}
|
||||
}
|
||||
Self::LoadBuildClass => w!(),
|
||||
Self::LoadCommonConstant { idx } => w!(?idx),
|
||||
Self::LoadFromDictOrDeref { i } => w!(cell_name = i),
|
||||
Self::LoadConst { consti } => {
|
||||
let value = ctx.get_constant(consti.get(arg));
|
||||
match value.borrow_constant() {
|
||||
BorrowedConstant::Code { code } if expand_code_objects => {
|
||||
write!(f, "{opcode:pad$}({code:?}):")?;
|
||||
code.display_inner(f, true, level + 1)?;
|
||||
Ok(())
|
||||
}
|
||||
c => {
|
||||
write!(f, "{opcode:pad$}(")?;
|
||||
c.fmt_display(f)?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::LoadSmallInt { i } => w!(i),
|
||||
Self::LoadDeref { i } => w!(cell_name = i),
|
||||
Self::LoadFast { var_num } => w!(varname = var_num),
|
||||
Self::LoadFastAndClear { var_num } => w!(varname = var_num),
|
||||
Self::LoadFastBorrow { var_num } => w!(varname = var_num),
|
||||
Self::LoadFastCheck { var_num } => w!(varname = var_num),
|
||||
Self::LoadFastLoadFast { var_nums } => {
|
||||
let oparg = var_nums.get(arg);
|
||||
let (idx1, idx2) = oparg.indexes();
|
||||
let name1 = varname(idx1);
|
||||
let name2 = varname(idx2);
|
||||
write!(f, "{:pad$}({}, {})", opcode, name1, name2)
|
||||
}
|
||||
Self::LoadFastBorrowLoadFastBorrow { var_nums } => {
|
||||
let oparg = var_nums.get(arg);
|
||||
let (idx1, idx2) = oparg.indexes();
|
||||
let name1 = varname(idx1);
|
||||
let name2 = varname(idx2);
|
||||
write!(f, "{:pad$}({}, {})", opcode, name1, name2)
|
||||
}
|
||||
Self::LoadFromDictOrGlobals { i } => w!(name = i),
|
||||
Self::LoadGlobal { namei } => {
|
||||
let oparg = namei.get(arg);
|
||||
let name_idx = oparg >> 1;
|
||||
if (oparg & 1) != 0 {
|
||||
write!(f, "{:pad$}({}, NULL + {})", opcode, oparg, name(name_idx))
|
||||
} else {
|
||||
write!(f, "{:pad$}({}, {})", opcode, oparg, name(name_idx))
|
||||
}
|
||||
}
|
||||
Self::LoadGlobalBuiltin => {
|
||||
let oparg = u32::from(arg);
|
||||
let name_idx = oparg >> 1;
|
||||
if (oparg & 1) != 0 {
|
||||
write!(f, "{:pad$}({}, NULL + {})", opcode, oparg, name(name_idx))
|
||||
} else {
|
||||
write!(f, "{:pad$}({}, {})", opcode, oparg, name(name_idx))
|
||||
}
|
||||
}
|
||||
Self::LoadGlobalModule => {
|
||||
let oparg = u32::from(arg);
|
||||
let name_idx = oparg >> 1;
|
||||
if (oparg & 1) != 0 {
|
||||
write!(f, "{:pad$}({}, NULL + {})", opcode, oparg, name(name_idx))
|
||||
} else {
|
||||
write!(f, "{:pad$}({}, {})", opcode, oparg, name(name_idx))
|
||||
}
|
||||
}
|
||||
Self::LoadLocals => w!(),
|
||||
Self::LoadName { namei } => w!(name = namei),
|
||||
Self::LoadSpecial { method } => w!(method),
|
||||
Self::LoadSuperAttr { namei } => {
|
||||
let oparg = namei.get(arg);
|
||||
write!(
|
||||
f,
|
||||
"{:pad$}({}, {}, method={}, class={})",
|
||||
opcode,
|
||||
u32::from(oparg),
|
||||
name(oparg.name_idx()),
|
||||
oparg.is_load_method(),
|
||||
oparg.has_class()
|
||||
)
|
||||
}
|
||||
Self::MakeCell { i } => w!(cell_name = i),
|
||||
Self::MakeFunction => w!(),
|
||||
Self::MapAdd { i } => w!(i),
|
||||
Self::MatchClass { count } => w!(count),
|
||||
Self::MatchKeys => w!(),
|
||||
Self::MatchMapping => w!(),
|
||||
Self::MatchSequence => w!(),
|
||||
Self::Nop => w!(),
|
||||
Self::NotTaken => w!(),
|
||||
Self::PopExcept => w!(),
|
||||
Self::PopJumpIfFalse { delta } => w!(delta),
|
||||
Self::PopJumpIfNone { delta } => w!(delta),
|
||||
Self::PopJumpIfNotNone { delta } => w!(delta),
|
||||
Self::PopJumpIfTrue { delta } => w!(delta),
|
||||
Self::PopTop => w!(),
|
||||
Self::EndFor => w!(),
|
||||
Self::PopIter => w!(),
|
||||
Self::PushExcInfo => w!(),
|
||||
Self::PushNull => w!(),
|
||||
Self::RaiseVarargs { argc } => w!(?argc),
|
||||
Self::Reraise { depth } => w!(depth),
|
||||
Self::Resume { context } => w!(context),
|
||||
Self::ReturnValue => w!(),
|
||||
Self::ReturnGenerator => w!(),
|
||||
Self::Send { delta } => w!(delta),
|
||||
Self::SetAdd { i } => w!(i),
|
||||
Self::SetFunctionAttribute { flag } => w!(?flag),
|
||||
Self::SetupAnnotations => w!(),
|
||||
Self::SetUpdate { i } => w!(i),
|
||||
Self::StoreAttr { namei } => w!(name = namei),
|
||||
Self::StoreDeref { i } => w!(cell_name = i),
|
||||
Self::StoreFast { var_num } => w!(varname = var_num),
|
||||
Self::StoreFastLoadFast { var_nums } => {
|
||||
let oparg = var_nums.get(arg);
|
||||
let (store_idx, load_idx) = oparg.indexes();
|
||||
write!(f, "{:pad$}({}, {})", opcode, store_idx, load_idx)
|
||||
}
|
||||
Self::StoreFastStoreFast { var_nums } => {
|
||||
let oparg = var_nums.get(arg);
|
||||
let (idx1, idx2) = oparg.indexes();
|
||||
write!(f, "{:pad$}({}, {})", opcode, varname(idx1), varname(idx2))
|
||||
}
|
||||
Self::StoreGlobal { namei } => w!(name = namei),
|
||||
Self::StoreName { namei } => w!(name = namei),
|
||||
Self::StoreSlice => w!(),
|
||||
Self::StoreSubscr => w!(),
|
||||
Self::Swap { i } => w!(i),
|
||||
Self::ToBool => w!(),
|
||||
Self::UnpackEx { counts } => w!(counts),
|
||||
Self::UnpackSequence { count } => w!(count),
|
||||
Self::WithExceptStart => w!(),
|
||||
Self::UnaryInvert => w!(),
|
||||
Self::UnaryNegative => w!(),
|
||||
Self::UnaryNot => w!(),
|
||||
Self::YieldValue { arg } => w!(arg),
|
||||
Self::GetYieldFromIter => w!(),
|
||||
Self::BuildTemplate => w!(),
|
||||
Self::BuildInterpolation { format } => w!(format),
|
||||
_ => w!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_opcodes!(
|
||||
@@ -1381,18 +1122,6 @@ impl InstructionMetadata for PseudoInstruction {
|
||||
fn is_unconditional_jump(&self) -> bool {
|
||||
matches!(self, Self::Jump { .. } | Self::JumpNoInterrupt { .. })
|
||||
}
|
||||
|
||||
fn fmt_dis(
|
||||
&self,
|
||||
_arg: OpArg,
|
||||
_f: &mut fmt::Formatter<'_>,
|
||||
_ctx: &impl InstrDisplayContext,
|
||||
_expand_code_objects: bool,
|
||||
_pad: usize,
|
||||
_level: usize,
|
||||
) -> fmt::Result {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -1476,16 +1205,6 @@ impl InstructionMetadata for AnyInstruction {
|
||||
inst_either!(fn stack_effect_jump(&self, oparg: u32) -> i32);
|
||||
|
||||
inst_either!(fn stack_effect_info(&self, oparg: u32) -> StackEffect);
|
||||
|
||||
inst_either!(fn fmt_dis(
|
||||
&self,
|
||||
arg: OpArg,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
ctx: &impl InstrDisplayContext,
|
||||
expand_code_objects: bool,
|
||||
pad: usize,
|
||||
level: usize
|
||||
) -> fmt::Result);
|
||||
}
|
||||
|
||||
impl AnyInstruction {
|
||||
@@ -1715,21 +1434,6 @@ pub trait InstructionMetadata {
|
||||
fn stack_effect_jump(&self, oparg: u32) -> i32 {
|
||||
self.stack_effect(oparg)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn fmt_dis(
|
||||
&self,
|
||||
arg: OpArg,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
ctx: &impl InstrDisplayContext,
|
||||
expand_code_objects: bool,
|
||||
pad: usize,
|
||||
level: usize,
|
||||
) -> fmt::Result;
|
||||
|
||||
fn display(&self, arg: OpArg, ctx: &impl InstrDisplayContext) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| self.fmt_dis(arg, f, ctx, false, 0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
||||
@@ -165,5 +165,10 @@ features = [
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
system-configuration = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { workspace = true }
|
||||
rustpython-pylib = { workspace = true, features = [ "freeze-stdlib" ] }
|
||||
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -255,3 +255,155 @@ mod _opcode {
|
||||
vm.ctx.none()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::{self, compiler::Mode};
|
||||
|
||||
macro_rules! assert_dis_snapshot {
|
||||
($value:expr) => {
|
||||
insta::assert_snapshot!(dis($value))
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the [`dis.dis`](https://docs.python.org/3/library/dis.html#dis.dis) output.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Memory addresses in the output are replaced with `0xdeadbeef` for consistency.
|
||||
fn dis(source: &str) -> String {
|
||||
let fname = String::from("<?>");
|
||||
|
||||
let builder = vm::Interpreter::builder(Default::default());
|
||||
let stdlib_defs = crate::stdlib_module_defs(&builder.ctx);
|
||||
let interp = builder
|
||||
.add_native_modules(&stdlib_defs)
|
||||
.add_frozen_modules(rustpython_pylib::FROZEN_STDLIB)
|
||||
.build();
|
||||
|
||||
interp.enter(|vm| {
|
||||
let scope = vm.new_scope_with_builtins();
|
||||
let code_obj = vm
|
||||
.compile(source.trim(), Mode::Exec, fname.clone())
|
||||
.map_err(|err| vm.new_syntax_error(&err, Some(source)))
|
||||
.unwrap();
|
||||
scope.globals.set_item("code", code_obj.into(), vm).unwrap();
|
||||
|
||||
let py_source = r#"
|
||||
import dis
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
|
||||
old_stdout = sys.stdout
|
||||
sys.stdout = buf = io.StringIO()
|
||||
dis.dis(code)
|
||||
sys.stdout = old_stdout
|
||||
|
||||
tmp_output = buf.getvalue()
|
||||
|
||||
# constant mem address
|
||||
output = re.sub(r'(<code object \w+ at )0x[0-9a-fA-F]+', r'\g<1>0xdeadbeef', tmp_output)
|
||||
"#;
|
||||
|
||||
let py_code_obj = vm
|
||||
.compile(py_source, Mode::Exec, fname)
|
||||
.map_err(|err| vm.new_syntax_error(&err, Some(py_source)))
|
||||
.unwrap();
|
||||
|
||||
vm.run_code_obj(py_code_obj, scope.clone()).unwrap();
|
||||
let py_output = scope.globals.get_item("output", vm).unwrap();
|
||||
py_output.str(vm).unwrap().to_string()
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_ors() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
if True or False or False:
|
||||
pass
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_ands() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
if True and False and False:
|
||||
pass
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_if_mixed() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
if (True and False) or (False and True):
|
||||
pass
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_bool_op() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
x = Test() and False or False
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_no_op() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
x = not True
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_constant_true_if_pass_keeps_line_anchor_nop() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
if 1:
|
||||
pass
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_double_async_with() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
async def test():
|
||||
for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
|
||||
with self.subTest(type=type(stop_exc)):
|
||||
try:
|
||||
async with egg():
|
||||
raise stop_exc
|
||||
except Exception as ex:
|
||||
self.assertIs(ex, stop_exc)
|
||||
else:
|
||||
self.fail(f'{stop_exc} was suppressed')
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bare_function_annotations_check_attribute_and_subscript_expressions() {
|
||||
assert_dis_snapshot!(
|
||||
r#"
|
||||
def f(one: int):
|
||||
int.new_attr: int
|
||||
[list][0].new_attr: [int, str]
|
||||
my_lst = [1]
|
||||
my_lst[one]: int
|
||||
return my_lst
|
||||
"#
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "dis(r#\"\ndef f(one: int):\n int.new_attr: int\n [list][0].new_attr: [int, str]\n my_lst = [1]\n my_lst[one]: int\n return my_lst\n\"#)"
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 LOAD_CONST 0 (<code object __annotate__ at 0xdeadbeef file "<?>", line 1>)
|
||||
MAKE_FUNCTION
|
||||
LOAD_CONST 1 (<code object f at 0xdeadbeef file "<?>", line 1>)
|
||||
MAKE_FUNCTION
|
||||
SET_FUNCTION_ATTRIBUTE 16 (annotate)
|
||||
STORE_NAME 0 (f)
|
||||
LOAD_CONST 2 (None)
|
||||
RETURN_VALUE
|
||||
|
||||
Disassembly of <code object __annotate__ at 0xdeadbeef file "<?>", line 1>:
|
||||
1 RESUME 0
|
||||
LOAD_FAST_BORROW 0 (format)
|
||||
LOAD_SMALL_INT 2
|
||||
COMPARE_OP 132 (>)
|
||||
POP_JUMP_IF_FALSE 3 (to L1)
|
||||
NOT_TAKEN
|
||||
LOAD_COMMON_CONSTANT 1 (NotImplementedError)
|
||||
RAISE_VARARGS 1
|
||||
L1: LOAD_CONST 1 ('one')
|
||||
LOAD_GLOBAL 0 (int)
|
||||
BUILD_MAP 1
|
||||
RETURN_VALUE
|
||||
|
||||
Disassembly of <code object f at 0xdeadbeef file "<?>", line 1>:
|
||||
1 RESUME 0
|
||||
|
||||
2 LOAD_GLOBAL 0 (int)
|
||||
POP_TOP
|
||||
|
||||
3 LOAD_GLOBAL 2 (list)
|
||||
BUILD_LIST 1
|
||||
LOAD_SMALL_INT 0
|
||||
BINARY_OP 26 ([])
|
||||
POP_TOP
|
||||
|
||||
4 LOAD_SMALL_INT 1
|
||||
BUILD_LIST 1
|
||||
STORE_FAST 1 (my_lst)
|
||||
|
||||
5 LOAD_FAST_BORROW 1 (my_lst)
|
||||
POP_TOP
|
||||
LOAD_FAST_BORROW 0 (one)
|
||||
POP_TOP
|
||||
|
||||
6 LOAD_FAST_BORROW 1 (my_lst)
|
||||
RETURN_VALUE
|
||||
10
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__const_no_op.snap
generated
Normal file
10
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__const_no_op.snap
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: x = not True
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 LOAD_CONST 2 (False)
|
||||
STORE_NAME 0 (x)
|
||||
LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "if 1:\n pass"
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 NOP
|
||||
|
||||
2 LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
8
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_ands.snap
generated
Normal file
8
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_ands.snap
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "if True and False and False:\n pass"
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
8
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_mixed.snap
generated
Normal file
8
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_mixed.snap
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "if (True and False) or (False and True):\n pass"
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
10
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_ors.snap
generated
Normal file
10
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__if_ors.snap
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "if True or False or False:\n pass"
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 NOP
|
||||
|
||||
2 LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
24
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__nested_bool_op.snap
generated
Normal file
24
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__nested_bool_op.snap
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: x = Test() and False or False
|
||||
---
|
||||
0 RESUME 0
|
||||
|
||||
1 LOAD_NAME 0 (Test)
|
||||
PUSH_NULL
|
||||
CALL 0
|
||||
COPY 1
|
||||
TO_BOOL
|
||||
POP_JUMP_IF_FALSE 11 (to L1)
|
||||
NOT_TAKEN
|
||||
POP_TOP
|
||||
LOAD_CONST 0 (False)
|
||||
COPY 1
|
||||
TO_BOOL
|
||||
POP_JUMP_IF_TRUE 3 (to L2)
|
||||
NOT_TAKEN
|
||||
L1: POP_TOP
|
||||
LOAD_CONST 0 (False)
|
||||
L2: STORE_NAME 1 (x)
|
||||
LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
183
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__nested_double_async_with.snap
generated
Normal file
183
crates/stdlib/src/snapshots/rustpython_stdlib___opcode__tests__nested_double_async_with.snap
generated
Normal file
@@ -0,0 +1,183 @@
|
||||
---
|
||||
source: crates/stdlib/src/_opcode.rs
|
||||
expression: "dis(r#\"\nasync def test():\n for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with egg():\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 RESUME 0
|
||||
|
||||
1 LOAD_CONST 0 (<code object test at 0xdeadbeef file "<?>", line 1>)
|
||||
MAKE_FUNCTION
|
||||
STORE_NAME 0 (test)
|
||||
LOAD_CONST 1 (None)
|
||||
RETURN_VALUE
|
||||
|
||||
Disassembly of <code object test at 0xdeadbeef file "<?>", line 1>:
|
||||
1 RETURN_GENERATOR
|
||||
POP_TOP
|
||||
RESUME 0
|
||||
|
||||
2 L1: LOAD_GLOBAL 1 (StopIteration + NULL)
|
||||
LOAD_CONST 0 ('spam')
|
||||
CALL 1
|
||||
LOAD_GLOBAL 3 (StopAsyncIteration + NULL)
|
||||
LOAD_CONST 1 ('ham')
|
||||
CALL 1
|
||||
BUILD_TUPLE 2
|
||||
GET_ITER
|
||||
L2: FOR_ITER 71 (to L11)
|
||||
STORE_FAST 0 (stop_exc)
|
||||
|
||||
3 LOAD_GLOBAL 4 (self)
|
||||
LOAD_ATTR 7 (subTest + NULL|self)
|
||||
LOAD_GLOBAL 9 (type + NULL)
|
||||
LOAD_FAST_BORROW 0 (stop_exc)
|
||||
CALL 1
|
||||
LOAD_CONST 2 (('type',))
|
||||
CALL_KW 1
|
||||
COPY 1
|
||||
LOAD_SPECIAL 1 (__exit__)
|
||||
SWAP 2
|
||||
SWAP 3
|
||||
LOAD_SPECIAL 0 (__enter__)
|
||||
CALL 0
|
||||
L3: POP_TOP
|
||||
|
||||
4 L4: NOP
|
||||
|
||||
5 L5: LOAD_GLOBAL 11 (egg + NULL)
|
||||
CALL 0
|
||||
COPY 1
|
||||
LOAD_SPECIAL 3 (__aexit__)
|
||||
SWAP 2
|
||||
SWAP 3
|
||||
LOAD_SPECIAL 2 (__aenter__)
|
||||
CALL 0
|
||||
GET_AWAITABLE 1
|
||||
LOAD_CONST 3 (None)
|
||||
L6: SEND 3 (to L9)
|
||||
L7: YIELD_VALUE 1
|
||||
L8: RESUME 3
|
||||
JUMP_BACKWARD_NO_INTERRUPT 5 (to L6)
|
||||
L9: END_SEND
|
||||
L10: POP_TOP
|
||||
|
||||
6 LOAD_FAST_BORROW 0 (stop_exc)
|
||||
RAISE_VARARGS 1
|
||||
|
||||
2 L11: END_FOR
|
||||
POP_ITER
|
||||
LOAD_CONST 3 (None)
|
||||
RETURN_VALUE
|
||||
|
||||
5 L12: CLEANUP_THROW
|
||||
L13: JUMP_BACKWARD_NO_INTERRUPT 10 (to L9)
|
||||
L14: PUSH_EXC_INFO
|
||||
WITH_EXCEPT_START
|
||||
GET_AWAITABLE 2
|
||||
LOAD_CONST 3 (None)
|
||||
L15: SEND 4 (to L19)
|
||||
L16: YIELD_VALUE 1
|
||||
L17: RESUME 3
|
||||
JUMP_BACKWARD_NO_INTERRUPT 5 (to L15)
|
||||
L18: CLEANUP_THROW
|
||||
L19: END_SEND
|
||||
TO_BOOL
|
||||
POP_JUMP_IF_TRUE 2 (to L20)
|
||||
NOT_TAKEN
|
||||
RERAISE 2
|
||||
L20: POP_TOP
|
||||
L21: POP_EXCEPT
|
||||
POP_TOP
|
||||
POP_TOP
|
||||
POP_TOP
|
||||
JUMP_FORWARD 3 (to L23)
|
||||
L22: COPY 3
|
||||
POP_EXCEPT
|
||||
RERAISE 1
|
||||
L23: NOP
|
||||
|
||||
10 L24: LOAD_GLOBAL 4 (self)
|
||||
LOAD_ATTR 13 (fail + NULL|self)
|
||||
LOAD_FAST 0 (stop_exc)
|
||||
FORMAT_SIMPLE
|
||||
LOAD_CONST 4 (' was suppressed')
|
||||
BUILD_STRING 2
|
||||
CALL 1
|
||||
POP_TOP
|
||||
JUMP_FORWARD 45 (to L31)
|
||||
|
||||
-- L25: PUSH_EXC_INFO
|
||||
|
||||
7 LOAD_GLOBAL 14 (Exception)
|
||||
CHECK_EXC_MATCH
|
||||
POP_JUMP_IF_FALSE 32 (to L29)
|
||||
NOT_TAKEN
|
||||
STORE_FAST 1 (ex)
|
||||
|
||||
8 L26: LOAD_GLOBAL 4 (self)
|
||||
LOAD_ATTR 17 (assertIs + NULL|self)
|
||||
LOAD_FAST_LOAD_FAST 16 (ex, stop_exc)
|
||||
CALL 2
|
||||
POP_TOP
|
||||
L27: POP_EXCEPT
|
||||
LOAD_CONST 3 (None)
|
||||
STORE_FAST 1 (ex)
|
||||
DELETE_FAST 1 (ex)
|
||||
JUMP_FORWARD 8 (to L31)
|
||||
|
||||
-- L28: LOAD_CONST 3 (None)
|
||||
STORE_FAST 1 (ex)
|
||||
DELETE_FAST 1 (ex)
|
||||
RERAISE 1
|
||||
|
||||
7 L29: RERAISE 0
|
||||
|
||||
-- L30: COPY 3
|
||||
POP_EXCEPT
|
||||
RERAISE 1
|
||||
|
||||
3 L31: LOAD_CONST 3 (None)
|
||||
LOAD_CONST 3 (None)
|
||||
LOAD_CONST 3 (None)
|
||||
CALL 3
|
||||
POP_TOP
|
||||
JUMP_BACKWARD 188 (to L2)
|
||||
L32: PUSH_EXC_INFO
|
||||
WITH_EXCEPT_START
|
||||
TO_BOOL
|
||||
POP_JUMP_IF_TRUE 2 (to L33)
|
||||
NOT_TAKEN
|
||||
RERAISE 2
|
||||
L33: POP_TOP
|
||||
L34: POP_EXCEPT
|
||||
POP_TOP
|
||||
POP_TOP
|
||||
POP_TOP
|
||||
JUMP_BACKWARD 205 (to L2)
|
||||
L35: COPY 3
|
||||
POP_EXCEPT
|
||||
RERAISE 1
|
||||
|
||||
-- L36: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
|
||||
RERAISE 1
|
||||
ExceptionTable:
|
||||
L1 to L3 -> L36 [0] lasti
|
||||
L3 to L4 -> L32 [3] lasti
|
||||
L5 to L7 -> L25 [3]
|
||||
L7 to L8 -> L12 [7]
|
||||
L8 to L10 -> L25 [3]
|
||||
L10 to L11 -> L14 [5] lasti
|
||||
L11 to L12 -> L36 [0] lasti
|
||||
L12 to L13 -> L25 [3]
|
||||
L14 to L16 -> L22 [7] lasti
|
||||
L16 to L17 -> L18 [10]
|
||||
L17 to L21 -> L22 [7] lasti
|
||||
L21 to L23 -> L25 [3]
|
||||
L24 to L25 -> L32 [3] lasti
|
||||
L25 to L26 -> L30 [4] lasti
|
||||
L26 to L27 -> L28 [4] lasti
|
||||
L27 to L28 -> L32 [3] lasti
|
||||
L28 to L30 -> L30 [4] lasti
|
||||
L30 to L31 -> L32 [3] lasti
|
||||
L31 to L32 -> L36 [0] lasti
|
||||
L32 to L34 -> L35 [5] lasti
|
||||
L34 to L36 -> L36 [0] lasti
|
||||
@@ -1462,12 +1462,6 @@ impl PyCode {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PyCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(**self).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPyObject for CodeObject {
|
||||
fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx.new_code(self).into()
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
//! This an example usage of the rustpython_compiler crate.
|
||||
//! This program reads, parses, and compiles a file you provide
|
||||
//! to RustPython bytecode, and then displays the output in the
|
||||
//! `dis.dis` format.
|
||||
//!
|
||||
//! example usage:
|
||||
//! $ cargo run --release --example dis demo*.py
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use core::error::Error;
|
||||
use lexopt::ValueExt;
|
||||
use rustpython_compiler as compiler;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn main() -> Result<(), lexopt::Error> {
|
||||
env_logger::init();
|
||||
|
||||
let mut scripts = vec![];
|
||||
let mut mode = compiler::Mode::Exec;
|
||||
let mut expand_code_objects = true;
|
||||
let mut optimize = 0;
|
||||
|
||||
let mut parser = lexopt::Parser::from_env();
|
||||
while let Some(arg) = parser.next()? {
|
||||
use lexopt::Arg::*;
|
||||
match arg {
|
||||
Long("help") | Short('h') => {
|
||||
let bin_name = parser.bin_name().unwrap_or("dis");
|
||||
println!(
|
||||
"usage: {bin_name} <scripts...> [-m,--mode=exec|single|eval] [-x,--no-expand] [-O]"
|
||||
);
|
||||
println!(
|
||||
"Compiles and disassembles python script files for viewing their bytecode."
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
Value(x) => scripts.push(PathBuf::from(x)),
|
||||
Long("mode") | Short('m') => {
|
||||
mode = parser
|
||||
.value()?
|
||||
.parse_with(|s| s.parse::<compiler::Mode>().map_err(|e| e.to_string()))?
|
||||
}
|
||||
Long("no-expand") | Short('x') => expand_code_objects = false,
|
||||
Short('O') => optimize += 1,
|
||||
_ => return Err(arg.unexpected()),
|
||||
}
|
||||
}
|
||||
|
||||
if scripts.is_empty() {
|
||||
return Err("expected at least one argument".into());
|
||||
}
|
||||
|
||||
let opts = compiler::CompileOpts {
|
||||
optimize,
|
||||
debug_ranges: true,
|
||||
};
|
||||
|
||||
for script in &scripts {
|
||||
if script.exists() && script.is_file() {
|
||||
let res = display_script(script, mode, opts, expand_code_objects);
|
||||
if let Err(e) = res {
|
||||
error!("Error while compiling {script:?}: {e}");
|
||||
}
|
||||
} else {
|
||||
eprintln!("{script:?} is not a file.");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_script(
|
||||
path: &Path,
|
||||
mode: compiler::Mode,
|
||||
opts: compiler::CompileOpts,
|
||||
expand_code_objects: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let source = fs::read_to_string(path)?;
|
||||
let code = compiler::compile(&source, mode, &path.to_string_lossy(), opts)?;
|
||||
println!("{}:", path.display());
|
||||
if expand_code_objects {
|
||||
println!("{}", code.display_expand_code_objects());
|
||||
} else {
|
||||
println!("{code}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user