diff --git a/examples/generator.rs b/examples/generator.rs index 49c37f52e..4bcd53026 100644 --- a/examples/generator.rs +++ b/examples/generator.rs @@ -1,4 +1,5 @@ use rustpython_vm as vm; +use std::process::ExitCode; use vm::{ builtins::PyIntRef, protocol::{PyIter, PyIterReturn}, @@ -40,10 +41,10 @@ gen() Ok(()) } -fn main() { +fn main() -> ExitCode { let interp = vm::Interpreter::with_init(Default::default(), |vm| { vm.add_native_modules(rustpython_stdlib::get_module_inits()); }); let result = py_main(&interp); - std::process::exit(interp.run(|_vm| result)); + ExitCode::from(interp.run(|_vm| result)) } diff --git a/examples/package_embed.rs b/examples/package_embed.rs index 664ea6d3c..ef9cee6cd 100644 --- a/examples/package_embed.rs +++ b/examples/package_embed.rs @@ -1,4 +1,5 @@ use rustpython_vm as vm; +use std::process::ExitCode; use vm::{builtins::PyStrRef, Interpreter}; fn py_main(interp: &Interpreter) -> vm::PyResult { @@ -13,7 +14,7 @@ fn py_main(interp: &Interpreter) -> vm::PyResult { }) } -fn main() -> vm::PyResult<()> { +fn main() -> ExitCode { let interp = vm::Interpreter::with_init(Default::default(), |vm| { vm.add_native_modules(rustpython_stdlib::get_module_inits()); }); @@ -22,6 +23,5 @@ fn main() -> vm::PyResult<()> { println!("name: {}", result); Ok(()) }); - let exit_code = interp.run(|_vm| result); - std::process::exit(exit_code); + ExitCode::from(interp.run(|_vm| result)) } diff --git a/parser/build.rs b/parser/build.rs index 6ab08cbbf..1304f46b3 100644 --- a/parser/build.rs +++ b/parser/build.rs @@ -2,15 +2,18 @@ use std::fmt::Write as _; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::path::PathBuf; -use std::process::{self, Command}; +use std::process::{Command, ExitCode}; use tiny_keccak::{Hasher, Sha3}; -fn main() { - check_lalrpop("src/python.lalrpop", "src/python.rs"); +fn main() -> ExitCode { + if let Err(exit_code) = check_lalrpop("src/python.lalrpop", "src/python.rs") { + return exit_code; + } gen_phf(); + ExitCode::SUCCESS } -fn check_lalrpop(source: &str, generated: &str) { +fn check_lalrpop(source: &str, generated: &str) -> Result<(), ExitCode> { println!("cargo:rerun-if-changed={source}"); let sha_prefix = "// sha3: "; @@ -44,20 +47,21 @@ fn check_lalrpop(source: &str, generated: &str) { }; if sha_equal(expected_sha3_str, &actual_sha3) { - return; + return Ok(()); } match Command::new("lalrpop").arg(source).status() { - Ok(stat) if stat.success() => {} + Ok(stat) if stat.success() => Ok(()), Ok(stat) => { eprintln!("failed to execute lalrpop; exited with {stat}"); - process::exit(stat.code().unwrap_or(1)); + let exit_code = stat.code().map(|v| (v % 256) as u8).unwrap_or(1); + Err(ExitCode::from(exit_code)) } Err(e) if e.kind() == io::ErrorKind::NotFound => { eprintln!( "the lalrpop executable is not installed and parser/{source} has been changed" ); eprintln!("please install lalrpop with `cargo install lalrpop`"); - process::exit(1); + Err(ExitCode::FAILURE) } Err(e) => panic!("io error {e:#}"), } diff --git a/src/lib.rs b/src/lib.rs index b81fdf95d..8e32124ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,13 +47,13 @@ mod shell; use clap::{App, AppSettings, Arg, ArgMatches}; use rustpython_vm::{scope::Scope, Interpreter, PyResult, Settings, VirtualMachine}; -use std::{env, process, str::FromStr}; +use std::{env, process::ExitCode, str::FromStr}; pub use rustpython_vm as vm; -/// The main cli of the `rustpython` interpreter. This function will exit with `process::exit()` +/// The main cli of the `rustpython` interpreter. This function will return with `std::process::ExitCode` /// based on the return code of the python code ran through the cli. -pub fn run(init: F) -> ! +pub fn run(init: F) -> ExitCode where F: FnOnce(&mut VirtualMachine), { @@ -92,8 +92,7 @@ where error!("Error writing profile information: {}", e); } } - - process::exit(exitcode) + ExitCode::from(exitcode) } fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { @@ -385,7 +384,8 @@ fn create_settings(matches: &ArgMatches) -> Settings { }; settings.hash_seed = hash_seed.unwrap_or_else(|| { error!("Fatal Python init error: PYTHONHASHSEED must be \"random\" or an integer in range [0; 4294967295]"); - process::exit(1) + // TODO: Need to change to ExitCode or Termination + std::process::exit(1) }); settings.argv = argv; @@ -449,7 +449,8 @@ fn write_profile(matches: &ArgMatches) -> Result<(), Box> Some("speedscope") | None => ProfileFormat::Speedscope, Some(other) => { error!("Unknown profile format {}", other); - process::exit(1); + // TODO: Need to change to ExitCode or Termination + std::process::exit(1); } }; diff --git a/src/main.rs b/src/main.rs index fdc9f7037..e88ea40f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,3 @@ -pub fn main() { +pub fn main() -> std::process::ExitCode { rustpython::run(|_vm| {}) } diff --git a/vm/src/vm/compile.rs b/vm/src/vm/compile.rs index 401cece01..94d8c3e84 100644 --- a/vm/src/vm/compile.rs +++ b/vm/src/vm/compile.rs @@ -59,6 +59,7 @@ impl VirtualMachine { } Err(err) => { error!("Failed reading file '{}': {}", path, err); + // TODO: Need to change to ExitCode or Termination std::process::exit(1); } } diff --git a/vm/src/vm/interpreter.rs b/vm/src/vm/interpreter.rs index e8b079e27..d8e57ed08 100644 --- a/vm/src/vm/interpreter.rs +++ b/vm/src/vm/interpreter.rs @@ -59,7 +59,7 @@ impl Interpreter { thread::enter_vm(&self.vm, || f(&self.vm)) } - pub fn run(self, f: F) -> i32 + pub fn run(self, f: F) -> u8 where F: FnOnce(&VirtualMachine) -> PyResult, { diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index a4e7bad49..e7e362429 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -678,7 +678,7 @@ impl VirtualMachine { } } - pub fn handle_exit_exception(&self, exc: PyBaseExceptionRef) -> i32 { + pub fn handle_exit_exception(&self, exc: PyBaseExceptionRef) -> u8 { if exc.fast_isinstance(self.ctx.exceptions.system_exit) { let args = exc.args(); let msg = match args.as_slice() { @@ -686,7 +686,7 @@ impl VirtualMachine { [arg] => match_class!(match arg { ref i @ PyInt => { use num_traits::cast::ToPrimitive; - return i.as_bigint().to_i32().unwrap_or(0); + return i.as_bigint().to_u8().unwrap_or(0); } arg => { if self.is_none(arg) {