mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Correctly handle a SystemExit unwound to the top level of execution
This commit is contained in:
1 parent
452e82f3a7
commit
e89d00f167
5 files changed
+46
-16
No files matched your search
Generated
+1
@@ -1092,6 +1092,7 @@ dependencies = [
|
||||
"flame 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flamescope 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustpython-compiler 0.1.1",
|
||||
"rustpython-parser 0.1.1",
|
||||
"rustpython-vm 0.1.1",
|
||||
|
||||
@@ -27,6 +27,7 @@ rustpython-compiler = {path = "compiler", version = "0.1.1"}
|
||||
rustpython-parser = {path = "parser", version = "0.1.1"}
|
||||
rustpython-vm = {path = "vm", version = "0.1.1"}
|
||||
dirs = "2.0"
|
||||
num-traits = "0.2.8"
|
||||
|
||||
flame = { version = "0.2", optional = true }
|
||||
flamescope = { version = "0.1", optional = true }
|
||||
|
||||
+40
-11
@@ -8,7 +8,9 @@ use clap::{App, AppSettings, Arg, ArgMatches};
|
||||
use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType};
|
||||
use rustpython_parser::error::ParseErrorType;
|
||||
use rustpython_vm::{
|
||||
import, print_exception,
|
||||
import, match_class,
|
||||
obj::{objint::PyInt, objtuple::PyTuple, objtype},
|
||||
print_exception,
|
||||
pyobject::{ItemProtocol, PyObjectRef, PyResult},
|
||||
scope::Scope,
|
||||
util, PySettings, VirtualMachine,
|
||||
@@ -30,17 +32,47 @@ fn main() {
|
||||
let vm = VirtualMachine::new(settings);
|
||||
|
||||
let res = run_rustpython(&vm, &matches);
|
||||
// See if any exception leaked out:
|
||||
handle_exception(&vm, res);
|
||||
|
||||
#[cfg(feature = "flame-it")]
|
||||
{
|
||||
main_guard.end();
|
||||
if let Err(e) = write_profile(&matches) {
|
||||
error!("Error writing profile information: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// See if any exception leaked out:
|
||||
if let Err(err) = res {
|
||||
if objtype::isinstance(&err, &vm.ctx.exceptions.system_exit) {
|
||||
let args = vm.get_attribute(err.clone(), "args").unwrap();
|
||||
let args = args.downcast::<PyTuple>().expect("'args' must be a tuple");
|
||||
match args.elements.len() {
|
||||
0 => return,
|
||||
1 => match_class!(match args.elements[0].clone() {
|
||||
i @ PyInt => {
|
||||
use num_traits::cast::ToPrimitive;
|
||||
process::exit(i.as_bigint().to_i32().unwrap());
|
||||
}
|
||||
arg => {
|
||||
if vm.is_none(&arg) {
|
||||
return;
|
||||
}
|
||||
if let Ok(s) = vm.to_str(&arg) {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
}),
|
||||
_ => {
|
||||
if let Ok(r) = vm.to_repr(args.as_object()) {
|
||||
println!("{}", r);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_exception(&vm, &err);
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
|
||||
@@ -349,13 +381,6 @@ fn _run_string(vm: &VirtualMachine, scope: Scope, source: &str, source_path: Str
|
||||
vm.run_code_obj(code_obj, scope)
|
||||
}
|
||||
|
||||
fn handle_exception<T>(vm: &VirtualMachine, result: PyResult<T>) {
|
||||
if let Err(err) = result {
|
||||
print_exception(vm, &err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_command(vm: &VirtualMachine, scope: Scope, source: String) -> PyResult<()> {
|
||||
debug!("Running command {}", source);
|
||||
_run_string(vm, scope, &source, "<stdin>".to_string())?;
|
||||
@@ -560,6 +585,10 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
|
||||
};
|
||||
|
||||
if let Err(exc) = result {
|
||||
if objtype::isinstance(&exc, &vm.ctx.exceptions.system_exit) {
|
||||
repl.save_history(&repl_history_path).unwrap();
|
||||
return Err(exc);
|
||||
}
|
||||
print_exception(vm, &exc);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -171,10 +171,9 @@ fn sys_git_info(vm: &VirtualMachine) -> PyObjectRef {
|
||||
])
|
||||
}
|
||||
|
||||
// TODO: raise a SystemExit here
|
||||
fn sys_exit(code: OptionalArg<i32>, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
let code = code.unwrap_or(0);
|
||||
std::process::exit(code)
|
||||
fn sys_exit(code: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
|
||||
let code = code.unwrap_or_else(|| vm.new_int(0));
|
||||
Err(vm.new_exception_obj(vm.ctx.exceptions.system_exit.clone(), vec![code])?)
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) {
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("VirtualMachine"))]
|
||||
fn new_exception_obj(&self, exc_type: PyClassRef, args: Vec<PyObjectRef>) -> PyResult {
|
||||
pub fn new_exception_obj(&self, exc_type: PyClassRef, args: Vec<PyObjectRef>) -> PyResult {
|
||||
// TODO: add repr of args into logging?
|
||||
vm_trace!("New exception created: {}", exc_type.name);
|
||||
self.invoke(&exc_type.into_object(), args)
|
||||
|
||||
Reference in new issue
Block a user