8000 Add "incognito" compilation · codefather-labs/RustPython@80f1146 · GitHub
[go: up one dir, main page]

Skip to content

Commit 80f1146

Browse files
committed
Add "incognito" compilation
1 parent 9925d5b commit 80f1146

File tree

11 files changed

+118
-40
lines changed

11 files changed

+118
-40
lines changed

bytecode/src/bytecode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub struct CodeObject {
4646
pub source_path: String,
4747
pub first_line_number: usize,
4848
pub obj_name: String, // Name of the object that created this code object
49+
pub incognito: bool,
4950
}
5051

5152
bitflags! {
@@ -393,6 +394,7 @@ impl CodeObject {
393394
source_path,
394395
first_line_number,
395396
obj_name,
397+
incognito: false,
396398
}
397399
}
398400

compiler/src/compile.rs

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,26 @@ struct Compiler<O: OutputStream = BasicOutputStream> {
3030
current_source_location: ast::Location,
3131
current_qualified_path: Option<String>,
3232
ctx: CompileContext,
33-
optimize: u8,
33+
opts: CompileOpts,
34+
}
35+
36+
#[derive(Debug, Clone)]
37+
pub struct CompileOpts {
38+
/// How optimized the bytecode output should be; any optimize > 0 does
39+
/// not emit assert statements
40+
pub optimize: u8,
41+
/// Whether introspection on defined functions/other items should be allowed;
42+
/// e.g. when true, `func.__globals__` throws an error (where func is a function defined
43+
/// in an incognito context)
44+
pub incognito: bool,
45+
}
46+
impl Default for CompileOpts {
47+
fn default() -> Self {
48+
CompileOpts {
49+
optimize: 0,
50+
incognito: false,
51+
}
52+
}
3453
}
3554

3655
#[derive(Clone, Copy)]
@@ -60,31 +79,31 @@ pub fn compile(
6079
source: &str,
6180
mode: Mode,
6281
source_path: String,
63-
optimize: u8,
82+
opts: CompileOpts,
6483
) -> CompileResult<CodeObject> {
6584
match mode {
6685
Mode::Exec => {
6786
let ast = parser::parse_program(source)?;
68-
compile_program(ast, source_path, optimize)
87+
compile_program(ast, source_path.clone(), opts)
6988
}
7089
Mode::Eval => {
7190
let statement = parser::parse_statement(source)?;
72-
compile_statement_eval(statement, source_path, optimize)
91+
compile_statement_eval(statement, source_path.clone(), opts)
7392
}
7493
Mode::Single => {
7594
let ast = parser::parse_program(source)?;
76-
compile_program_single(ast, source_path, optimize)
95+
compile_program_single(ast, source_path.clone(), opts)
7796
}
7897
}
7998
}
8099

81100
/// A helper function for the shared code of the different compile functions
82101
fn with_compiler(
83102
source_path: String,
84-
optimize: u8,
103+
opts: CompileOpts,
85104
f: impl FnOnce(&mut Compiler) -> CompileResult<()>,
86105
) -> CompileResult<CodeObject> {
87-
let mut compiler = Compiler::new(optimize);
106+
let mut compiler = Compiler::new(opts);
88107
compiler.source_path = Some(source_path);
89108
compiler.push_new_code_object("<module>".to_owned());
90109
f(&mut compiler)?;
@@ -97,9 +116,9 @@ fn with_compiler(
97116
pub fn compile_program(
98117
ast: ast::Program,
99118
source_path: String,
100-
optimize: u8,
119+
opts: CompileOpts,
101120
) -> CompileResult<CodeObject> {
102-
with_compiler(source_path, optimize, |compiler| {
121+
with_compiler(source_path, opts, |compiler| {
103122
let symbol_table = make_symbol_table(&ast)?;
104123
compiler.compile_program(&ast, symbol_table)
105124
})
@@ -109,9 +128,9 @@ pub fn compile_program(
109128
pub fn compile_statement_eval(
110129
statement: Vec<ast::Statement>,
111130
source_path: String,
112-
optimize: u8,
131+
opts: CompileOpts,
113132
) -> CompileResult<CodeObject> {
114-
with_compiler(source_path, optimize, |compiler| {
133+
with_compiler(source_path, opts, |compiler| {
115134
let symbol_table = statements_to_symbol_table(&statement)?;
116135
compiler.compile_statement_eval(&statement, symbol_table)
117136
})
@@ -121,9 +140,9 @@ pub fn compile_statement_eval(
121140
pub fn compile_program_single(
122141
ast: ast::Program,
123142
source_path: String,
124-
optimize: u8,
143+
opts: CompileOpts,
125144
) -> CompileResult<CodeObject> {
126-
with_compiler(source_path, optimize, |compiler| {
145+
with_compiler(source_path, opts, |compiler| {
127146
let symbol_table = 2358 make_symbol_table(&ast)?;
128147
compiler.compile_program_single(&ast, symbol_table)
129148
})
@@ -134,12 +153,12 @@ where
134153
O: OutputStream,
135154
{
136155
fn default() -> Self {
137-
Compiler::new(0)
156+
Compiler::new(CompileOpts::default())
138157
}
139158
}
140159

141160
impl<O: OutputStream> Compiler<O> {
142-
fn new(optimize: u8) -> Self {
161+
fn new(opts: CompileOpts) -> Self {
143162
Compiler {
144163
output_stack: Vec::new(),
145164
symbol_table_stack: Vec::new(),
@@ -151,7 +170,7 @@ impl<O: OutputStream> Compiler<O> {
151170
in_loop: false,
152171
func: FunctionContext::NoFunction,
153172
},
154-
optimize,
173+
opts,
155174
}
156175
}
157176

@@ -167,7 +186,8 @@ impl<O: OutputStream> Compiler<O> {
167186
}
168187
}
169188

170-
fn push_output(&mut self, code: CodeObject) {
189+
fn push_output(&mut self, mut code: CodeObject) {
190+
code.incognito = self.opts.incognito;
171191
self.output_stack.push(code.into());
172192
}
173193

@@ -518,7 +538,7 @@ impl<O: OutputStream> Compiler<O> {
518538
} => self.compile_class_def(name, body, bases, keywords, decorator_list)?,
519539
Assert { test, msg } => {
520540
// if some flag, ignore all assert statements!
521-
if self.optimize == 0 {
541+
if self.opts.optimize == 0 {
522542
let end_label = self.new_label();
523543
self.compile_jump_if(test, true, end_label)?;
524544
self.emit(Instruction::LoadName {

derive/src/compile_bytecode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl CompilationSource {
4949
module_name: String,
5050
origin: F,
5151
) -> Result<CodeObject, Diagnostic> {
52-
compile::compile(source, mode, module_name, 0).map_err(|err| {
52+
compile::compile(source, mode, module_name, Default::default()).map_err(|err| {
5353
Diagnostic::spans_error(
5454
self.span,
5555
format!("Python compile error from {}: {}", origin(), err),

examples/dis.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,14 @@ fn main() {
6262
let optimize = matches.occurrences_of("optimize") as u8;
6363
let scripts = matches.values_of_os("scripts").unwrap();
6464

65+
let opts = compile::CompileOpts {
66+
optimize,
67+
..Default::default()
68+
};
69+
6570
for script in scripts.map(Path::new) {
6671
if script.exists() && script.is_file() {
67-
let res = display_script(script, mode, optimize, expand_codeobjects);
72+
let res = display_script(script, mode, opts.clone(), expand_codeobjects);
6873
if let Err(e) = res {
6974
error!("Error while compiling {:?}: {}", script, e);
7075
}
@@ -77,11 +82,11 @@ fn main() {
7782
fn display_script(
7883
path: &Path,
7984
mode: compile::Mode,
80-
optimize: u8,
85+
opts: compile::CompileOpts,
8186
expand_codeobjects: bool,
8287
) -> Result<(), Box<dyn Error>> {
8388
let source = fs::read_to_string(path)?;
84-
let code = compile::compile(&source, mode, path.to_string_lossy().into_owned(), optimize)?;
89+
let code = compile::compile(&source, mode, path.to_string_lossy().into_owned(), opts)?;
8590
println!("{}:", path.display());
8691
if expand_codeobjects {
8792
println!("{}", code.display_expand_codeobjects());

tests/snippets/function.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def foo():
1313
assert foo.__name__ == "foo"
1414
assert foo.__qualname__ == "foo"
1515
assert foo.__module__ == "function"
16+
assert foo.__globals__ is globals()
1617

1718
def my_func(a,):
1819
return a+2

vm/src/import.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,8 @@ pub fn import_file(
7474
file_path: String,
7575
content: String,
7676
) -> PyResult {
77-
let code_obj = compile::compile(
78-
&content,
79-
compile::Mode::Exec,
80-
file_path,
81-
vm.settings.optimize,
82-
)
83-
.map_err(|err| vm.new_syntax_error(&err))?;
77+
let code_obj = compile::compile(&content, compile::Mode::Exec, file_path, vm.compile_opts())
78+
.map_err(|err| vm.new_syntax_error(&err))?;
8479
import_codeobj(vm, module_name, code_obj, true)
8580
}
8681

vm/src/obj/objframe.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,21 @@ impl FrameRef {
3030
}
3131

3232
#[pyproperty]
33-
fn f_globals(self) -> PyDictRef {
34-
self.scope.globals.clone()
33+
fn f_globals(self, vm: &VirtualMachine) -> PyResult<PyDictRef> {
34+
if self.code.incognito {
35+
Err(vm.new_type_error("Can't get f_globals on an incognito frame".to_owned()))
36+
} else {
37+
Ok(self.scope.globals.clone())
38+
}
3539
}
3640

3741
#[pyproperty]
38-
fn f_locals(self) -> PyDictRef {
39-
self.scope.get_locals()
42+
fn f_locals(self, vm: &VirtualMachine) -> PyResult<PyDictRef> {
43+
if self.code.incognito {
44+
Err(vm.new_type_error("Can't get f_locals on an incognito frame".to_owned()))
45+
} else {
46+
Ok(self.scope.get_locals())
47+
}
4048
}
4149

4250
#[pyproperty]

vm/src/obj/objfunction.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,15 @@ impl PyFunction {
278278
fn kwdefaults(&self) -> Option<PyDictRef> {
279279
self.kw_only_defaults.clone()
280280
}
281+
282+
#[pyproperty(magic)]
283+
fn globals(&self, vm: &VirtualMachine) -> PyResult<PyDictRef> {
284+
if self.code.incognito {
285+
Err(vm.new_type_error("Can't get __globals__ on an incognito function".to_owned()))
286+
} else {
287+
Ok(self.scope.globals.clone())
288+
}
289+
}
281290
}
282291

283292
#[pyclass]

vm/src/vm.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use num_bigint::BigInt;
1717
use num_traits::ToPrimitive;
1818
use once_cell::sync::Lazy;
1919
#[cfg(feature = "rustpython-compiler")]
20-
use rustpython_compiler::{compile, error::CompileError};
20+
use rustpython_compiler::{
21+
compile::{self, CompileOpts},
22+
error::CompileError,
23+
};
2124

2225
use crate::builtins::{self, to_ascii};
2326
use crate::bytecode;
@@ -1000,14 +1003,35 @@ impl VirtualMachine {
10001003
}
10011004
}
10021005

1006+
/// Returns a basic CompileOpts instance with options accurate to the vm. Used
1007+
/// as the CompileOpts for `vm.compile()`.
1008+
#[cfg(feature = "rustpython-compiler")]
1009+
pub fn compile_opts(&self) -> CompileOpts {
1010+
CompileOpts {
1011+
optimize: self.settings.optimize,
1012+
..Default::default()
1013+
}
1014+
}
1015+
10031016
#[cfg(feature = "rustpython-compiler")]
10041017
pub fn compile(
10051018
&self,
10061019
source: &str,
10071020
mode: compile::Mode,
10081021
source_path: String,
10091022
) -> Result<PyCodeRef, CompileError> {
1010-
compile::compile(source, mode, source_path, self.settings.optimize)
1023+
self.compile_with_opts(source, mode, source_path, self.compile_opts())
1024+
}
1025+
1026+
#[cfg(feature = "rustpython-compiler")]
1027+
pub fn compile_with_opts(
1028+
&self,
1029+
source: &str,
1030+
mode: compile::Mode,
1031+
source_path: String,
1032+
opts: CompileOpts,
1033+
) -> Result<PyCodeRef, CompileError> {
1034+
compile::compile(source, mode, source_path, opts)
10111035
.map(|codeobj| PyCode::new(codeobj).into_ref(self))
10121036
.map_err(|mut compile_error| {
10131037
compile_error.update_statement_info(source.trim_end().to_owned());

wasm/lib/src/vm_class.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,13 @@ impl WASMVirtualMachine {
263263
strict_private: Option<bool>,
264264
) -> Result<(), JsValue> {
265265
self.with(|StoredVirtualMachine { ref vm, .. }| {
266+
let strict_private = strict_private.unwrap_or(false);
267+
let opts = compile::CompileOpts {
268+
incognito: strict_private,
269+
..vm.compile_opts()
270+
};
266271
let code = vm
267-
.compile(source, Mode::Exec, name.clone())
272+
.compile_with_opts(source, Mode::Exec, name.clone(), opts)
268273
.map_err(convert::syntax_err)?;
269274
let attrs = vm.ctx.new_dict();
270275
attrs
@@ -282,7 +287,7 @@ impl WASMVirtualMachine {
282287
vm.run_code_obj(code, Scope::new(None, attrs.clone(), vm))
283288
.to_js(vm)?;
284289

285-
let module_attrs = if strict_private.unwrap_or(false) {
290+
let module_attrs = if strict_private {
286291
let all = attrs
287292
.get_item_option("__all__", vm)
288293
.to_js(vm)?

0 commit comments

Comments
 (0)
0