Skip to content

Commit c83d8fd

Browse files
committed
exception-to-exitcode to vm method
1 parent ec9697a commit c83d8fd

File tree

2 files changed

+50
-52
lines changed

2 files changed

+50
-52
lines changed

src/lib.rs

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ mod shell;
4747

4848
use clap::{App, AppSettings, Arg, ArgMatches};
4949
use rustpython_vm::{
50-
builtins::PyInt,
51-
match_class,
5250
scope::Scope,
5351
stdlib::{atexit, sys},
54-
AsObject, Interpreter, PyResult, Settings, VirtualMachine,
52+
Interpreter, PyResult, Settings, VirtualMachine,
5553
};
5654
use std::{env, process, str::FromStr};
5755

@@ -68,7 +66,8 @@ where
6866
env_logger::init();
6967
let app = App::new("RustPython");
7068
let matches = parse_arguments(app);
71-
let settings = create_settings(&matches);
69+
let matches = &matches;
70+
let settings = create_settings(matches);
7271

7372
// don't translate newlines (\r\n <=> \n)
7473
#[cfg(windows)]
@@ -89,61 +88,31 @@ where
8988
});
9089

9190
let exitcode = interp.enter(move |vm| {
92-
let res = run_rustpython(vm, &matches);
91+
let res = run_rustpython(vm, matches);
9392

9493
flush_std(vm);
9594

96-
#[cfg(feature = "flame-it")]
97-
{
98-
main_guard.end();
99-
if let Err(e) = write_profile(&matches) {
100-
error!("Error writing profile information: {}", e);
101-
}
102-
}
103-
10495
// See if any exception leaked out:
105-
let exitcode = match res {
106-
Ok(()) => 0,
107-
Err(err) if err.fast_isinstance(&vm.ctx.exceptions.system_exit) => {
108-
let args = err.args();
109-
let exitcode = match args.as_slice() {
110-
[] => Ok(0),
111-
[arg] => match_class!(match arg {
112-
ref i @ PyInt => {
113-
use num_traits::cast::ToPrimitive;
114-
Ok(i.as_bigint().to_i32().unwrap_or(0))
115-
}
116-
arg => {
117-
if vm.is_none(arg) {
118-
Ok(0)
119-
} else {
120-
Err(arg.str(vm).ok())
121-
}
122-
}
123-
}),
124-
_ => Err(args.as_object().repr(vm).ok()),
125-
};
126-
exitcode.unwrap_or_else(|msg| {
127-
if let Some(msg) = msg {
128-
let stderr = sys::PyStderr(vm);
129-
writeln!(stderr, "{}", msg);
130-
}
131-
1
132-
})
133-
}
134-
Err(exc) => {
135-
vm.print_exception(exc);
136-
1
137-
}
138-
};
96+
let exit_code = res
97+
.map(|_| 0)
98+
.map_err(|exc| vm.handle_exit_exception(exc))
99+
.unwrap_or_else(|code| code);
139100

140101
let _ = atexit::_run_exitfuncs(vm);
141102

142103
flush_std(vm);
143104

144-
exitcode
105+
exit_code
145106
});
146107

108+
#[cfg(feature = "flame-it")]
109+
{
110+
main_guard.end();
111+
if let Err(e) = write_profile(&matches) {
112+
error!("Error writing profile information: {}", e);
113+
}
114+
}
115+
147116
process::exit(exitcode)
148117
}
149118

vm/src/vm/mod.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
code::{self, PyCode},
2020
pystr::IntoPyStrRef,
2121
tuple::{PyTuple, PyTupleTyped},
22-
PyBaseExceptionRef, PyDictRef, PyList, PyModule, PyStrRef, PyTypeRef,
22+
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrRef, PyTypeRef,
2323
},
2424
bytecode,
2525
codecs::CodecsRegistry,
@@ -278,15 +278,13 @@ impl VirtualMachine {
278278

279279
#[cold]
280280
pub fn run_unraisable(&self, e: PyBaseExceptionRef, msg: Option<String>, object: PyObjectRef) {
281-
use crate::stdlib::sys::UnraisableHookArgs;
282-
283281
let sys_module = self.import("sys", None, 0).unwrap();
284282
let unraisablehook = sys_module.get_attr("unraisablehook", self).unwrap();
285283

286284
let exc_type = e.class().clone();
287285
let exc_traceback = e.traceback().to_pyobject(self); // TODO: actual traceback
288286
let exc_value = e.into();
289-
let args = UnraisableHookArgs {
287+
let args = stdlib::sys::UnraisableHookArgs {
290288
exc_type,
291289
exc_value,
292290
exc_traceback,
@@ -660,6 +658,37 @@ impl VirtualMachine {
660658
}
661659
}
662660

661+
pub fn handle_exit_exception(&self, exc: PyBaseExceptionRef) -> i32 {
662+
if exc.fast_isinstance(&self.ctx.exceptions.system_exit) {
663+
let args = exc.args();
664+
let msg = match args.as_slice() {
665+
[] => return 0,
666+
[arg] => match_class!(match arg {
667+
ref i @ PyInt => {
668+
use num_traits::cast::ToPrimitive;
669+
return i.as_bigint().to_i32().unwrap_or(0);
670+
}
671+
arg => {
672+
if self.is_none(arg) {
673+
return 0;
674+
} else {
675+
arg.str(self).ok()
676+
}
677+
}
678+
}),
679+
_ => args.as_object().repr(self).ok(),
680+
};
681+
if let Some(msg) = msg {
682+
let stderr = stdlib::sys::PyStderr(self);
683+
writeln!(stderr, "{}", msg);
684+
}
685+
1
686+
} else {
687+
self.print_exception(exc);
688+
1
689+
}
690+
}
691+
663692
pub fn map_codeobj(&self, code: bytecode::CodeObject) -> code::CodeObject {
664693
code.map_bag(&code::PyObjBag(self))
665694
}

0 commit comments

Comments
 (0)