Skip to content

Commit 48b0a17

Browse files
committed
Merge branch 'master' into coolreader18/proc-macro-span-errors
2 parents dc63fc8 + 615a121 commit 48b0a17

16 files changed

+212
-131
lines changed

src/main.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,8 @@ fn main() {
6565
}
6666

6767
fn _run_string(vm: &VirtualMachine, source: &str, source_path: String) -> PyResult {
68-
let code_obj =
69-
compile::compile(vm, source, &compile::Mode::Exec, source_path).map_err(|err| {
70-
let syntax_error = vm.context().exceptions.syntax_error.clone();
71-
vm.new_exception(syntax_error, err.to_string())
72-
})?;
68+
let code_obj = compile::compile(vm, source, &compile::Mode::Exec, source_path)
69+
.map_err(|err| vm.new_syntax_error(&err))?;
7370
// trace!("Code object: {:?}", code_obj.borrow());
7471
let vars = vm.ctx.new_scope(); // Keep track of local variables
7572
vm.run_code_obj(code_obj, vars)
@@ -120,8 +117,7 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> Result<(), Com
120117
// Don't inject syntax errors for line continuation
121118
Err(err @ CompileError::Parse(ParseError::EOF(_))) => Err(err),
122119
Err(err) => {
123-
let syntax_error = vm.context().exceptions.syntax_error.clone();
124-
let exc = vm.new_exception(syntax_error, format!("{}", err));
120+
let exc = vm.new_syntax_error(&err);
125121
print_exception(vm, &exc);
126122
Err(err)
127123
}

tests/snippets/builtin_slice.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
b = [1, 2]
1212

1313
assert b[:] == [1, 2]
14+
assert b[slice(None)] == [1, 2]
1415
assert b[: 2 ** 100] == [1, 2]
1516
assert b[-2 ** 100 :] == [1, 2]
1617
assert b[2 ** 100 :] == []
@@ -60,6 +61,12 @@
6061
assert slice_c.stop == 5
6162
assert slice_c.step == 2
6263

64+
a = object()
65+
slice_d = slice(a, "v", 1.0)
66+
assert slice_d.start is a
67+
assert slice_d.stop == "v"
68+
assert slice_d.step == 1.0
69+
6370

6471
class SubScript(object):
6572
def __getitem__(self, item):
@@ -74,6 +81,18 @@ def __setitem__(self, key, value):
7481
ss[:1] = 1
7582

7683

84+
class CustomIndex:
85+
def __init__(self, x):
86+
self.x = x
87+
88+
def __index__(self):
89+
return self.x
90+
91+
92+
assert c[CustomIndex(1):CustomIndex(3)] == [1, 2]
93+
assert d[CustomIndex(1):CustomIndex(3)] == "23"
94+
95+
7796
def test_all_slices():
7897
"""
7998
test all possible slices except big number

tests/snippets/global_nonlocal.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ def b():
1111
b()
1212
assert a == 4
1313

14+
def x():
15+
def y():
16+
nonlocal b
17+
b = 3
18+
b = 2
19+
y()
20+
return b
21+
22+
res = x()
23+
assert res == 3, str(res)

tests/snippets/import.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from import_target import func as aliased_func, other_func as aliased_other_func
44
from import_star import *
55

6+
import import_mutual1
67
assert import_target.X == import_target.func()
78
assert import_target.X == func()
89

tests/snippets/import_mutual1.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Mutual recursive import:
3+
import import_mutual2
4+

tests/snippets/import_mutual2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
# Mutual recursive import:
3+
import import_mutual1

tests/snippets/stdlib_os.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ def __exit__(self, exc_type, exc_val, exc_tb):
5151
assert ENV_KEY in os.environ
5252
assert os.getenv(ENV_KEY) == ENV_VALUE
5353
del os.environ[ENV_KEY]
54-
os.unsetenv(ENV_KEY)
5554
assert ENV_KEY not in os.environ
5655
assert os.getenv(ENV_KEY) == None
56+
57+
if os.name == "posix":
58+
os.putenv(ENV_KEY, ENV_VALUE)
59+
os.unsetenv(ENV_KEY)
60+
assert os.getenv(ENV_KEY) == None

vm/src/bytecode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub type Label = usize;
4141
#[derive(Debug, Clone, PartialEq)]
4242
pub enum NameScope {
4343
Local,
44+
NonLocal,
4445
Global,
4546
}
4647

vm/src/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,12 @@ impl Compiler {
179179
let role = self.lookup_name(name);
180180
match role {
181181
SymbolRole::Global => bytecode::NameScope::Global,
182+
SymbolRole::Nonlocal => bytecode::NameScope::NonLocal,
182183
_ => bytecode::NameScope::Local,
183184
}
184185
}
185186

186187
fn load_name(&mut self, name: &str) {
187-
// TODO: if global, do something else!
188188
let scope = self.scope_for_name(name);
189189
self.emit(Instruction::LoadName {
190190
name: name.to_string(),

vm/src/frame.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::cell::RefCell;
22
use std::fmt;
33
use std::rc::Rc;
44

5-
use num_bigint::BigInt;
6-
75
use rustpython_parser::ast;
86

97
use crate::builtins;
@@ -12,7 +10,6 @@ use crate::function::PyFuncArgs;
1210
use crate::obj::objbool;
1311
use crate::obj::objcode::PyCodeRef;
1412
use crate::obj::objdict::{PyDict, PyDictRef};
15-
use crate::obj::objint::PyInt;
1613
use crate::obj::objiter;
1714
use crate::obj::objlist;
1815
use crate::obj::objslice::PySlice;
@@ -129,6 +126,7 @@ pub trait NameProtocol {
129126
fn store_name(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
130127
fn delete_name(&self, vm: &VirtualMachine, name: &str);
131128
fn load_cell(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
129+
fn store_cell(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
132130
fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef>;
133131
fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef);
134132
}
@@ -157,6 +155,16 @@ impl NameProtocol for Scope {
157155
None
158156
}
159157

158+
fn store_cell(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef) {
159+
self.locals
160+
.iter()
161+
.skip(1)
162+
.next()
163+
.expect("no outer scope for non-local")
164+
.set_item(name, value, vm)
165+
.unwrap();
166+
}
167+
160168
fn store_name(&self, vm: &VirtualMachine, key: &str, value: PyObjectRef) {
161169
self.get_locals().set_item(key, value, vm).unwrap();
162170
}
@@ -435,26 +443,21 @@ impl Frame {
435443
}
436444
bytecode::Instruction::BuildSlice { size } => {
437445
assert!(*size == 2 || *size == 3);
438-
let elements = self.pop_multiple(*size);
439446

440-
let mut out: Vec<Option<BigInt>> = elements
441-
.into_iter()
442-
.map(|x| {
443-
if x.is(&vm.ctx.none()) {
444-
None
445-
} else if let Some(i) = x.payload::<PyInt>() {
446-
Some(i.as_bigint().clone())
447-
} else {
448-
panic!("Expect Int or None as BUILD_SLICE arguments")
449-
}
450-
})
451-
.collect();
452-
453-
let start = out[0].take();
454-
let stop = out[1].take();
455-
let step = if out.len() == 3 { out[2].take() } else { None };
447+
let step = if *size == 3 {
448+
Some(self.pop_value())
449+
} else {
450+
None
451+
};
452+
let stop = self.pop_value();
453+
let start = self.pop_value();
456454

457-
let obj = PySlice { start, stop, step }.into_ref(vm);
455+
let obj = PySlice {
456+
start: Some(start),
457+
stop,
458+
step,
459+
}
460+
.into_ref(vm);
458461
self.push_value(obj.into_object());
459462
Ok(None)
460463
}
@@ -1037,8 +1040,11 @@ impl Frame {
10371040
bytecode::NameScope::Global => {
10381041
self.scope.store_global(vm, name, obj);
10391042
}
1043+
bytecode::NameScope::NonLocal => {
1044+
self.scope.store_cell(vm, name, obj);
1045+
}
10401046
bytecode::NameScope::Local => {
1041-
self.scope.store_name(&vm, name, obj);
1047+
self.scope.store_name(vm, name, obj);
10421048
}
10431049
}
10441050
Ok(None)
@@ -1057,6 +1063,7 @@ impl Frame {
10571063
) -> FrameResult {
10581064
let optional_value = match name_scope {
10591065
bytecode::NameScope::Global => self.scope.load_global(vm, name),
1066+
bytecode::NameScope::NonLocal => self.scope.load_cell(vm, name),
10601067
bytecode::NameScope::Local => self.scope.load_name(&vm, name),
10611068
};
10621069

vm/src/function.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::HashMap;
2+
use std::mem;
23
use std::ops::RangeInclusive;
34

45
use crate::obj::objtype::{isinstance, PyClassRef};
@@ -48,6 +49,12 @@ impl From<(&Args, &KwArgs)> for PyFuncArgs {
4849
}
4950
}
5051

52+
impl FromArgs for PyFuncArgs {
53+
fn from_args(_vm: &VirtualMachine, args: &mut PyFuncArgs) -> Result<Self, ArgumentError> {
54+
Ok(mem::replace(args, Default::default()))
55+
}
56+
}
57+
5158
impl PyFuncArgs {
5259
pub fn new(mut args: Vec<PyObjectRef>, kwarg_names: Vec<String>) -> PyFuncArgs {
5360
let mut kwargs = vec![];

vm/src/import.rs

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,47 @@ use crate::pyobject::{ItemProtocol, PyResult};
1111
use crate::util;
1212
use crate::vm::VirtualMachine;
1313

14-
fn import_uncached_module(vm: &VirtualMachine, current_path: PathBuf, module: &str) -> PyResult {
15-
// Check for Rust-native modules
16-
if let Some(module) = vm.stdlib_inits.borrow().get(module) {
17-
return Ok(module(vm).clone());
18-
}
14+
pub fn import_module(vm: &VirtualMachine, current_path: PathBuf, module_name: &str) -> PyResult {
15+
// Cached modules:
16+
let sys_modules = vm.get_attribute(vm.sys_module.clone(), "modules").unwrap();
1917

20-
let notfound_error = vm.context().exceptions.module_not_found_error.clone();
21-
let import_error = vm.context().exceptions.import_error.clone();
18+
// First, see if we already loaded the module:
19+
if let Ok(module) = sys_modules.get_item(module_name.to_string(), vm) {
20+
Ok(module)
21+
} else if let Some(make_module_func) = vm.stdlib_inits.borrow().get(module_name) {
22+
let module = make_module_func(vm);
23+
sys_modules.set_item(module_name, module.clone(), vm)?;
24+
Ok(module)
25+
} else {
26+
let notfound_error = vm.context().exceptions.module_not_found_error.clone();
27+
let import_error = vm.context().exceptions.import_error.clone();
2228

23-
// Time to search for module in any place:
24-
let file_path = find_source(vm, current_path, module)
25-
.map_err(|e| vm.new_exception(notfound_error.clone(), e))?;
26-
let source = util::read_file(file_path.as_path())
27-
.map_err(|e| vm.new_exception(import_error.clone(), e.to_string()))?;
28-
let code_obj = compile::compile(
29-
vm,
30-
&source,
31-
&compile::Mode::Exec,
32-
file_path.to_str().unwrap().to_string(),
33-
)
34-
.map_err(|err| vm.new_syntax_error(&err))?;
35-
// trace!("Code object: {:?}", code_obj);
29+
// Time to search for module in any place:
30+
let file_path = find_source(vm, current_path, module_name)
31+
.map_err(|e| vm.new_exception(notfound_error.clone(), e))?;
32+
let source = util::read_file(file_path.as_path())
33+
.map_err(|e| vm.new_exception(import_error.clone(), e.to_string()))?;
34+
let code_obj = compile::compile(
35+
vm,
36+
&source,
37+
&compile::Mode::Exec,
38+
file_path.to_str().unwrap().to_string(),
39+
)
40+
.map_err(|err| vm.new_syntax_error(&err))?;
41+
// trace!("Code object: {:?}", code_obj);
3642

37-
let attrs = vm.ctx.new_dict();
38-
attrs.set_item("__name__", vm.new_str(module.to_string()), vm)?;
39-
vm.run_code_obj(code_obj, Scope::new(None, attrs.clone()))?;
40-
Ok(vm.ctx.new_module(module, attrs))
41-
}
43+
let attrs = vm.ctx.new_dict();
44+
attrs.set_item("__name__", vm.new_str(module_name.to_string()), vm)?;
45+
let module = vm.ctx.new_module(module_name, attrs.clone());
4246

43-
pub fn import_module(vm: &VirtualMachine, current_path: PathBuf, module_name: &str) -> PyResult {
44-
// First, see if we already loaded the module:
45-
let sys_modules = vm.get_attribute(vm.sys_module.clone(), "modules")?;
46-
if let Ok(module) = sys_modules.get_item(module_name.to_string(), vm) {
47-
return Ok(module);
47+
// Store module in cache to prevent infinite loop with mutual importing libs:
48+
sys_modules.set_item(module_name, module.clone(), vm)?;
49+
50+
// Execute main code in module:
51+
vm.run_code_obj(code_obj, Scope::new(None, attrs))?;
52+
53+
Ok(module)
4854
}
49-
let module = import_uncached_module(vm, current_path, module_name)?;
50-
sys_modules.set_item(module_name, module.clone(), vm)?;
51-
Ok(module)
5255
}
5356

5457
fn find_source(vm: &VirtualMachine, current_path: PathBuf, name: &str) -> Result<PathBuf, String> {

vm/src/obj/objlist.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ impl PyListRef {
210210
}
211211

212212
fn setslice(self, slice: PySliceRef, sec: PyIterable, vm: &VirtualMachine) -> PyResult {
213-
let step = slice.step.clone().unwrap_or_else(BigInt::one);
213+
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
214214

215215
if step.is_zero() {
216216
Err(vm.new_value_error("slice step cannot be zero".to_string()))
217217
} else if step.is_positive() {
218-
let range = self.get_slice_range(&slice.start, &slice.stop);
218+
let range = self.get_slice_range(&slice.start_index(vm)?, &slice.stop_index(vm)?);
219219
if range.start < range.end {
220220
match step.to_i32() {
221221
Some(1) => self._set_slice(range, sec, vm),
@@ -237,14 +237,14 @@ impl PyListRef {
237237
} else {
238238
// calculate the range for the reverse slice, first the bounds needs to be made
239239
// exclusive around stop, the lower number
240-
let start = &slice.start.as_ref().map(|x| {
240+
let start = &slice.start_index(vm)?.as_ref().map(|x| {
241241
if *x == (-1).to_bigint().unwrap() {
242242
self.get_len() + BigInt::one() //.to_bigint().unwrap()
243243
} else {
244244
x + 1
245245
}
246246
});
247-
let stop = &slice.stop.as_ref().map(|x| {
247+
let stop = &slice.stop_index(vm)?.as_ref().map(|x| {
248248
if *x == (-1).to_bigint().unwrap() {
249249
self.get_len().to_bigint().unwrap()
250250
} else {
@@ -552,9 +552,9 @@ impl PyListRef {
552552
}
553553

554554
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult {
555-
let start = &slice.start;
556-
let stop = &slice.stop;
557-
let step = slice.step.clone().unwrap_or_else(BigInt::one);
555+
let start = slice.start_index(vm)?;
556+
let stop = slice.stop_index(vm)?;
557+
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
558558

559559
if step.is_zero() {
560560
Err(vm.new_value_error("slice step cannot be zero".to_string()))

0 commit comments

Comments
 (0)