From ac765a957beb5655ae882f0b871971b69cc082ec Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Sat, 13 Jul 2019 12:23:53 +0200 Subject: [PATCH] Add a settings struct for storage of different settings which influence the VM. --- compiler/src/compile.rs | 18 ++++++------ derive/src/compile_bytecode.rs | 2 +- src/main.rs | 44 +++++++++++++++++++++++----- vm/src/builtins.rs | 2 +- vm/src/import.rs | 9 ++++-- vm/src/lib.rs | 2 +- vm/src/sysmodule.rs | 23 ++++++++++++--- vm/src/vm.rs | 53 ++++++++++++++++++++++++++++++---- 8 files changed, 123 insertions(+), 30 deletions(-) diff --git a/compiler/src/compile.rs b/compiler/src/compile.rs index f78a25b4f..93ea6446e 100644 --- a/compiler/src/compile.rs +++ b/compiler/src/compile.rs @@ -20,7 +20,7 @@ struct Compiler { current_qualified_path: Option, in_loop: bool, in_function_def: bool, - optimize: bool, + optimize: u8, } /// Compile a given sourcecode into a bytecode object. @@ -28,7 +28,7 @@ pub fn compile( source: &str, mode: &Mode, source_path: String, - optimize: bool, + optimize: u8, ) -> Result { match mode { Mode::Exec => { @@ -49,7 +49,7 @@ pub fn compile( /// A helper function for the shared code of the different compile functions fn with_compiler( source_path: String, - optimize: bool, + optimize: u8, f: impl FnOnce(&mut Compiler) -> Result<(), CompileError>, ) -> Result { let mut compiler = Compiler::new(optimize); @@ -65,7 +65,7 @@ fn with_compiler( pub fn compile_program( ast: ast::Program, source_path: String, - optimize: bool, + optimize: u8, ) -> Result { with_compiler(source_path, optimize, |compiler| { let symbol_table = make_symbol_table(&ast)?; @@ -77,7 +77,7 @@ pub fn compile_program( pub fn compile_statement_eval( statement: Vec, source_path: String, - optimize: bool, + optimize: u8, ) -> Result { with_compiler(source_path, optimize, |compiler| { let symbol_table = statements_to_symbol_table(&statement)?; @@ -89,7 +89,7 @@ pub fn compile_statement_eval( pub fn compile_program_single( ast: ast::Program, source_path: String, - optimize: bool, + optimize: u8, ) -> Result { with_compiler(source_path, optimize, |compiler| { let symbol_table = make_symbol_table(&ast)?; @@ -113,12 +113,12 @@ type Label = usize; impl Default for Compiler { fn default() -> Self { - Compiler::new(false) + Compiler::new(0) } } impl Compiler { - fn new(optimize: bool) -> Self { + fn new(optimize: u8) -> Self { Compiler { code_object_stack: Vec::new(), scope_stack: Vec::new(), @@ -455,7 +455,7 @@ impl Compiler { } => self.compile_class_def(name, body, bases, keywords, decorator_list)?, ast::Statement::Assert { test, msg } => { // if some flag, ignore all assert statements! - if !self.optimize { + if self.optimize == 0 { let end_label = self.new_label(); self.compile_test(test, Some(end_label), None, EvalContext::Statement)?; self.emit(Instruction::LoadName { diff --git a/derive/src/compile_bytecode.rs b/derive/src/compile_bytecode.rs index eedba9ffc..f03b5d065 100644 --- a/derive/src/compile_bytecode.rs +++ b/derive/src/compile_bytecode.rs @@ -38,7 +38,7 @@ struct CompilationSource { impl CompilationSource { fn compile(self, mode: &compile::Mode, module_name: String) -> Result { let compile = |source| { - compile::compile(source, mode, module_name, false).map_err(|err| { + compile::compile(source, mode, module_name, 0).map_err(|err| { Diagnostic::spans_error(self.span, format!("Compile error: {}", err)) }) }; diff --git a/src/main.rs b/src/main.rs index ed799fc7b..792c3c527 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate env_logger; #[macro_use] extern crate log; extern crate rustyline; +use std::convert::TryInto; use clap::{App, Arg}; use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType}; @@ -14,7 +15,7 @@ use rustpython_vm::{ obj::objstr, print_exception, pyobject::{ItemProtocol, PyResult}, - util, VirtualMachine, + util, PySettings, VirtualMachine, }; use rustyline::{error::ReadlineError, Editor}; @@ -37,10 +38,31 @@ fn main() { .help("Optimize. Set __debug__ to false. Remove debug statements."), ) .arg( - Arg::with_name("v") + Arg::with_name("verbose") .short("v") .multiple(true) - .help("Give the verbosity"), + .help("Give the verbosity (can be applied multiple times)"), + ) + .arg(Arg::with_name("debug").short("d").help("Debug the parser.")) + .arg( + Arg::with_name("quiet") + .short("q") + .help("Be quiet at startup."), + ) + .arg( + Arg::with_name("inspect") + .short("i") + .help("Inspect interactively after running the script."), + ) + .arg( + Arg::with_name("no-user-site") + .short("s") + .help("don't add user site directory to sys.path."), + ) + .arg( + Arg::with_name("no-site") + .short("S") + .help("don't imply 'import site' on initialization"), ) .arg( Arg::with_name("c") @@ -71,11 +93,19 @@ fn main() { ); let matches = app.get_matches(); - let opt_level = matches.occurrences_of("optimize"); - let optimize = opt_level > 0; - debug!("Optimize: {}", optimize); + let opt_level: u8 = matches.occurrences_of("optimize").try_into().unwrap(); + let verbosity_level: u8 = matches.occurrences_of("verbose").try_into().unwrap(); + // Construct vm: - let vm = VirtualMachine::new(optimize); + let mut settings: PySettings = Default::default(); + settings.debug = matches.is_present("debug"); + settings.inspect = matches.is_present("inspect"); + settings.optimize = opt_level; + settings.no_site = matches.is_present("no-site"); + settings.no_user_site = matches.is_present("no-user-site"); + settings.verbose = verbosity_level; + settings.quiet = matches.is_present("quiet"); + let vm = VirtualMachine::new(settings); let res = import::init_importlib(&vm, true); handle_exception(&vm, res); diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 114a3eff5..7e47419db 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -798,7 +798,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) { }); } - let debug_mode = !vm.optimize; + let debug_mode: bool = vm.settings.optimize == 0; extend_module!(vm, module, { "__debug__" => ctx.new_bool(debug_mode), //set __name__ fixes: https://github.com/RustPython/RustPython/issues/146 diff --git a/vm/src/import.rs b/vm/src/import.rs index 0412f57a6..88d66ce82 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -55,8 +55,13 @@ pub fn import_file( file_path: String, content: String, ) -> PyResult { - let code_obj = compile::compile(&content, &compile::Mode::Exec, file_path, vm.optimize) - .map_err(|err| vm.new_syntax_error(&err))?; + let code_obj = compile::compile( + &content, + &compile::Mode::Exec, + file_path, + vm.settings.optimize, + ) + .map_err(|err| vm.new_syntax_error(&err))?; import_codeobj(vm, module_name, code_obj, true) } diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 73f1804fa..5b13df234 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -70,7 +70,7 @@ mod vm; // pub use self::pyobject::Executor; pub use self::exceptions::print_exception; -pub use self::vm::VirtualMachine; +pub use self::vm::{PySettings, VirtualMachine}; pub use rustpython_bytecode::*; #[doc(hidden)] diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index ce033001d..10aeb4747 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -6,7 +6,7 @@ use crate::function::{OptionalArg, PyFuncArgs}; use crate::obj::objstr::PyStringRef; use crate::pyobject::{IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult}; use crate::version; -use crate::vm::VirtualMachine; +use crate::vm::{PySettings, VirtualMachine}; /* * The magic sys module. @@ -51,7 +51,7 @@ struct SysFlags { /// -E ignore_environment: bool, /// -v - verbose: bool, + verbose: u8, /// -b bytes_warning: bool, /// -q @@ -66,6 +66,22 @@ struct SysFlags { utf8_mode: bool, } +impl SysFlags { + fn from_settings(settings: &PySettings) -> Self { + // Start with sensible defaults: + let mut flags: SysFlags = Default::default(); + flags.debug = settings.debug; + flags.inspect = settings.inspect; + flags.optimize = settings.optimize; + flags.no_user_site = settings.no_user_site; + flags.no_site = settings.no_site; + flags.ignore_environment = settings.ignore_environment; + flags.verbose = settings.verbose; + flags.quiet = settings.quiet; + flags + } +} + fn sys_getrefcount(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(object, None)]); let size = Rc::strong_count(&object); @@ -103,8 +119,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR let ctx = &vm.ctx; let flags_type = SysFlags::make_class(ctx); - // TODO parse command line arguments and environment variables to populate SysFlags - let flags = SysFlags::default() + let flags = SysFlags::from_settings(&vm.settings) .into_struct_sequence(vm, flags_type) .unwrap(); diff --git a/vm/src/vm.rs b/vm/src/vm.rs index b5cd49daa..232eca0e1 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -56,12 +56,55 @@ pub struct VirtualMachine { pub exceptions: RefCell>, pub frozen: RefCell>, pub import_func: RefCell, - pub optimize: bool, + pub settings: PySettings, +} + +/// Struct containing all kind of settings for the python vm. +pub struct PySettings { + /// -d command line switch + pub debug: bool, + + /// -i + pub inspect: bool, + + /// -O optimization switch counter + pub optimize: u8, + + /// -s + pub no_user_site: bool, + + /// -S + pub no_site: bool, + + /// -E + pub ignore_environment: bool, + + /// verbosity level (-v switch) + pub verbose: u8, + + /// -q + pub quiet: bool, +} + +/// Sensible default settings. +impl Default for PySettings { + fn default() -> Self { + PySettings { + debug: false, + inspect: false, + optimize: 0, + no_user_site: false, + no_site: false, + ignore_environment: false, + verbose: 0, + quiet: false, + } + } } impl VirtualMachine { /// Create a new `VirtualMachine` structure. - pub fn new(optimize: bool) -> VirtualMachine { + pub fn new(settings: PySettings) -> VirtualMachine { flame_guard!("init VirtualMachine"); let ctx = PyContext::new(); @@ -82,7 +125,7 @@ impl VirtualMachine { exceptions: RefCell::new(vec![]), frozen, import_func, - optimize, + settings, }; builtins::make_module(&vm, builtins.clone()); @@ -751,7 +794,7 @@ impl VirtualMachine { mode: &compile::Mode, source_path: String, ) -> Result { - compile::compile(source, mode, source_path, self.optimize) + compile::compile(source, mode, source_path, self.settings.optimize) .map(|codeobj| PyCode::new(codeobj).into_ref(self)) } @@ -1024,7 +1067,7 @@ impl VirtualMachine { impl Default for VirtualMachine { fn default() -> Self { - VirtualMachine::new(false) + VirtualMachine::new(Default::default()) } }