rustpython_vm/vm/
compile.rs1use crate::{
2 builtins::{PyCode, PyDictRef},
3 compiler::{self, CompileError, CompileOpts},
4 convert::TryFromObject,
5 scope::Scope,
6 AsObject, PyObjectRef, PyRef, PyResult, VirtualMachine,
7};
8
9impl VirtualMachine {
10 pub fn compile(
11 &self,
12 source: &str,
13 mode: compiler::Mode,
14 source_path: String,
15 ) -> Result<PyRef<PyCode>, CompileError> {
16 self.compile_with_opts(source, mode, source_path, self.compile_opts())
17 }
18
19 pub fn compile_with_opts(
20 &self,
21 source: &str,
22 mode: compiler::Mode,
23 source_path: String,
24 opts: CompileOpts,
25 ) -> Result<PyRef<PyCode>, CompileError> {
26 compiler::compile(source, mode, source_path, opts).map(|code| self.ctx.new_code(code))
27 }
28
29 pub fn run_script(&self, scope: Scope, path: &str) -> PyResult<()> {
30 if get_importer(path, self)?.is_some() {
31 self.insert_sys_path(self.new_pyobj(path))?;
32 let runpy = self.import("runpy", 0)?;
33 let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?;
34 run_module_as_main.call((identifier!(self, __main__).to_owned(), false), self)?;
35 return Ok(());
36 }
37
38 let dir = std::path::Path::new(path)
39 .parent()
40 .unwrap()
41 .to_str()
42 .unwrap();
43 self.insert_sys_path(self.new_pyobj(dir))?;
44
45 match std::fs::read_to_string(path) {
46 Ok(source) => {
47 self.run_code_string(scope, &source, path.to_owned())?;
48 }
49 Err(err) => {
50 error!("Failed reading file '{}': {}", path, err);
51 std::process::exit(1);
53 }
54 }
55 Ok(())
56 }
57
58 pub fn run_code_string(&self, scope: Scope, source: &str, source_path: String) -> PyResult {
59 let code_obj = self
60 .compile(source, compiler::Mode::Exec, source_path.clone())
61 .map_err(|err| self.new_syntax_error(&err, Some(source)))?;
62 scope.globals.set_item(
64 identifier!(self, __file__),
65 self.new_pyobj(source_path),
66 self,
67 )?;
68 self.run_code_obj(code_obj, scope)
69 }
70
71 pub fn run_block_expr(&self, scope: Scope, source: &str) -> PyResult {
72 let code_obj = self
73 .compile(source, compiler::Mode::BlockExpr, "<embedded>".to_owned())
74 .map_err(|err| self.new_syntax_error(&err, Some(source)))?;
75 self.run_code_obj(code_obj, scope)
77 }
78}
79
80fn get_importer(path: &str, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
81 let path_importer_cache = vm.sys_module.get_attr("path_importer_cache", vm)?;
82 let path_importer_cache = PyDictRef::try_from_object(vm, path_importer_cache)?;
83 if let Some(importer) = path_importer_cache.get_item_opt(path, vm)? {
84 return Ok(Some(importer));
85 }
86 let path = vm.ctx.new_str(path);
87 let path_hooks = vm.sys_module.get_attr("path_hooks", vm)?;
88 let mut importer = None;
89 let path_hooks: Vec<PyObjectRef> = path_hooks.try_into_value(vm)?;
90 for path_hook in path_hooks {
91 match path_hook.call((path.clone(),), vm) {
92 Ok(imp) => {
93 importer = Some(imp);
94 break;
95 }
96 Err(e) if e.fast_isinstance(vm.ctx.exceptions.import_error) => continue,
97 Err(e) => return Err(e),
98 }
99 }
100 Ok(if let Some(imp) = importer {
101 let imp = path_importer_cache.get_or_insert(vm, path.into(), || imp.clone())?;
102 Some(imp)
103 } else {
104 None
105 })
106}