forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdis.rs
96 lines (89 loc) · 2.89 KB
/
dis.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/// 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 clap;
extern crate env_logger;
#[macro_use]
extern crate log;
use clap::{App, Arg};
use rustpython_compiler as compiler;
use std::error::Error;
use std::fs;
use std::path::Path;
fn main() {
env_logger::init();
let app = App::new("dis")
.version(crate_version!())
.author(crate_authors!())
.about("Compiles and disassembles python script files for viewing their bytecode.")
.arg(
Arg::with_name("scripts")
.help("Scripts to scan")
.multiple(true)
.required(true),
)
.arg(
Arg::with_name("mode")
.help("The mode to compile the scripts in")
.long("mode")
.short("m")
.default_value("exec")
.possible_values(&["exec", "single", "eval"])
.takes_value(true),
)
.arg(
Arg::with_name("no_expand")
.help(
"Don't expand CodeObject LoadConst instructions to show \
the instructions inside",
)
.long("no-expand")
.short("x"),
)
.arg(
Arg::with_name("optimize")
.help("The amount of optimization to apply to the compiled bytecode")
.short("O")
.multiple(true),
);
let matches = app.get_matches();
let mode = matches.value_of_lossy("mode").unwrap().parse().unwrap();
let expand_code_objects = !matches.is_present("no_expand");
let optimize = matches.occurrences_of("optimize") as u8;
let scripts = matches.values_of_os("scripts").unwrap();
let opts = compiler::CompileOpts {
optimize,
..Default::default()
};
for script in scripts.map(Path::new) {
if script.exists() && script.is_file() {
let res = display_script(script, mode, opts.clone(), expand_code_objects);
if let Err(e) = res {
error!("Error while compiling {:?}: {}", script, e);
}
} else {
eprintln!("{script:?} is not a file.");
}
}
}
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().into_owned(), opts)?;
println!("{}:", path.display());
if expand_code_objects {
println!("{}", code.display_expand_code_objects());
} else {
println!("{code}");
}
Ok(())
}