From ae8dc46947aa1d6d3bd747065b68c9b1b99c8157 Mon Sep 17 00:00:00 2001 From: Nick Hynes Date: Wed, 13 Feb 2019 23:22:03 +0000 Subject: [PATCH 01/80] Allow compiling VM for wasm32-unknown-unknown --- src/main.rs | 4 ++-- vm/src/stdlib/os.rs | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6ac2a0417..b7d70d0be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -134,13 +134,13 @@ fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool true } -#[cfg(not(target_family = "unix"))] +#[cfg(not(unix))] fn get_history_path() -> PathBuf { //Path buffer PathBuf::from(".repl_history.txt") } -#[cfg(target_family = "unix")] +#[cfg(unix)] fn get_history_path() -> PathBuf { //work around for windows dependent builds. The xdg crate is unix specific //so access to the BaseDirectories struct breaks builds on python. diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 83e770f2c..fcb27b0a9 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -16,28 +16,28 @@ use super::super::obj::objtype; use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use super::super::vm::VirtualMachine; -#[cfg(target_family = "unix")] +#[cfg(unix)] pub fn raw_file_number(handle: File) -> i64 { use std::os::unix::io::IntoRawFd; i64::from(handle.into_raw_fd()) } -#[cfg(target_family = "unix")] +#[cfg(unix)] pub fn rust_file(raw_fileno: i64) -> File { use std::os::unix::io::FromRawFd; unsafe { File::from_raw_fd(raw_fileno as i32) } } -#[cfg(target_family = "windows")] +#[cfg(windows)] pub fn raw_file_number(handle: File) -> i64 { use std::os::windows::io::IntoRawHandle; handle.into_raw_handle() as i64 } -#[cfg(target_family = "windows")] +#[cfg(windows)] pub fn rust_file(raw_fileno: i64) -> File { use std::ffi::c_void; use std::os::windows::io::FromRawHandle; @@ -46,6 +46,16 @@ pub fn rust_file(raw_fileno: i64) -> File { unsafe { File::from_raw_handle(raw_fileno as *mut c_void) } } +#[cfg(all(not(unix), not(windows)))] +pub fn rust_file(raw_fileno: i64) -> File { + unimplemented!(); +} + +#[cfg(all(not(unix), not(windows)))] +pub fn raw_file_number(handle: File) -> i64 { + unimplemented!(); +} + pub fn os_close(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(fileno, Some(vm.ctx.int_type()))]); From f1654cb89035cb7cc29ee273d2fd8b852ece9436 Mon Sep 17 00:00:00 2001 From: ZapAnton Date: Wed, 13 Feb 2019 11:55:06 +0300 Subject: [PATCH 02/80] Migrated the project to the Rust 2018 edition --- Cargo.toml | 1 + parser/Cargo.toml | 1 + parser/build.rs | 2 +- parser/src/error.rs | 4 ++-- parser/src/lexer.rs | 14 +++++++------- parser/src/lib.rs | 3 --- parser/src/parser.rs | 2 -- py_code_object/Cargo.toml | 1 + py_code_object/python_compiler/Cargo.toml | 1 + vm/Cargo.toml | 1 + vm/src/import.rs | 2 +- vm/src/stdlib/random.rs | 2 +- vm/src/sysmodule.rs | 6 +++--- wasm/lib/Cargo.toml | 1 + 14 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 92213e8cb..a1f366cd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "rustpython" version = "0.0.1" authors = ["Windel Bouwman", "Shing Lyu "] +edition = "2018" [workspace] members = [".", "vm", "wasm/lib", "parser"] diff --git a/parser/Cargo.toml b/parser/Cargo.toml index d914a98a6..e57d42140 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -3,6 +3,7 @@ name = "rustpython_parser" version = "0.0.1" authors = [ "Shing Lyu", "Windel Bouwman" ] build = "build.rs" +edition = "2018" [build-dependencies] lalrpop="0.15.1" diff --git a/parser/build.rs b/parser/build.rs index 23c7d3f80..d35ace0c0 100644 --- a/parser/build.rs +++ b/parser/build.rs @@ -1,4 +1,4 @@ -extern crate lalrpop; +use lalrpop; fn main() { lalrpop::process_root().unwrap(); diff --git a/parser/src/error.rs b/parser/src/error.rs index f40d2abad..5239911d4 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -3,8 +3,8 @@ extern crate lalrpop_util; use self::lalrpop_util::ParseError as InnerError; -use lexer::{LexicalError, Location}; -use token::Tok; +use crate::lexer::{LexicalError, Location}; +use crate::token::Tok; use std::error::Error; use std::fmt; diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index f48c48d49..c13ad70ab 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -541,7 +541,7 @@ where fn is_char(&self) -> bool { match self.chr0 { - Some('a'...'z') | Some('A'...'Z') | Some('_') | Some('0'...'9') => true, + Some('a'..='z') | Some('A'..='Z') | Some('_') | Some('0'..='9') => true, _ => false, } } @@ -549,19 +549,19 @@ where fn is_number(&self, radix: u32) -> bool { match radix { 2 => match self.chr0 { - Some('0'...'1') => true, + Some('0'..='1') => true, _ => false, }, 8 => match self.chr0 { - Some('0'...'7') => true, + Some('0'..='7') => true, _ => false, }, 10 => match self.chr0 { - Some('0'...'9') => true, + Some('0'..='9') => true, _ => false, }, 16 => match self.chr0 { - Some('0'...'9') | Some('a'...'f') | Some('A'...'F') => true, + Some('0'..='9') | Some('a'..='f') | Some('A'..='F') => true, _ => false, }, x => unimplemented!("Radix not implemented: {}", x), @@ -686,8 +686,8 @@ where } match self.chr0 { - Some('0'...'9') => return Some(self.lex_number()), - Some('_') | Some('a'...'z') | Some('A'...'Z') => return Some(self.lex_identifier()), + Some('0'..='9') => return Some(self.lex_number()), + Some('_') | Some('a'..='z') | Some('A'..='Z') => return Some(self.lex_identifier()), Some('#') => { self.lex_comment(); continue; diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 8deba2c41..f7f369968 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -1,9 +1,6 @@ #[macro_use] extern crate log; -extern crate num_bigint; -extern crate num_traits; - pub mod ast; pub mod error; pub mod lexer; diff --git a/parser/src/parser.rs b/parser/src/parser.rs index ae7f88f31..a5380017d 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -1,5 +1,3 @@ -extern crate lalrpop_util; - use std::iter; use super::ast; diff --git a/py_code_object/Cargo.toml b/py_code_object/Cargo.toml index 59e1e3efe..abb2d7832 100644 --- a/py_code_object/Cargo.toml +++ b/py_code_object/Cargo.toml @@ -2,6 +2,7 @@ name = "py_code_object" version = "0.1.0" authors = ["Shing Lyu "] +edition = "2018" [dependencies] log = "0.3" diff --git a/py_code_object/python_compiler/Cargo.toml b/py_code_object/python_compiler/Cargo.toml index 505bc8f4f..1a301ee87 100644 --- a/py_code_object/python_compiler/Cargo.toml +++ b/py_code_object/python_compiler/Cargo.toml @@ -2,6 +2,7 @@ name = "python_compiler" version = "0.1.0" authors = ["Shing Lyu "] +edition = "2018" [dependencies] cpython = { git = "https://github.com/dgrunwald/rust-cpython.git" } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 0dc048c8c..f0ab63aab 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -2,6 +2,7 @@ name = "rustpython_vm" version = "0.1.0" authors = ["Shing Lyu "] +edition = "2018" [dependencies] bitflags = "1.0.4" diff --git a/vm/src/import.rs b/vm/src/import.rs index c127a8149..42ab0e25f 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -9,7 +9,7 @@ use super::compile; use super::pyobject::{DictProtocol, PyResult}; use super::util; use super::vm::VirtualMachine; -use obj::{objsequence, objstr}; +use crate::obj::{objsequence, objstr}; fn import_uncached_module( vm: &mut VirtualMachine, diff --git a/vm/src/stdlib/random.rs b/vm/src/stdlib/random.rs index a6952be51..417cf8fa2 100644 --- a/vm/src/stdlib/random.rs +++ b/vm/src/stdlib/random.rs @@ -5,7 +5,7 @@ extern crate rand; use super::super::obj::{objfloat, objtype}; use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use super::super::VirtualMachine; -use stdlib::random::rand::distributions::{Distribution, Normal}; +use crate::stdlib::random::rand::distributions::{Distribution, Normal}; pub fn mk_module(ctx: &PyContext) -> PyObjectRef { let py_mod = ctx.new_module(&"random".to_string(), ctx.new_scope(None)); diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index e5c701fd6..e7aad4430 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -1,8 +1,8 @@ -use obj::objtype; -use pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::obj::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; use std::rc::Rc; use std::{env, mem}; -use vm::VirtualMachine; /* * The magic sys module. diff --git a/wasm/lib/Cargo.toml b/wasm/lib/Cargo.toml index 6c78e0640..ac5da7450 100644 --- a/wasm/lib/Cargo.toml +++ b/wasm/lib/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Ryan Liddle "] license = "MIT" description = "A Python-3 (CPython >= 3.5.0) Interpreter written in Rust, compiled to WASM" repository = "https://github.com/RustPython/RustPython/tree/master/wasm/lib" +edition = "2018" [lib] crate-type = ["cdylib", "rlib"] From f45f307a555c2e4653d1d04d3df380e51589f76b Mon Sep 17 00:00:00 2001 From: janczer Date: Fri, 15 Feb 2019 09:10:09 +0100 Subject: [PATCH 03/80] Add copy method to list object --- tests/snippets/set.py | 7 +++++++ vm/src/obj/objset.rs | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index efc070f54..b6466d1c4 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -83,3 +83,10 @@ except TypeError: else: assert False, "TypeError was not raised" +a = set([1,2,3]) +b = a.copy() +assert len(a) == 3 +assert len(b) == 3 +b.clear() +assert len(a) == 3 +assert len(b) == 0 diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 537378379..c1b457300 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -152,6 +152,13 @@ fn set_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.context().new_int(elements.len())) } +fn set_copy(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + trace!("set.copy called with: {:?}", args); + arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]); + let elements = get_elements(s); + Ok(PyObject::new(PyObjectPayload::Set { elements }, vm.ctx.set_type())) +} + fn set_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.set_type()))]); @@ -450,6 +457,7 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "add", context.new_rustfunc(set_add)); context.set_attr(&set_type, "remove", context.new_rustfunc(set_remove)); context.set_attr(&set_type, "clear", context.new_rustfunc(set_clear)); + context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy)); let frozenset_type = &context.frozenset_type; From 1e92bb892e6645a26fd4b52f1ff056da0d414c3f Mon Sep 17 00:00:00 2001 From: janczer Date: Fri, 15 Feb 2019 19:47:53 +0100 Subject: [PATCH 04/80] Fix fmt in set.copy --- vm/src/obj/objset.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index c1b457300..dc1f2b344 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -156,7 +156,10 @@ fn set_copy(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("set.copy called with: {:?}", args); arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]); let elements = get_elements(s); - Ok(PyObject::new(PyObjectPayload::Set { elements }, vm.ctx.set_type())) + Ok(PyObject::new( + PyObjectPayload::Set { elements }, + vm.ctx.set_type(), + )) } fn set_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { From bf19d652dc1b488b8a2d711687bfc7e99e21ec13 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Fri, 15 Feb 2019 19:58:03 +0100 Subject: [PATCH 05/80] Fix issue with equality --- tests/snippets/list.py | 4 ++++ vm/src/vm.rs | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index 749d6c2bc..bd69b5d30 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -88,3 +88,7 @@ except ValueError: pass else: assert False, "Remove not exist element should raise ValueError" + +x = [1] +x.append(x) +assert x in x diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 45b88e45d..374f44923 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -608,9 +608,13 @@ impl VirtualMachine { } pub fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, a, b| { - Ok(vm.new_bool(a.is(&b))) - }) + if a.is(&b) { + Ok(self.new_bool(true)) + } else { + self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, _, _| { + Ok(vm.new_bool(false)) + }) + } } pub fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { From 5d82e2c6b57eaa22b1baa10e919902b0d5e5983e Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 12:42:43 +0100 Subject: [PATCH 06/80] Fix equality check in list_count, list_index and list_contains --- tests/snippets/list.py | 18 ++++++++++++++++++ vm/src/obj/objlist.rs | 16 +++++++++++++--- vm/src/vm.rs | 10 +++------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index bd69b5d30..5474326e2 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -92,3 +92,21 @@ else: x = [1] x.append(x) assert x in x +assert x.index(x) == 1 +assert x.count(x) == 1 + +class Foo(object): + def __eq__(self, x): + return False + +foo = Foo() +foo1 = Foo() +x = [1, foo, 2, foo, []] +assert foo in x +assert 2 in x +assert x.index(foo) == 1 +assert x.count(foo) == 2 +assert x.index(2) == 2 +assert [] in x +assert x.index([]) == 4 +assert foo1 not in x diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 1c09794fc..68dec4536 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -1,5 +1,5 @@ use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::{ReprGuard, VirtualMachine}; use super::objbool; @@ -234,9 +234,13 @@ fn list_count(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let elements = get_elements(zelf); let mut count: usize = 0; for element in elements.iter() { - let is_eq = vm._eq(element.clone(), value.clone())?; - if objbool::boolval(vm, is_eq)? { + if value.is(&element) { count += 1; + } else { + let is_eq = vm._eq(element.clone(), value.clone())?; + if objbool::boolval(vm, is_eq)? { + count += 1; + } } } Ok(vm.context().new_int(count)) @@ -262,6 +266,9 @@ fn list_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(list, Some(vm.ctx.list_type())), (needle, None)] ); for (index, element) in get_elements(list).iter().enumerate() { + if needle.is(&element) { + return Ok(vm.context().new_int(index)); + } let py_equal = vm._eq(needle.clone(), element.clone())?; if objbool::get_value(&py_equal) { return Ok(vm.context().new_int(index)); @@ -335,6 +342,9 @@ fn list_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(list, Some(vm.ctx.list_type())), (needle, None)] ); for element in get_elements(list).iter() { + if needle.is(&element) { + return Ok(vm.new_bool(true)); + } match vm._eq(needle.clone(), element.clone()) { Ok(value) => { if objbool::get_value(&value) { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 374f44923..45b88e45d 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -608,13 +608,9 @@ impl VirtualMachine { } pub fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - if a.is(&b) { - Ok(self.new_bool(true)) - } else { - self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, _, _| { - Ok(vm.new_bool(false)) - }) - } + self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, a, b| { + Ok(vm.new_bool(a.is(&b))) + }) } pub fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { From 117c6c8494fa297f7c92a6b99f71cc12b1c1893a Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 13:00:39 +0100 Subject: [PATCH 07/80] Fix list_remove --- tests/snippets/list.py | 5 +++++ vm/src/obj/objlist.rs | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index 5474326e2..60c5ca5a4 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -94,6 +94,8 @@ x.append(x) assert x in x assert x.index(x) == 1 assert x.count(x) == 1 +x.remove(x) +assert x not in x class Foo(object): def __eq__(self, x): @@ -110,3 +112,6 @@ assert x.index(2) == 2 assert [] in x assert x.index([]) == 4 assert foo1 not in x +x.remove(foo) +assert x.index(foo) == 2 +assert x.count(foo) == 1 diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 68dec4536..f80b8b6a8 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -426,9 +426,12 @@ fn list_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(list, Some(vm.ctx.list_type())), (needle, None)] ); - let mut elements = get_mut_elements(list); let mut ri: Option = None; - for (index, element) in elements.iter().enumerate() { + for (index, element) in get_elements(list).iter().enumerate() { + if needle.is(&element) { + ri = Some(index); + break; + } let py_equal = vm._eq(needle.clone(), element.clone())?; if objbool::get_value(&py_equal) { ri = Some(index); @@ -437,6 +440,7 @@ fn list_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } if let Some(index) = ri { + let mut elements = get_mut_elements(list); elements.remove(index); Ok(vm.get_none()) } else { From dd6b5b9aaeda21a2594dc73b4f734e56feb28750 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 13:15:58 +0100 Subject: [PATCH 08/80] Fix list_eq --- tests/snippets/list.py | 12 ++++++++++++ vm/src/obj/objlist.rs | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index 60c5ca5a4..bd4016436 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -115,3 +115,15 @@ assert foo1 not in x x.remove(foo) assert x.index(foo) == 2 assert x.count(foo) == 1 + +x = [] +x.append(x) +assert x == x + +a = [1, 2, 3] +b = [1, 2, 3] +c = [a, b] +a.append(c) +b.append(c) + +assert a == b diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index f80b8b6a8..e790f9e14 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -66,6 +66,10 @@ fn list_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { required = [(zelf, Some(vm.ctx.list_type())), (other, None)] ); + if zelf.is(&other) { + return Ok(vm.ctx.new_bool(true)); + } + let result = if objtype::isinstance(other, &vm.ctx.list_type()) { let zelf = get_elements(zelf); let other = get_elements(other); From 93c184a7451b32b800194cbfa2dd3ce82349eeb0 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 13:25:13 +0100 Subject: [PATCH 09/80] Fix fmt --- vm/src/obj/objlist.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index e790f9e14..6a7515b0f 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -1,5 +1,6 @@ use super::super::pyobject::{ - IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, }; use super::super::vm::{ReprGuard, VirtualMachine}; use super::objbool; From 5a154f9745d0a2c1b7c7e116ffd5bc7343ef7bd8 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 14:23:20 +0100 Subject: [PATCH 10/80] Fix list & tuple equality --- tests/snippets/list.py | 3 +++ tests/snippets/tuple.py | 7 +++++++ vm/src/obj/objsequence.rs | 14 +++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index bd4016436..10ff02290 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -104,6 +104,7 @@ class Foo(object): foo = Foo() foo1 = Foo() x = [1, foo, 2, foo, []] +assert x == x assert foo in x assert 2 in x assert x.index(foo) == 1 @@ -127,3 +128,5 @@ a.append(c) b.append(c) assert a == b + +assert [foo] == [foo] diff --git a/tests/snippets/tuple.py b/tests/snippets/tuple.py index e7662b98d..d50f552dc 100644 --- a/tests/snippets/tuple.py +++ b/tests/snippets/tuple.py @@ -27,3 +27,10 @@ assert repr(recursive) == "([(...)],)" assert (None, "", 1).index(1) == 2 assert 1 in (None, "", 1) + +class Foo(object): + def __eq__(self, x): + return False + +foo = Foo() +assert (foo,) == (foo,) diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index 5afe6bd9c..eed4ca60d 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -1,4 +1,6 @@ -use super::super::pyobject::{PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol}; +use super::super::pyobject::{ + IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; use super::super::vm::VirtualMachine; use super::objbool; use super::objint; @@ -178,10 +180,12 @@ pub fn seq_equal( ) -> Result { if zelf.len() == other.len() { for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { - let eq = vm._eq(a.clone(), b.clone())?; - let value = objbool::boolval(vm, eq)?; - if !value { - return Ok(false); + if !a.is(&b) { + let eq = vm._eq(a.clone(), b.clone())?; + let value = objbool::boolval(vm, eq)?; + if !value { + return Ok(false); + } } } Ok(true) From 90184bcb902666c5d5258d896bbe3ef0bbdb76c1 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 14:54:29 +0100 Subject: [PATCH 11/80] Code coverage for RustPython --- .travis.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0f3aa9949..dc5b5da07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -97,6 +97,30 @@ matrix: - cargo clippy env: - REGULAR_TEST=true + - name: Code Coverage + language: python + python: 3.6 + cache: + pip: true + # Because we're using the Python Travis environment, we can't use + # the built-in cargo cacher + directories: + - /home/travis/.cargo + - target + before_script: + - curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf - + script: + - cargo build --verbose --all + - cargo test --verbose --all + - tests/.travis-runner.sh + - zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print` + - ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" > lcov.info + - bash <(curl -s https://codecov.io/bash) -f lcov.info + env: + - TRAVIS_RUST_VERSION=nightly + - REGULAR_TEST=false + - CARGO_INCREMENTAL=0 + - RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" allow_failures: - rust: nightly env: REGULAR_TEST=true From 1e3c2fbf1850400f09db600d067dff456ae9bf81 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 15:28:43 +0100 Subject: [PATCH 12/80] Try again --- .travis.yml | 12 +++--------- tests/.travis-runner.sh | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc5b5da07..cbab6ae21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ matrix: env: - TRAVIS_RUST_VERSION=stable - REGULAR_TEST=false + - CODE_COVERAGE=false script: tests/.travis-runner.sh - language: python python: 3.6 @@ -45,6 +46,7 @@ matrix: env: - TRAVIS_RUST_VERSION=beta - REGULAR_TEST=false + - CODE_COVERAGE=false script: tests/.travis-runner.sh - name: rustfmt language: rust @@ -107,20 +109,12 @@ matrix: directories: - /home/travis/.cargo - target - before_script: - - curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf - script: - - cargo build --verbose --all - - cargo test --verbose --all - tests/.travis-runner.sh - - zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print` - - ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" > lcov.info - - bash <(curl -s https://codecov.io/bash) -f lcov.info env: - TRAVIS_RUST_VERSION=nightly - REGULAR_TEST=false - - CARGO_INCREMENTAL=0 - - RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" + - CODE_COVERAGE=true allow_failures: - rust: nightly env: REGULAR_TEST=true diff --git a/tests/.travis-runner.sh b/tests/.travis-runner.sh index 680b18ea4..bb6108d18 100755 --- a/tests/.travis-runner.sh +++ b/tests/.travis-runner.sh @@ -10,7 +10,27 @@ pip install pipenv (cd tests; pipenv install) # Build outside of the test runner -cargo build --verbose --release +if [ $CODE_COVERAGE = "true" ] +then + export CARGO_INCREMENTAL=0 + export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" + + cargo build --verbose +else + cargo build --verbose --release +fi # Run the tests (cd tests; pipenv run pytest) + +if [ $CODE_COVERAGE = "true" ] +then + cargo test --verbose --all + zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print` + + # Install grcov + curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf - + + ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" > lcov.info + bash <(curl -s https://codecov.io/bash) -f lcov.info +fi From ce541a1ca5b6b8f9a4103b4ef91f8c612b87b11a Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 15:55:41 +0100 Subject: [PATCH 13/80] Remove parenthesis --- tests/.travis-runner.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/.travis-runner.sh b/tests/.travis-runner.sh index bb6108d18..62396bf16 100755 --- a/tests/.travis-runner.sh +++ b/tests/.travis-runner.sh @@ -32,5 +32,8 @@ then curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf - ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" > lcov.info - bash <(curl -s https://codecov.io/bash) -f lcov.info + + # Install codecov.io reporter + curl -s https://codecov.io/bash -o codecov.sh + bash codecov.sh -f lcov.info fi From 31c5b5ed3d1716fc9575ab480ae9a41ca838d421 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 17:30:05 +0100 Subject: [PATCH 14/80] Workaround issue with grcov --- tests/.travis-runner.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/.travis-runner.sh b/tests/.travis-runner.sh index 62396bf16..4b6429f56 100755 --- a/tests/.travis-runner.sh +++ b/tests/.travis-runner.sh @@ -31,7 +31,7 @@ then # Install grcov curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf - - ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" > lcov.info + ./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -p "x" > lcov.info # Install codecov.io reporter curl -s https://codecov.io/bash -o codecov.sh From 255417469736586e7c84f11c82c4e79e71fb7b27 Mon Sep 17 00:00:00 2001 From: Liran Ringel <5730310+liranringel@users.noreply.github.com> Date: Sat, 16 Feb 2019 18:09:15 +0200 Subject: [PATCH 15/80] Set up CI with Azure Pipelines --- azure-pipelines.yml | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..ee8889c03 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,56 @@ +trigger: +- master + +jobs: + +- job: 'Test' + pool: + vmImage: 'vs2017-win2016' + strategy: + matrix: + Python37: + python.version: '3.7' + maxParallel: 10 + + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '$(python.version)' + architecture: 'x64' + + - script: | + "C:\Program Files\Git\mingw64\bin\curl.exe" -sSf -o rustup-init.exe https://win.rustup.rs/ + .\rustup-init.exe -y + set PATH=%PATH%;%USERPROFILE%\.cargo\bin + rustc -V + cargo -V + displayName: 'Installing Rust' + + - script: | + set PATH=%PATH%;%USERPROFILE%\.cargo\bin + cargo build --verbose --all + displayName: 'Build' + + - script: | + set PATH=%PATH%;%USERPROFILE%\.cargo\bin + cargo test --verbose --all + displayName: 'Run tests' + + - script: | + pip install pipenv + pushd tests + pipenv install + popd + displayName: 'Install pipenv and python packages' + + - script: | + set PATH=%PATH%;%USERPROFILE%\.cargo\bin + cargo build --verbose --release + displayName: 'Build release' + + - script: | + set PATH=%PATH%;%USERPROFILE%\.cargo\bin + pushd tests + pipenv run pytest + popd + displayName: 'Run snippet tests' From e86e108e67b016b3befa4654d7fe606f5e04c733 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 18:19:52 +0100 Subject: [PATCH 16/80] Don't run tests in --release with code coverage --- tests/test_snippets.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_snippets.py b/tests/test_snippets.py index 77774f205..4be73b7bd 100644 --- a/tests/test_snippets.py +++ b/tests/test_snippets.py @@ -77,8 +77,12 @@ def run_via_rustpython(filename, test_type): log_level = 'info' if test_type == _TestType.benchmark else 'trace' env['RUST_LOG'] = '{},cargo=error,jobserver=error'.format(log_level) env['RUST_BACKTRACE'] = '1' - subprocess.check_call( - ['cargo', 'run', '--release', filename], env=env) + if env.get('CODE_COVERAGE', 'false') == 'true': + subprocess.check_call( + ['cargo', 'run', filename], env=env) + else: + subprocess.check_call( + ['cargo', 'run', '--release', filename], env=env) def create_test_function(cls, filename, method, test_type): From 9b7160800baafd2346faed9072de3e9fdb633185 Mon Sep 17 00:00:00 2001 From: Liran Ringel Date: Sat, 16 Feb 2019 19:23:33 +0200 Subject: [PATCH 17/80] Fix os_info.py to pass on windows --- tests/snippets/os_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snippets/os_info.py b/tests/snippets/os_info.py index c59b1a5d9..c335e4ad9 100644 --- a/tests/snippets/os_info.py +++ b/tests/snippets/os_info.py @@ -1,3 +1,3 @@ import os -assert os.name == 'posix' +assert os.name == 'posix' or os.name == 'nt' From 47e95486f05d8ec51831069ed24ed8694d964ee7 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sat, 16 Feb 2019 08:50:45 -0800 Subject: [PATCH 18/80] Reuse and improve ergonomics of assert_raises utility - Move assert_raises to testutils - Add optional message argument, with reasonable default - Reverse order of expr and exception type for readability - Lambda argument no longer takes parameter - Convert applicable snippets to use assert_raises --- tests/snippets/builtin_divmod.py | 17 ++--- tests/snippets/builtin_format.py | 16 ++--- tests/snippets/builtin_hex.py | 9 +-- tests/snippets/builtin_max.py | 30 ++------- tests/snippets/builtin_min.py | 31 ++------- tests/snippets/builtin_open.py | 8 +-- tests/snippets/builtin_ord.py | 24 ++----- tests/snippets/builtin_range.py | 31 ++------- tests/snippets/builtin_slice.py | 8 +-- tests/snippets/division_by_zero.py | 62 +++--------------- tests/snippets/division_of_big_ints.py | 16 ++--- tests/snippets/floats.py | 22 +------ tests/snippets/func_defaults.py | 90 ++++++++------------------ tests/snippets/list.py | 30 ++------- tests/snippets/membership.py | 16 ++--- tests/snippets/printing.py | 17 ++--- tests/snippets/set.py | 17 ++--- tests/snippets/stdlib_os.py | 8 +-- tests/snippets/test_bitwise.py | 30 ++------- tests/snippets/testutils.py | 20 ++++++ 20 files changed, 129 insertions(+), 373 deletions(-) create mode 100644 tests/snippets/testutils.py diff --git a/tests/snippets/builtin_divmod.py b/tests/snippets/builtin_divmod.py index 43b77a452..939e1d2d4 100644 --- a/tests/snippets/builtin_divmod.py +++ b/tests/snippets/builtin_divmod.py @@ -1,17 +1,8 @@ +from testutils import assert_raises + assert divmod(11, 3) == (3, 2) assert divmod(8,11) == (0, 8) assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999) -try: - divmod(5, 0) -except ZeroDivisionError: - pass -else: - assert False, "Expected divmod by zero to throw ZeroDivisionError" - -try: - divmod(5.0, 0.0) -except ZeroDivisionError: - pass -else: - assert False, "Expected divmod by zero to throw ZeroDivisionError" +assert_raises(ZeroDivisionError, lambda: divmod(5, 0), 'divmod by zero') +assert_raises(ZeroDivisionError, lambda: divmod(5.0, 0.0), 'divmod by zero') diff --git a/tests/snippets/builtin_format.py b/tests/snippets/builtin_format.py index a811775e0..6c06cbd98 100644 --- a/tests/snippets/builtin_format.py +++ b/tests/snippets/builtin_format.py @@ -1,17 +1,9 @@ +from testutils import assert_raises + assert format(5, "b") == "101" -try: - format(2, 3) -except TypeError: - pass -else: - assert False, "TypeError not raised when format is called with a number" +assert_raises(TypeError, lambda: format(2, 3), 'format called with number') assert format({}) == "{}" -try: - format({}, 'b') -except TypeError: - pass -else: - assert False, "TypeError not raised when format_spec not empty for dict" +assert_raises(TypeError, lambda: format({}, 'b'), 'format_spec not empty for dict') diff --git a/tests/snippets/builtin_hex.py b/tests/snippets/builtin_hex.py index b975e2186..f6f25ab58 100644 --- a/tests/snippets/builtin_hex.py +++ b/tests/snippets/builtin_hex.py @@ -1,9 +1,6 @@ +from testutils import assert_raises + assert hex(16) == '0x10' assert hex(-16) == '-0x10' -try: - hex({}) -except TypeError: - pass -else: - assert False, "TypeError not raised when ord() is called with a dict" +assert_raises(TypeError, lambda: hex({}), 'ord() called with dict') diff --git a/tests/snippets/builtin_max.py b/tests/snippets/builtin_max.py index 321aa6984..1494ecd80 100644 --- a/tests/snippets/builtin_max.py +++ b/tests/snippets/builtin_max.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + # simple values assert max(0, 0) == 0 assert max(1, 0) == 1 @@ -14,32 +16,17 @@ assert max({ }) == "b" assert max([1, 2], default=0) == 2 assert max([], default=0) == 0 -try: - max([]) -except ValueError: - pass -else: - assert False, "ValueError was not raised" +assert_raises(ValueError, lambda: max([])) # key parameter assert max(1, 2, -3, key=abs) == -3 assert max([1, 2, -3], key=abs) == -3 # no argument -try: - max() -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: max()) # one non-iterable argument -try: - max(1) -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: max(1)) # custom class @@ -64,9 +51,4 @@ class MyNotComparable(): pass -try: - max(MyNotComparable(), MyNotComparable()) -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: max(MyNotComparable(), MyNotComparable())) diff --git a/tests/snippets/builtin_min.py b/tests/snippets/builtin_min.py index 77c9eaccf..ed45eff58 100644 --- a/tests/snippets/builtin_min.py +++ b/tests/snippets/builtin_min.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + # simple values assert min(0, 0) == 0 assert min(1, 0) == 0 @@ -14,32 +16,18 @@ assert min({ }) == "a" assert min([1, 2], default=0) == 1 assert min([], default=0) == 0 -try: - min([]) -except ValueError: - pass -else: - assert False, "ValueError was not raised" + +assert_raises(ValueError, lambda: min([])) # key parameter assert min(1, 2, -3, key=abs) == 1 assert min([1, 2, -3], key=abs) == 1 # no argument -try: - min() -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: min()) # one non-iterable argument -try: - min(1) -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: min(1)) # custom class @@ -64,9 +52,4 @@ class MyNotComparable(): pass -try: - min(MyNotComparable(), MyNotComparable()) -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: min(MyNotComparable(), MyNotComparable())) diff --git a/tests/snippets/builtin_open.py b/tests/snippets/builtin_open.py index 805c975c8..55eafcd6c 100644 --- a/tests/snippets/builtin_open.py +++ b/tests/snippets/builtin_open.py @@ -1,8 +1,6 @@ +from testutils import assert_raises + fd = open('README.md') assert 'RustPython' in fd.read() -try: - open('DoesNotExist') - assert False -except FileNotFoundError: - pass +assert_raises(FileNotFoundError, lambda: open('DoesNotExist')) diff --git a/tests/snippets/builtin_ord.py b/tests/snippets/builtin_ord.py index 2dd03f91a..2549f28e7 100644 --- a/tests/snippets/builtin_ord.py +++ b/tests/snippets/builtin_ord.py @@ -1,23 +1,9 @@ +from testutils import assert_raises + assert ord("a") == 97 assert ord("é") == 233 assert ord("🤡") == 129313 -try: - ord() -except TypeError: - pass -else: - assert False, "TypeError not raised when ord() is called with no argument" -try: - ord("") -except TypeError: - pass -else: - assert False, "TypeError not raised when ord() is called with an empty string" - -try: - ord("ab") -except TypeError: - pass -else: - assert False, "TypeError not raised when ord() is called with more than one character" +assert_raises(TypeError, lambda: ord(), "ord() is called with no argument") +assert_raises(TypeError, lambda: ord(""), "ord() is called with an empty string") +assert_raises(TypeError, lambda: ord("ab"), "ord() is called with more than one character") diff --git a/tests/snippets/builtin_range.py b/tests/snippets/builtin_range.py index 6a20c6f1e..89014880c 100644 --- a/tests/snippets/builtin_range.py +++ b/tests/snippets/builtin_range.py @@ -1,20 +1,4 @@ -def assert_raises(expr, exc_type): - """ - Helper function to assert `expr` raises an exception of type `exc_type` - Args: - expr: Callable - exec_type: Exception - Returns: - None - Raises: - Assertion error on failure - """ - try: - expr(None) - except exc_type: - assert True - else: - assert False +from testutils import assert_raises assert range(2**63+1)[2**63] == 9223372036854775808 @@ -29,15 +13,10 @@ assert range(4, 10).index(6) == 2 assert range(4, 10, 2).index(6) == 1 assert range(10, 4, -2).index(8) == 1 -# index raises value error on out of bounds -assert_raises(lambda _: range(10).index(-1), ValueError) -assert_raises(lambda _: range(10).index(10), ValueError) - -# index raises value error if out of step -assert_raises(lambda _: range(4, 10, 2).index(5), ValueError) - -# index raises value error if needle is not an int -assert_raises(lambda _: range(10).index('foo'), ValueError) +assert_raises(ValueError, lambda: range(10).index(-1), 'out of bounds') +assert_raises(ValueError, lambda: range(10).index(10), 'out of bounds') +assert_raises(ValueError, lambda: range(4, 10, 2).index(5), 'out of step') +assert_raises(ValueError, lambda: range(10).index('foo'), 'not an int') # count tests assert range(10).count(2) == 1 diff --git a/tests/snippets/builtin_slice.py b/tests/snippets/builtin_slice.py index b7c3922c0..1d8a93b47 100644 --- a/tests/snippets/builtin_slice.py +++ b/tests/snippets/builtin_slice.py @@ -1,3 +1,4 @@ +from testutils import assert_raises a = [] assert a[:] == [] @@ -18,12 +19,7 @@ assert b[-10:1] == [1] assert b[0:0] == [] assert b[1:0] == [] -try: - _ = b[::0] -except ValueError: - pass -else: - assert False, "Zero step slice should raise ValueError" +assert_raises(ValueError, lambda: b[::0], 'zero step slice') assert b[::-1] == [2, 1] assert b[1::-1] == [2, 1] diff --git a/tests/snippets/division_by_zero.py b/tests/snippets/division_by_zero.py index d92419d79..d8b900636 100644 --- a/tests/snippets/division_by_zero.py +++ b/tests/snippets/division_by_zero.py @@ -1,55 +1,11 @@ -try: - 5 / 0 -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' +from testutils import assert_raises -try: - 5 / -0.0 -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' +assert_raises(ZeroDivisionError, lambda: 5 / 0) +assert_raises(ZeroDivisionError, lambda: 5 / -0.0) +assert_raises(ZeroDivisionError, lambda: 5 / (2-2)) +assert_raises(ZeroDivisionError, lambda: 5 % 0) +assert_raises(ZeroDivisionError, lambda: 5 // 0) +assert_raises(ZeroDivisionError, lambda: 5.3 // (-0.0)) +assert_raises(ZeroDivisionError, lambda: divmod(5, 0)) -try: - 5 / (2-2) -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' - -try: - 5 % 0 -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' - -try: - 5 // 0 -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' - -try: - 5.3 // (-0.0) -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' - -try: - divmod(5, 0) -except ZeroDivisionError: - pass -else: - assert False, 'Expected ZeroDivisionError' - -try: - raise ZeroDivisionError('Is an ArithmeticError subclass?') -except ArithmeticError: - pass -else: - assert False, 'Expected ZeroDivisionError' +assert issubclass(ZeroDivisionError, ArithmeticError) diff --git a/tests/snippets/division_of_big_ints.py b/tests/snippets/division_of_big_ints.py index 466862219..9595ae603 100644 --- a/tests/snippets/division_of_big_ints.py +++ b/tests/snippets/division_of_big_ints.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + # 2.456984346552728 res = 10**500 / (4 * 10**499 + 7 * 10**497 + 3 * 10**494) assert 2.456984 <= res <= 2.456985 @@ -8,20 +10,10 @@ assert 95.238095 <= res <= 95.238096 assert 10**500 / (2*10**(500-308)) == 5e307 assert 10**500 / (10**(500-308)) == 1e308 -try: - 10**500 / (10**(500-309)) -except OverflowError: - pass -else: - assert False, 'Expected overflow on too big result' +assert_raises(OverflowError, lambda: 10**500 / (10**(500-309)), 'too big result') # a bit more than f64::MAX = 1.7976931348623157e+308_f64 assert (2 * 10**308) / 2 == 1e308 # when dividing too big int by a float, the operation should fail -try: - (2 * 10**308) / 2.0 -except OverflowError: - pass -else: - assert False, 'Expected overflow on division of a big int by a float' +assert_raises(OverflowError, lambda: (2 * 10**308) / 2.0, 'division of big int by float') diff --git a/tests/snippets/floats.py b/tests/snippets/floats.py index 8f17c4bd5..003cf1ff0 100644 --- a/tests/snippets/floats.py +++ b/tests/snippets/floats.py @@ -1,22 +1,6 @@ import math -def assert_raises(expr, exc_type): - """ - Helper function to assert `expr` raises an exception of type `exc_type` - Args: - expr: Callable - exec_type: Exception - Returns: - None - Raises: - Assertion error on failure - """ - try: - expr(None) - except exc_type: - assert True - else: - assert False +from testutils import assert_raises 1 + 1.1 @@ -79,8 +63,8 @@ assert float('2.99e-23') == 2.99e-23 assert float(b'3.14') == 3.14 assert float(b'2.99e-23') == 2.99e-23 -assert_raises(lambda _: float('foo'), ValueError) -assert_raises(lambda _: float(2**10000), OverflowError) +assert_raises(ValueError, lambda: float('foo')) +assert_raises(OverflowError, lambda: float(2**10000)) # check that magic methods are implemented for ints and floats diff --git a/tests/snippets/func_defaults.py b/tests/snippets/func_defaults.py index a7d08c136..5fcf93047 100644 --- a/tests/snippets/func_defaults.py +++ b/tests/snippets/func_defaults.py @@ -1,21 +1,12 @@ +from testutils import assert_raises + def no_args(): pass no_args() -try: - no_args('one_arg') -except TypeError: - pass -else: - assert False, 'no TypeError raised: 1 arg to no_args' - -try: - no_args(kw='should fail') -except TypeError: - pass -else: - assert False, 'no TypeError raised: kwarg to no_args' +assert_raises(TypeError, lambda: no_args('one_arg'), '1 arg to no_args') +assert_raises(TypeError, lambda: no_args(kw='should fail'), 'kwarg to no_args') def one_arg(arg): @@ -24,40 +15,20 @@ def one_arg(arg): one_arg('one_arg') assert "arg" == one_arg(arg="arg") -try: - one_arg() -except TypeError: - pass -else: - assert False, 'no TypeError raised: no args to one_arg' +assert_raises(TypeError, lambda: one_arg(), 'no args to one_arg') +assert_raises(TypeError, + lambda: one_arg(wrong_arg='wont work'), + 'incorrect kwarg to one_arg') +assert_raises(TypeError, + lambda: one_arg('one_arg', 'two_arg'), + 'two args to one_arg') +assert_raises(TypeError, + lambda: one_arg('one_arg', extra_arg='wont work'), + 'no TypeError raised: extra kwarg to one_arg') -try: - one_arg(wrong_arg='wont work') -except TypeError: - pass -else: - assert False, 'no TypeError raised: incorrect kwarg to one_arg' - -try: - one_arg('one_arg', 'two_arg') -except TypeError: - pass -else: - assert False, 'no TypeError raised: two args to one_arg' - -try: - one_arg('one_arg', extra_arg='wont work') -except TypeError: - pass -else: - assert False, 'no TypeError raised: extra kwarg to one_arg' - -try: - one_arg('one_arg', arg='duplicate') -except TypeError: - pass -else: - assert False, 'no TypeError raised: same pos and kwarg to one_arg' +assert_raises(TypeError, + lambda: one_arg('one_arg', arg='duplicate'), + 'same pos and kwarg to one_arg') def one_default_arg(arg="default"): @@ -67,12 +38,9 @@ assert 'default' == one_default_arg() assert 'arg' == one_default_arg('arg') assert 'kwarg' == one_default_arg(arg='kwarg') -try: - one_default_arg('one_arg', 'two_arg') -except TypeError: - pass -else: - assert False, 'no TypeError raised: two args to one_default_arg' +assert_raises(TypeError, + lambda: one_default_arg('one_arg', 'two_arg'), + 'two args to one_default_arg') def one_normal_one_default_arg(pos, arg="default"): @@ -81,19 +49,13 @@ def one_normal_one_default_arg(pos, arg="default"): assert ('arg', 'default') == one_normal_one_default_arg('arg') assert ('arg', 'arg2') == one_normal_one_default_arg('arg', 'arg2') -try: - one_normal_one_default_arg() -except TypeError: - pass -else: - assert False, 'no TypeError raised: no args to one_normal_one_default_arg' +assert_raises(TypeError, + lambda: one_normal_one_default_arg(), + 'no args to one_normal_one_default_arg') -try: - one_normal_one_default_arg('one', 'two', 'three') -except TypeError: - pass -else: - assert False, 'no TypeError raised: three args to one_normal_one_default_arg' +assert_raises(TypeError, + lambda: one_normal_one_default_arg('one', 'two', 'three'), + 'three args to one_normal_one_default_arg') def two_pos(a, b): diff --git a/tests/snippets/list.py b/tests/snippets/list.py index 749d6c2bc..4bf6dd049 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + x = [1, 2, 3] assert x[0] == 1 assert x[1] == 2 @@ -16,12 +18,7 @@ assert x * 2 == [1, 2, 3, 1, 2, 3], "list __mul__ by 2 failed" # index() assert ['a', 'b', 'c'].index('b') == 1 assert [5, 6, 7].index(7) == 2 -try: - ['a', 'b', 'c'].index('z') -except ValueError: - pass -else: - assert False, "ValueError was not raised" +assert_raises(ValueError, lambda: ['a', 'b', 'c'].index('z')) x = [[1,0,-3], 'a', 1] y = [[3,2,1], 'z', 2] @@ -33,12 +30,7 @@ assert x > y, "list __gt__ failed" assert [1,2,'a'].pop() == 'a', "list pop failed" -try: - [].pop() -except IndexError: - pass -else: - assert False, "IndexError was not raised" +assert_raises(IndexError, lambda: [].pop()) recursive = [] recursive.append(recursive) @@ -61,12 +53,7 @@ x = ['a', 'b', 'c'] x.insert(-100, 'z') assert x == ['z', 'a', 'b', 'c'] -try: - x.insert(100000000000000000000, 'z') -except OverflowError: - pass -else: - assert False, "OverflowError was not raised" +assert_raises(OverflowError, lambda: x.insert(100000000000000000000, 'z')) x = [[], 2, {}] y = x.copy() @@ -82,9 +69,4 @@ a.remove(1) assert len(a) == 2 assert not 1 in a -try: - a.remove(10) -except ValueError: - pass -else: - assert False, "Remove not exist element should raise ValueError" +assert_raises(ValueError, lambda: a.remove(10), 'Remove not exist element') diff --git a/tests/snippets/membership.py b/tests/snippets/membership.py index 4c6fb3cae..a944c4539 100644 --- a/tests/snippets/membership.py +++ b/tests/snippets/membership.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + # test lists assert 3 in [1, 2, 3] assert 3 not in [1, 2] @@ -19,12 +21,7 @@ assert b"5" <= b"5" assert b"4" > b"2" assert not b"1" >= b"2" assert b"10" >= b"10" -try: - bytes() > 2 -except TypeError: - pass -else: - assert False, "TypeError not raised" +assert_raises(TypeError, lambda: bytes() > 2) # test tuple assert 1 in (1, 2) @@ -53,12 +50,7 @@ class MyNotContainingClass(): pass -try: - 1 in MyNotContainingClass() -except TypeError: - pass -else: - assert False, "TypeError not raised" +assert_raises(TypeError, lambda: 1 in MyNotContainingClass()) class MyContainingClass(): diff --git a/tests/snippets/printing.py b/tests/snippets/printing.py index 2611e1387..e420c6c7f 100644 --- a/tests/snippets/printing.py +++ b/tests/snippets/printing.py @@ -1,18 +1,9 @@ +from testutils import assert_raises + print(2 + 3) -try: - print('test', end=4) -except TypeError: - pass -else: - assert False, 'Expected TypeError on wrong type passed to end' - -try: - print('test', sep=['a']) -except TypeError: - pass -else: - assert False, 'Expected TypeError on wrong type passed to sep' +assert_raises(TypeError, lambda: print('test', end=4), 'wrong type passed to end') +assert_raises(TypeError, lambda: print('test', sep=['a']), 'wrong type passed to sep') try: print('test', end=None, sep=None, flush=None) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index 7a377fce3..f20c278e2 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -1,3 +1,5 @@ +from testutils import assert_raises + assert set([1,2]) == set([1,2]) assert not set([1,2,3]) == set([1,2]) @@ -69,19 +71,8 @@ assert set([1,2,3]).symmetric_difference(set([5,6])) == set([1,2,3,5,6]) assert set([1,2,3]) ^ set([4,5]) == set([1,2,3,4,5]) assert set([1,2,3]) ^ set([1,2,3,4,5]) == set([4,5]) -try: - set([[]]) -except TypeError: - pass -else: - assert False, "TypeError was not raised" - -try: - set().add([]) -except TypeError: - pass -else: - assert False, "TypeError was not raised" +assert_raises(TypeError, lambda: set([[]])) +assert_raises(TypeError, lambda: set().add([])) a = set([1, 2, 3]) assert a.discard(1) is None diff --git a/tests/snippets/stdlib_os.py b/tests/snippets/stdlib_os.py index d8f03053f..ed9e91c70 100644 --- a/tests/snippets/stdlib_os.py +++ b/tests/snippets/stdlib_os.py @@ -1,13 +1,11 @@ import os +from testutils import assert_raises + assert os.open('README.md', 0) > 0 -try: - os.open('DOES_NOT_EXIST', 0) - assert False -except FileNotFoundError: - pass +assert_raises(FileNotFoundError, lambda: os.open('DOES_NOT_EXIST', 0)) assert os.O_RDONLY == 0 diff --git a/tests/snippets/test_bitwise.py b/tests/snippets/test_bitwise.py index 18b90a197..32028c996 100644 --- a/tests/snippets/test_bitwise.py +++ b/tests/snippets/test_bitwise.py @@ -1,20 +1,4 @@ -def assert_raises(expr, exc_type): - """ - Helper function to assert `expr` raises an exception of type `exc_type` - Args: - expr: Callable - exec_type: Exception - Returns: - None - Raises: - Assertion error on failure - """ - try: - expr(None) - except exc_type: - assert True - else: - assert False +from testutils import assert_raises # # Tests @@ -23,15 +7,15 @@ assert 8 >> 3 == 1 assert 8 << 3 == 64 # Left shift raises type error -assert_raises(lambda _: 1 << 0.1, TypeError) -assert_raises(lambda _: 1 << "abc", TypeError) +assert_raises(TypeError, lambda: 1 << 0.1) +assert_raises(TypeError, lambda: 1 << "abc") # Right shift raises type error -assert_raises(lambda _: 1 >> 0.1, TypeError) -assert_raises(lambda _: 1 >> "abc", TypeError) +assert_raises(TypeError, lambda: 1 >> 0.1) +assert_raises(TypeError, lambda: 1 >> "abc") # Left shift raises value error on negative -assert_raises(lambda _: 1 << -1, ValueError) +assert_raises(ValueError, lambda: 1 << -1) # Right shift raises value error on negative -assert_raises(lambda _: 1 >> -1, ValueError) +assert_raises(ValueError, lambda: 1 >> -1) diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py new file mode 100644 index 000000000..b5b69b867 --- /dev/null +++ b/tests/snippets/testutils.py @@ -0,0 +1,20 @@ +def assert_raises(exc_type, expr, msg=None): + """ + Helper function to assert `expr` raises an exception of type `exc_type`. + Args: + expr: Callable + exec_type: Exception + Returns: + None + Raises: + Assertion error on failure + """ + try: + expr() + except exc_type: + pass + else: + failmsg = f'{exc_type.__name__} was not raised' + if msg is not None: + failmsg += f': {msg}' + assert False, failmsg From 6d646cc38e0aa6a917ff7d28016ec18350321e71 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 16 Feb 2019 18:33:45 +0100 Subject: [PATCH 19/80] Add a codecov badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3d3f84820..d79bd56da 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:. [![Build Status](https://travis-ci.org/RustPython/RustPython.svg?branch=master)](https://travis-ci.org/RustPython/RustPython) +[![codecov](https://codecov.io/gh/RustPython/RustPython/branch/master/graph/badge.svg)](https://codecov.io/gh/mozilla/RustPython/RustPython) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Contributors](https://img.shields.io/github/contributors/RustPython/RustPython.svg)](https://github.com/RustPython/RustPython/graphs/contributors) [![Gitter](https://badges.gitter.im/RustPython/Lobby.svg)](https://gitter.im/rustpython/Lobby) From 114d9df1d1f101422475bc3c8d84f6c23f46687c Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sat, 16 Feb 2019 19:43:25 -0800 Subject: [PATCH 20/80] Allow attributes to be used as decorators --- parser/src/python.lalrpop | 17 +++++++++++++---- tests/snippets/decorators.py | 12 ++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index e80484d0e..8ee407f9a 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -613,17 +613,26 @@ ClassDef: ast::LocatedStatement = { }, }; +Path: ast::Expression = { + => ast::Expression::Identifier { name: n }, + "." => { + ast::Expression::Attribute { + value: Box::new(p), + name: n, + } + }, +}; + // Decorators: Decorator: ast::Expression = { - "@" "\n" => { - let name = ast::Expression::Identifier { name: n }; + "@" "\n" => { match a { Some((_, args, _)) => ast::Expression::Call { - function: Box::new(name), + function: Box::new(p), args: args.0, keywords: args.1, }, - None => name, + None => p, } }, }; diff --git a/tests/snippets/decorators.py b/tests/snippets/decorators.py index a423361ad..fcc196f93 100644 --- a/tests/snippets/decorators.py +++ b/tests/snippets/decorators.py @@ -14,3 +14,15 @@ c = add(10, 3) assert c == 14 + +def f(func): return lambda: 42 +class A: pass +a = A() +a.a = A() +a.a.x = f + +@a.a.x +def func(): + pass + +assert func() == 42 From b61730972e4ff299f64f8d9f9255c257015113c4 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 17 Feb 2019 17:07:49 +0100 Subject: [PATCH 21/80] Fix typo in codecov.io badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d79bd56da..de013376c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:. [![Build Status](https://travis-ci.org/RustPython/RustPython.svg?branch=master)](https://travis-ci.org/RustPython/RustPython) -[![codecov](https://codecov.io/gh/RustPython/RustPython/branch/master/graph/badge.svg)](https://codecov.io/gh/mozilla/RustPython/RustPython) +[![codecov](https://codecov.io/gh/RustPython/RustPython/branch/master/graph/badge.svg)](https://codecov.io/gh/RustPython/RustPython) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Contributors](https://img.shields.io/github/contributors/RustPython/RustPython.svg)](https://github.com/RustPython/RustPython/graphs/contributors) [![Gitter](https://badges.gitter.im/RustPython/Lobby.svg)](https://gitter.im/rustpython/Lobby) From fe3f45f6557e2890517f8d8f4c35364f719e5590 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 09:26:31 -0800 Subject: [PATCH 22/80] Implement remaining binop reverse fallbacks --- vm/src/frame.rs | 16 ++++++---------- vm/src/vm.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 0400bc9fb..f7c7fa3ba 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -900,18 +900,14 @@ impl Frame { bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref), bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref), bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref), - bytecode::BinaryOperator::MatrixMultiply => { - vm.call_method(&a_ref, "__matmul__", vec![b_ref]) - } + bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref), bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref), - bytecode::BinaryOperator::Divide => vm._div(a_ref, b_ref), - bytecode::BinaryOperator::FloorDivide => { - vm.call_method(&a_ref, "__floordiv__", vec![b_ref]) - } + bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref), + bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref), bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref), - bytecode::BinaryOperator::Modulo => vm._modulo(a_ref, b_ref), - bytecode::BinaryOperator::Lshift => vm.call_method(&a_ref, "__lshift__", vec![b_ref]), - bytecode::BinaryOperator::Rshift => vm.call_method(&a_ref, "__rshift__", vec![b_ref]), + bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref), + bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref), + bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref), bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref), bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref), bytecode::BinaryOperator::And => vm._and(a_ref, b_ref), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 45b88e45d..bfa2fe57d 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -571,24 +571,48 @@ impl VirtualMachine { }) } - pub fn _div(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + pub fn _matmul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "@")) + }) + } + + pub fn _truediv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { self.call_or_unsupported(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "/")) }) } + pub fn _floordiv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "//")) + }) + } + pub fn _pow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { self.call_or_unsupported(a, b, "__pow__", "__rpow__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "**")) }) } - pub fn _modulo(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + pub fn _mod(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { self.call_or_unsupported(a, b, "__mod__", "__rmod__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "%")) }) } + pub fn _lshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__lshift__", "__rlshift__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "<<")) + }) + } + + pub fn _rshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__rshift__", "__rrshift__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, ">>")) + }) + } + pub fn _xor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { self.call_or_unsupported(a, b, "__xor__", "__rxor__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "^")) From b310d5e24b2356fdd9fa50bf51afe0d00aacb938 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 10:47:58 -0800 Subject: [PATCH 23/80] Use i-methods for in-place operations --- vm/src/bytecode.rs | 1 + vm/src/compile.rs | 9 +- vm/src/frame.rs | 20 +++- vm/src/vm.rs | 239 ++++++++++++++++++++++++++++++++------------- 4 files changed, 197 insertions(+), 72 deletions(-) diff --git a/vm/src/bytecode.rs b/vm/src/bytecode.rs index 9fbe14663..951659f06 100644 --- a/vm/src/bytecode.rs +++ b/vm/src/bytecode.rs @@ -71,6 +71,7 @@ pub enum Instruction { }, BinaryOperation { op: BinaryOperator, + inplace: bool, }, LoadAttr { name: String, diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 34f1e7eb0..067bfa442 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -608,7 +608,7 @@ impl Compiler { self.compile_expression(value)?; // Perform operation: - self.compile_op(op); + self.compile_op(op, true); self.compile_store(target)?; } ast::Statement::Delete { targets } => { @@ -757,7 +757,7 @@ impl Compiler { Ok(()) } - fn compile_op(&mut self, op: &ast::Operator) { + fn compile_op(&mut self, op: &ast::Operator, inplace: bool) { let i = match op { ast::Operator::Add => bytecode::BinaryOperator::Add, ast::Operator::Sub => bytecode::BinaryOperator::Subtract, @@ -773,7 +773,7 @@ impl Compiler { ast::Operator::BitXor => bytecode::BinaryOperator::Xor, ast::Operator::BitAnd => bytecode::BinaryOperator::And, }; - self.emit(Instruction::BinaryOperation { op: i }); + self.emit(Instruction::BinaryOperation { op: i, inplace }); } fn compile_test( @@ -852,13 +852,14 @@ impl Compiler { self.compile_expression(b)?; // Perform operation: - self.compile_op(op); + self.compile_op(op, false); } ast::Expression::Subscript { a, b } => { self.compile_expression(a)?; self.compile_expression(b)?; self.emit(Instruction::BinaryOperation { op: bytecode::BinaryOperator::Subscript, + inplace: false, }); } ast::Expression::Unop { op, a } => { diff --git a/vm/src/frame.rs b/vm/src/frame.rs index f7c7fa3ba..d57c9de73 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -316,7 +316,9 @@ impl Frame { vm.call_method(&dict_obj, "__setitem__", vec![key, value])?; Ok(None) } - bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(vm, op), + bytecode::Instruction::BinaryOperation { ref op, inplace } => { + self.execute_binop(vm, op, *inplace) + } bytecode::Instruction::LoadAttr { ref name } => self.load_attr(vm, name), bytecode::Instruction::StoreAttr { ref name } => self.store_attr(vm, name), bytecode::Instruction::DeleteAttr { ref name } => self.delete_attr(vm, name), @@ -893,23 +895,39 @@ impl Frame { &mut self, vm: &mut VirtualMachine, op: &bytecode::BinaryOperator, + inplace: bool, ) -> FrameResult { let b_ref = self.pop_value(); let a_ref = self.pop_value(); let value = match *op { + bytecode::BinaryOperator::Subtract if inplace => vm._isub(a_ref, b_ref), bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref), + bytecode::BinaryOperator::Add if inplace => vm._iadd(a_ref, b_ref), bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref), + bytecode::BinaryOperator::Multiply if inplace => vm._imul(a_ref, b_ref), bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref), + bytecode::BinaryOperator::MatrixMultiply if inplace => vm._imatmul(a_ref, b_ref), bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref), + bytecode::BinaryOperator::Power if inplace => vm._ipow(a_ref, b_ref), bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref), + bytecode::BinaryOperator::Divide if inplace => vm._itruediv(a_ref, b_ref), bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref), + bytecode::BinaryOperator::FloorDivide if inplace => vm._ifloordiv(a_ref, b_ref), bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref), + // TODO: Subscript should probably have its own op + bytecode::BinaryOperator::Subscript if inplace => unreachable!(), bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref), + bytecode::BinaryOperator::Modulo if inplace => vm._imod(a_ref, b_ref), bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref), + bytecode::BinaryOperator::Lshift if inplace => vm._ilshift(a_ref, b_ref), bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref), + bytecode::BinaryOperator::Rshift if inplace => vm._irshift(a_ref, b_ref), bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref), + bytecode::BinaryOperator::Xor if inplace => vm._ixor(a_ref, b_ref), bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref), + bytecode::BinaryOperator::Or if inplace => vm._ior(a_ref, b_ref), bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref), + bytecode::BinaryOperator::And if inplace => vm._iand(a_ref, b_ref), bytecode::BinaryOperator::And => vm._and(a_ref, b_ref), }?; diff --git a/vm/src/vm.rs b/vm/src/vm.rs index bfa2fe57d..5302bbf4c 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -499,171 +499,276 @@ impl VirtualMachine { } } - /// Calls default method, reverse method or exception + /// Calls a method on `obj` passing `arg`, if the method exists. /// - /// * `a` - First argument. - /// * `b` - Second argument. - /// * `d` - Default method to try and call (such as `__and__`). - /// * `r` - Reverse method to try and call (such as `__rand__`), in case first one fails. - /// * `op` - Operator for the exception text, for example `&`. - /// - /// Given the above example, it will - /// 1. Try to call `__and__` with `a` and `b` - /// 2. If above fails try to call `__rand__` with `a` and `b` - /// 3. If above in not implemented, call unsupported(a, b) for result. - /// - pub fn call_or_unsupported( + /// Otherwise, or if the result is the special `NotImplemented` built-in constant, + /// calls `unsupported` to determine fallback value. + pub fn call_or_unsupported( &mut self, - a: PyObjectRef, - b: PyObjectRef, - d: &str, - r: &str, + obj: PyObjectRef, + arg: PyObjectRef, + method: &str, + unsupported: F, + ) -> PyResult + where + F: Fn(&mut VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult, + { + if let Ok(method) = self.get_method(obj.clone(), method) { + let result = self.invoke( + method, + PyFuncArgs { + args: vec![arg.clone()], + kwargs: vec![], + }, + )?; + if !result.is(&self.ctx.not_implemented()) { + return Ok(result); + } + } + + unsupported(self, obj, arg) + } + + /// Calls a method, falling back to its reflection with the operands + /// reversed, and then to the value provided by `unsupported`. + /// + /// For example: the following: + /// + /// `call_or_reflection(lhs, rhs, "__and__", "__rand__", unsupported)` + /// + /// 1. Calls `__and__` with `lhs` and `rhs`. + /// 2. If above is not implemented, calls `__rand__` with `rhs` and `lhs`. + /// 3. If above is not implemented, invokes `unsupported` for the result. + pub fn call_or_reflection( + &mut self, + lhs: PyObjectRef, + rhs: PyObjectRef, + default: &str, + reflection: &str, unsupported: fn(&mut VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult, ) -> PyResult { - // Try to call the first method - if let Ok(method) = self.get_method(a.clone(), d) { - let result = self.invoke( - method, - PyFuncArgs { - args: vec![b.clone()], - kwargs: vec![], - }, - )?; - - if !result.is(&self.ctx.not_implemented()) { - return Ok(result); - } - } - - // 2. Try to call reverse method - if let Ok(method) = self.get_method(b.clone(), r) { - let result = self.invoke( - method, - PyFuncArgs { - args: vec![a.clone()], - kwargs: vec![], - }, - )?; - - if !result.is(&self.ctx.not_implemented()) { - return Ok(result); - } - } - - unsupported(self, a, b) + // Try to call the default method + self.call_or_unsupported(lhs, rhs, default, move |vm, lhs, rhs| { + // Try to call the reflection method + vm.call_or_unsupported(rhs, lhs, reflection, unsupported) + }) } pub fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__sub__", "__rsub__", |vm, a, b| { + self.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "-")) }) } + pub fn _isub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__isub__", |vm, a, b| { + vm.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "-=")) + }) + }) + } + pub fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__add__", "__radd__", |vm, a, b| { + self.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "+")) }) } + pub fn _iadd(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__iadd__", |vm, a, b| { + vm.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "+=")) + }) + }) + } + pub fn _mul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__mul__", "__rmul__", |vm, a, b| { + self.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "*")) }) } + pub fn _imul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__imul__", |vm, a, b| { + vm.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "*=")) + }) + }) + } + pub fn _matmul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { + self.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "@")) }) } + pub fn _imatmul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__imatmul__", |vm, a, b| { + vm.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "@=")) + }) + }) + } + pub fn _truediv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { + self.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "/")) }) } + pub fn _itruediv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__itruediv__", |vm, a, b| { + vm.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "/=")) + }) + }) + } + pub fn _floordiv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { + self.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "//")) }) } + pub fn _ifloordiv(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__ifloordiv__", |vm, a, b| { + vm.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "//=")) + }) + }) + } + pub fn _pow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__pow__", "__rpow__", |vm, a, b| { + self.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "**")) }) } + pub fn _ipow(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__ipow__", |vm, a, b| { + vm.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "**=")) + }) + }) + } + pub fn _mod(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__mod__", "__rmod__", |vm, a, b| { + self.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "%")) }) } + pub fn _imod(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__imod__", |vm, a, b| { + vm.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "%=")) + }) + }) + } + pub fn _lshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__lshift__", "__rlshift__", |vm, a, b| { + self.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "<<")) }) } + pub fn _ilshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__ilshift__", |vm, a, b| { + vm.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "<<=")) + }) + }) + } + pub fn _rshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__rshift__", "__rrshift__", |vm, a, b| { + self.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, ">>")) }) } + pub fn _irshift(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__irshift__", |vm, a, b| { + vm.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, ">>=")) + }) + }) + } + pub fn _xor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__xor__", "__rxor__", |vm, a, b| { + self.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "^")) }) } + pub fn _ixor(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__ixor__", |vm, a, b| { + vm.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "^=")) + }) + }) + } + pub fn _or(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__or__", "__ror__", |vm, a, b| { + self.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "|")) }) } + pub fn _ior(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__ior__", |vm, a, b| { + vm.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "|=")) + }) + }) + } + pub fn _and(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__and__", "__rand__", |vm, a, b| { + self.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "&")) }) } + pub fn _iand(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + self.call_or_unsupported(a, b, "__iand__", |vm, a, b| { + vm.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| { + Err(vm.new_unsupported_operand_error(a, b, "&=")) + }) + }) + } + pub fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__eq__", "__eq__", |vm, a, b| { + self.call_or_reflection(a, b, "__eq__", "__eq__", |vm, a, b| { Ok(vm.new_bool(a.is(&b))) }) } pub fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__ne__", "__ne__", |vm, a, b| { + self.call_or_reflection(a, b, "__ne__", "__ne__", |vm, a, b| { let eq = vm._eq(a, b)?; objbool::not(vm, &eq) }) } pub fn _lt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__lt__", "__gt__", |vm, a, b| { + self.call_or_reflection(a, b, "__lt__", "__gt__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "<")) }) } pub fn _le(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__le__", "__ge__", |vm, a, b| { + self.call_or_reflection(a, b, "__le__", "__ge__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, "<=")) }) } pub fn _gt(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__gt__", "__lt__", |vm, a, b| { + self.call_or_reflection(a, b, "__gt__", "__lt__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, ">")) }) } pub fn _ge(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { - self.call_or_unsupported(a, b, "__ge__", "__le__", |vm, a, b| { + self.call_or_reflection(a, b, "__ge__", "__le__", |vm, a, b| { Err(vm.new_unsupported_operand_error(a, b, ">=")) }) } From dcb29ab1f01e733f1f24289e88fc48f5ca8fa255 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 10:54:25 -0800 Subject: [PATCH 24/80] Add list.__iadd__ --- tests/snippets/list.py | 4 ++++ vm/src/obj/objlist.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/tests/snippets/list.py b/tests/snippets/list.py index 4bf6dd049..ad65f2a92 100644 --- a/tests/snippets/list.py +++ b/tests/snippets/list.py @@ -70,3 +70,7 @@ assert len(a) == 2 assert not 1 in a assert_raises(ValueError, lambda: a.remove(10), 'Remove not exist element') + +foo = bar = [1] +foo += [2] +assert (foo, bar) == ([1, 2], [1, 2]) diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 1c09794fc..6edc762f8 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -181,6 +181,24 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn list_iadd(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.list_type())), (other, None)] + ); + + if objtype::isinstance(other, &vm.ctx.list_type()) { + let mut elements = get_mut_elements(zelf); + for elem in get_elements(other).iter() { + elements.push(elem.clone()); + } + Ok(zelf.clone()) + } else { + Ok(vm.ctx.not_implemented()) + } +} + fn list_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.list_type()))]); @@ -443,6 +461,7 @@ pub fn init(context: &PyContext) { The argument must be an iterable if specified."; context.set_attr(&list_type, "__add__", context.new_rustfunc(list_add)); + context.set_attr(&list_type, "__iadd__", context.new_rustfunc(list_iadd)); context.set_attr( &list_type, "__contains__", From 7abaea556a6544060c7af8257daa8bc84c5aff78 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 14:30:38 -0800 Subject: [PATCH 25/80] Micro-optimize list.__iadd__ --- vm/src/obj/objlist.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 6edc762f8..66468db0c 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -189,10 +189,7 @@ fn list_iadd(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); if objtype::isinstance(other, &vm.ctx.list_type()) { - let mut elements = get_mut_elements(zelf); - for elem in get_elements(other).iter() { - elements.push(elem.clone()); - } + get_mut_elements(zelf).extend_from_slice(&get_elements(other)); Ok(zelf.clone()) } else { Ok(vm.ctx.not_implemented()) From afabde26d5171183f6bffca0791859e68fde327f Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 17:18:47 -0800 Subject: [PATCH 26/80] coverage: try deleting old gcda files --- tests/.travis-runner.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/.travis-runner.sh b/tests/.travis-runner.sh index 4b6429f56..8a004d3b1 100755 --- a/tests/.travis-runner.sh +++ b/tests/.travis-runner.sh @@ -12,6 +12,8 @@ pip install pipenv # Build outside of the test runner if [ $CODE_COVERAGE = "true" ] then + find . -name '*.gcda' -delete + export CARGO_INCREMENTAL=0 export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads" From ddc7da4a9d047ad490008ef696950e915eaeef75 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 17 Feb 2019 18:17:26 -0800 Subject: [PATCH 27/80] Add test for in-place ops --- tests/snippets/inplace_ops.py | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 tests/snippets/inplace_ops.py diff --git a/tests/snippets/inplace_ops.py b/tests/snippets/inplace_ops.py new file mode 100644 index 000000000..a794bd3c8 --- /dev/null +++ b/tests/snippets/inplace_ops.py @@ -0,0 +1,109 @@ +class InPlace: + def __init__(self, val): + self.val = val + + def __ipow__(self, other): + self.val **= other + return self + + def __imul__(self, other): + self.val *= other + return self + + def __imatmul__(self, other): + # I guess you could think of an int as a 1x1 matrix + self.val *= other + return self + + def __itruediv__(self, other): + self.val /= other + return self + + def __ifloordiv__(self, other): + self.val //= other + return self + + def __imod__(self, other): + self.val %= other + return self + + def __iadd__(self, other): + self.val += other + return self + + def __isub__(self, other): + self.val -= other + return self + + def __ilshift__(self, other): + self.val <<= other + return self + + def __irshift__(self, other): + self.val >>= other + return self + + def __iand__(self, other): + self.val &= other + return self + + def __ixor__(self, other): + self.val ^= other + return self + + def __ior__(self, other): + self.val |= other + return self + + +i = InPlace(2) +i **= 3 +assert i.val == 8 + +i = InPlace(2) +i *= 2 +assert i.val == 4 + +i = InPlace(2) +i @= 2 +assert i.val == 4 + +i = InPlace(1) +i /= 2 +assert i.val == 0.5 + +i = InPlace(1) +i //= 2 +assert i.val == 0 + +i = InPlace(10) +i %= 3 +assert i.val == 1 + +i = InPlace(1) +i += 1 +assert i.val == 2 + +i = InPlace(2) +i -= 1 +assert i.val == 1 + +i = InPlace(2) +i <<= 3 +assert i.val == 16 + +i = InPlace(16) +i >>= 3 +assert i.val == 2 + +i = InPlace(0b010101) +i &= 0b111000 +assert i.val == 0b010000 + +i = InPlace(0b010101) +i ^= 0b111000 +assert i.val == 0b101101 + +i = InPlace(0b010101) +i |= 0b111000 +assert i.val == 0b111101 From 85110f6fbf01ac927ca61bd44f9c01fd79195e4c Mon Sep 17 00:00:00 2001 From: janczer Date: Mon, 18 Feb 2019 18:21:39 +0100 Subject: [PATCH 28/80] Add dict.clear and bytes.clear --- tests/snippets/bytearray.py | 4 ++++ tests/snippets/dict.py | 3 +++ vm/src/obj/objbytes.rs | 13 +++++++++++++ vm/src/obj/objdict.rs | 13 +++++++++++++ 4 files changed, 33 insertions(+) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index 2fffe3111..fdada9095 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -29,3 +29,7 @@ assert not bytearray(b'tuPpEr').isupper() assert bytearray(b'Is Title Case').istitle() assert not bytearray(b'is Not title casE').istitle() + +a = b'abcd' +a.clear() +assert len(a) == 0 diff --git a/tests/snippets/dict.py b/tests/snippets/dict.py index ca9d61aa6..1e4acc3e3 100644 --- a/tests/snippets/dict.py +++ b/tests/snippets/dict.py @@ -14,3 +14,6 @@ c['d'] = 3 c['a']['g'] = 2 assert dict_eq(a, {'g': 2}) assert dict_eq(b, {'a': a, 'd': 9}) + +a.clear() +assert len(a) == 0 diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 6c8ab30ed..99f72ac65 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -41,6 +41,7 @@ pub fn init(context: &PyContext) { "__doc__", context.new_str(bytes_doc.to_string()), ); + context.set_attr(bytes_type, "clear", context.new_rustfunc(bytes_clear)); } fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -208,3 +209,15 @@ fn bytes_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(iter_obj) } + +fn bytes_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytes_type()))]); + let mut mut_obj = zelf.borrow_mut(); + match mut_obj.payload { + PyObjectPayload::Bytes { ref mut value } => { + value.clear(); + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("".to_string())), + } +} diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 3e4a7fadd..65fda7e47 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -244,6 +244,18 @@ fn dict_delitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn dict_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]); + let mut mut_obj = dict.borrow_mut(); + match mut_obj.payload { + PyObjectPayload::Dict { ref mut elements } => { + elements.clear(); + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("".to_string())), + } +} + /// When iterating over a dictionary, we iterate over the keys of it. fn dict_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]); @@ -337,4 +349,5 @@ pub fn init(context: &PyContext) { "__setitem__", context.new_rustfunc(dict_setitem), ); + context.set_attr(&dict_type, "clear", context.new_rustfunc(dict_clear)); } From 58369b6fbcb33a8e2835ca9d8caf763a9ef01f23 Mon Sep 17 00:00:00 2001 From: janczer Date: Mon, 18 Feb 2019 18:45:49 +0100 Subject: [PATCH 29/80] Delete unnessesary code from dict.clear --- vm/src/obj/objdict.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 65fda7e47..84b6a0ab9 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -246,14 +246,8 @@ fn dict_delitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn dict_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]); - let mut mut_obj = dict.borrow_mut(); - match mut_obj.payload { - PyObjectPayload::Dict { ref mut elements } => { - elements.clear(); - Ok(vm.get_none()) - } - _ => Err(vm.new_type_error("".to_string())), - } + get_mut_elements(dict).clear(); + Ok(vm.get_none()) } /// When iterating over a dictionary, we iterate over the keys of it. From e016b68552c65cf8a4464bc6a2c3b917e166df30 Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Mon, 18 Feb 2019 19:59:28 +0100 Subject: [PATCH 30/80] Document arg_check! macro a bit --- vm/src/macros.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 033e7fbc7..2b06a825d 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -1,3 +1,4 @@ +// count number of tokens given as arguments. // see: https://danielkeep.github.io/tlborm/book/blk-counting.html macro_rules! replace_expr { ($_t:tt $sub:expr) => { @@ -44,9 +45,11 @@ macro_rules! arg_check { ( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*], optional=[$( ($optional_arg_name:ident, $optional_arg_type:expr) ),*] ) => { let mut arg_count = 0; + // use macro magic to compile-time count number of required and optional arguments let minimum_arg_count = count_tts!($($arg_name)*); let maximum_arg_count = minimum_arg_count + count_tts!($($optional_arg_name)*); + // verify that the number of given arguments is right if $args.args.len() < minimum_arg_count || $args.args.len() > maximum_arg_count { let expected_str = if minimum_arg_count == maximum_arg_count { format!("{}", minimum_arg_count) @@ -60,6 +63,9 @@ macro_rules! arg_check { ))); }; + // for each required parameter: + // check if the type matches. If not, return with error + // assign the arg to a variable $( type_check!($vm, $args, arg_count, $arg_name, $arg_type); let $arg_name = &$args.args[arg_count]; @@ -69,6 +75,9 @@ macro_rules! arg_check { } )* + // for each optional parameter, if there are enough positional arguments: + // check if the type matches. If not, return with error + // assign the arg to a variable $( let $optional_arg_name = if arg_count < $args.args.len() { type_check!($vm, $args, arg_count, $optional_arg_name, $optional_arg_type); From 7965a63ba9721d6260ad3860dfcb15add7c799a7 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Mon, 18 Feb 2019 16:37:14 -0800 Subject: [PATCH 31/80] Fix infinite loop when breaking from nested for loop --- tests/snippets/control_flow.py | 10 ++++ vm/src/compile.rs | 21 ++++---- vm/src/frame.rs | 91 +++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 50 deletions(-) create mode 100644 tests/snippets/control_flow.py diff --git a/tests/snippets/control_flow.py b/tests/snippets/control_flow.py new file mode 100644 index 000000000..e25d6eee2 --- /dev/null +++ b/tests/snippets/control_flow.py @@ -0,0 +1,10 @@ +def foo(): + sum = 0 + for i in range(10): + sum += i + for j in range(10): + sum += j + break + return sum + +assert foo() == 45 diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 067bfa442..960b7e069 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -234,11 +234,11 @@ impl Compiler { target: start_label, }); self.set_label(else_label); + self.emit(Instruction::PopBlock); if let Some(orelse) = orelse { self.compile_statements(orelse)?; } self.set_label(end_label); - self.emit(Instruction::PopBlock); } ast::Statement::With { items, body } => { let end_label = self.new_label(); @@ -267,14 +267,6 @@ impl Compiler { body, orelse, } => { - // The thing iterated: - for i in iter { - self.compile_expression(i)?; - } - - // Retrieve iterator - self.emit(Instruction::GetIter); - // Start loop let start_label = self.new_label(); let else_label = self.new_label(); @@ -283,6 +275,15 @@ impl Compiler { start: start_label, end: end_label, }); + + // The thing iterated: + for i in iter { + self.compile_expression(i)?; + } + + // Retrieve Iterator + self.emit(Instruction::GetIter); + self.set_label(start_label); self.emit(Instruction::ForIter { target: else_label }); @@ -295,11 +296,11 @@ impl Compiler { target: start_label, }); self.set_label(else_label); + self.emit(Instruction::PopBlock); if let Some(orelse) = orelse { self.compile_statements(orelse)?; } self.set_label(end_label); - self.emit(Instruction::PopBlock); } ast::Statement::Raise { exception, cause } => match exception { Some(value) => { diff --git a/vm/src/frame.rs b/vm/src/frame.rs index d57c9de73..4c0749999 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -23,7 +23,15 @@ use super::vm::VirtualMachine; use num_bigint::BigInt; #[derive(Clone, Debug)] -enum Block { +struct Block { + /// The type of block. + typ: BlockType, + /// The level of the value stack when the block was entered. + level: usize, +} + +#[derive(Clone, Debug)] +enum BlockType { Loop { start: bytecode::Label, end: bytecode::Label, @@ -357,21 +365,21 @@ impl Frame { } } bytecode::Instruction::SetupLoop { start, end } => { - self.push_block(Block::Loop { + self.push_block(BlockType::Loop { start: *start, end: *end, }); Ok(None) } bytecode::Instruction::SetupExcept { handler } => { - self.push_block(Block::TryExcept { handler: *handler }); + self.push_block(BlockType::TryExcept { handler: *handler }); Ok(None) } bytecode::Instruction::SetupWith { end } => { let context_manager = self.pop_value(); // Call enter: let obj = vm.call_method(&context_manager, "__enter__", vec![])?; - self.push_block(Block::With { + self.push_block(BlockType::With { end: *end, context_manager: context_manager.clone(), }); @@ -380,22 +388,23 @@ impl Frame { } bytecode::Instruction::CleanupWith { end: end1 } => { let block = self.pop_block().unwrap(); - if let Block::With { + if let BlockType::With { end: end2, context_manager, - } = &block + } = &block.typ { - assert!(end1 == end2); + debug_assert!(end1 == end2); // call exit now with no exception: - self.with_exit(vm, context_manager, None)?; - Ok(None) + self.with_exit(vm, &context_manager, None)?; } else { - panic!("Block stack is incorrect, expected a with block"); + unreachable!("Block stack is incorrect, expected a with block"); } + + Ok(None) } bytecode::Instruction::PopBlock => { - self.pop_block(); + self.pop_block().expect("no pop to block"); Ok(None) } bytecode::Instruction::GetIter => { @@ -532,7 +541,7 @@ impl Frame { bytecode::Instruction::Break => { let block = self.unwind_loop(vm); - if let Block::Loop { end, .. } = block { + if let BlockType::Loop { end, .. } = block.typ { self.jump(end); } Ok(None) @@ -543,7 +552,7 @@ impl Frame { } bytecode::Instruction::Continue => { let block = self.unwind_loop(vm); - if let Block::Loop { start, .. } = block { + if let BlockType::Loop { start, .. } = block.typ { self.jump(start); } else { assert!(false); @@ -711,16 +720,15 @@ impl Frame { // Unwind all blocks: fn unwind_blocks(&mut self, vm: &mut VirtualMachine) -> Option { - loop { - let block = self.pop_block(); - match block { - Some(Block::Loop { .. }) => {} - Some(Block::TryExcept { .. }) => { + while let Some(block) = self.pop_block() { + match block.typ { + BlockType::Loop { .. } => {} + BlockType::TryExcept { .. } => { // TODO: execute finally handler } - Some(Block::With { + BlockType::With { context_manager, .. - }) => { + } => { match self.with_exit(vm, &context_manager, None) { Ok(..) => {} Err(exc) => { @@ -729,28 +737,28 @@ impl Frame { } } } - None => break None, } } + + None } fn unwind_loop(&mut self, vm: &mut VirtualMachine) -> Block { loop { - let block = self.pop_block(); - match block { - Some(Block::Loop { .. }) => break block.unwrap(), - Some(Block::TryExcept { .. }) => { + let block = self.pop_block().expect("not in a loop"); + match block.typ { + BlockType::Loop { .. } => break block, + BlockType::TryExcept { .. } => { // TODO: execute finally handler } - Some(Block::With { + BlockType::With { context_manager, .. - }) => match self.with_exit(vm, &context_manager, None) { + } => match self.with_exit(vm, &context_manager, None) { Ok(..) => {} Err(exc) => { panic!("Exception in with __exit__ {:?}", exc); } }, - None => panic!("No block to break / continue"), } } } @@ -761,18 +769,17 @@ impl Frame { exc: PyObjectRef, ) -> Option { // unwind block stack on exception and find any handlers: - loop { - let block = self.pop_block(); - match block { - Some(Block::TryExcept { handler }) => { + while let Some(block) = self.pop_block() { + match block.typ { + BlockType::TryExcept { handler } => { self.push_value(exc); self.jump(handler); return None; } - Some(Block::With { + BlockType::With { end, context_manager, - }) => { + } => { match self.with_exit(vm, &context_manager, Some(exc.clone())) { Ok(exit_action) => { match objbool::boolval(vm, exit_action) { @@ -797,15 +804,14 @@ impl Frame { } } } - Some(Block::Loop { .. }) => {} - None => break, + BlockType::Loop { .. } => {} } } Some(exc) } fn with_exit( - &mut self, + &self, vm: &mut VirtualMachine, context_manager: &PyObjectRef, exc: Option, @@ -1061,12 +1067,17 @@ impl Frame { self.code.locations[self.lasti].clone() } - fn push_block(&mut self, block: Block) { - self.blocks.push(block); + fn push_block(&mut self, typ: BlockType) { + self.blocks.push(Block { + typ, + level: self.stack.len(), + }); } fn pop_block(&mut self) -> Option { - self.blocks.pop() + let block = self.blocks.pop()?; + self.stack.truncate(block.level); + Some(block) } pub fn push_value(&mut self, obj: PyObjectRef) { From d5c91a8de0dd171d357cd2139bbdc2c9ba31b113 Mon Sep 17 00:00:00 2001 From: janczer Date: Tue, 19 Feb 2019 07:11:13 +0100 Subject: [PATCH 32/80] Move clear method from bytes to bytearray --- tests/snippets/bytearray.py | 2 +- vm/src/obj/objbytearray.rs | 17 +++++++++++++++++ vm/src/obj/objbytes.rs | 13 ------------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index fdada9095..7ad36662e 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -30,6 +30,6 @@ assert not bytearray(b'tuPpEr').isupper() assert bytearray(b'Is Title Case').istitle() assert not bytearray(b'is Not title casE').istitle() -a = b'abcd' +a = bytearray(b'abcd') a.clear() assert len(a) == 0 diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 1e42bd516..186b2f17c 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -95,6 +95,11 @@ pub fn init(context: &PyContext) { "istitle", context.new_rustfunc(bytearray_istitle), ); + context.set_attr( + &bytearray_type, + "clear", + context.new_rustfunc(bytearray_clear), + ); } fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -261,3 +266,15 @@ fn bytearray_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let data = String::from_utf8(value.to_vec()).unwrap(); Ok(vm.new_str(format!("bytearray(b'{}')", data))) } + +fn bytearray_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytearray_type()))]); + let mut mut_obj = zelf.borrow_mut(); + match mut_obj.payload { + PyObjectPayload::Bytes { ref mut value } => { + value.clear(); + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("".to_string())), + } +} diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 99f72ac65..6c8ab30ed 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -41,7 +41,6 @@ pub fn init(context: &PyContext) { "__doc__", context.new_str(bytes_doc.to_string()), ); - context.set_attr(bytes_type, "clear", context.new_rustfunc(bytes_clear)); } fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -209,15 +208,3 @@ fn bytes_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(iter_obj) } - -fn bytes_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytes_type()))]); - let mut mut_obj = zelf.borrow_mut(); - match mut_obj.payload { - PyObjectPayload::Bytes { ref mut value } => { - value.clear(); - Ok(vm.get_none()) - } - _ => Err(vm.new_type_error("".to_string())), - } -} From 0cc898e19d37b198d3ecbb4183e389a47c6d3885 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 19 Feb 2019 02:18:52 -0500 Subject: [PATCH 33/80] Updated Compilation phase to detect whether or not we are currently inside of a loop or not. This is useful to determine whether or not we can use looping specific keywords such as break or continue. --- src/main.rs | 2 +- tests/snippets/control_flow.py | 10 ++++++++++ vm/src/builtins.rs | 6 +++--- vm/src/compile.rs | 18 ++++++++++++++++++ vm/src/error.rs | 3 +++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 tests/snippets/control_flow.py diff --git a/src/main.rs b/src/main.rs index 13b145e9e..90e4788cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,7 @@ fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> Py ) .map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) })?; // trace!("Code object: {:?}", code_obj.borrow()); let builtins = vm.get_builtin_scope(); diff --git a/tests/snippets/control_flow.py b/tests/snippets/control_flow.py new file mode 100644 index 000000000..e25d6eee2 --- /dev/null +++ b/tests/snippets/control_flow.py @@ -0,0 +1,10 @@ +def foo(): + sum = 0 + for i in range(10): + sum += i + for j in range(10): + sum += j + break + return sum + +assert foo() == 45 diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index d3aaa6ee0..2ce0a6733 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -152,7 +152,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, filename, vm.ctx.code_type()).map_err(|err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }) } @@ -206,7 +206,7 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( |err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }, )? } else { @@ -241,7 +241,7 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { compile::compile(&source, &mode, "".to_string(), vm.ctx.code_type()).map_err( |err| { let syntax_error = vm.context().exceptions.syntax_error.clone(); - vm.new_exception(syntax_error, err.description().to_string()) + vm.new_exception(syntax_error, err.to_string()) }, )? } else if objtype::isinstance(source, &vm.ctx.code_type()) { diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 067bfa442..b02f15e3d 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -16,6 +16,7 @@ struct Compiler { nxt_label: usize, source_path: Option, current_source_location: ast::Location, + in_loop: bool, } /// Compile a given sourcecode into a bytecode object. @@ -73,6 +74,7 @@ impl Compiler { nxt_label: 0, source_path: None, current_source_location: ast::Location::default(), + in_loop: false, } } @@ -229,7 +231,10 @@ impl Compiler { self.set_label(start_label); self.compile_test(test, None, Some(else_label), EvalContext::Statement)?; + + self.in_loop = true; self.compile_statements(body)?; + self.in_loop = false; self.emit(Instruction::Jump { target: start_label, }); @@ -290,7 +295,10 @@ impl Compiler { self.compile_store(target)?; // Body of loop: + self.in_loop = true; self.compile_statements(body)?; + self.in_loop = false; + self.emit(Instruction::Jump { target: start_label, }); @@ -563,9 +571,19 @@ impl Compiler { self.set_label(end_label); } ast::Statement::Break => { + + if !self.in_loop { + return Err(CompileError::SyntaxErr(String::from("break"))); + } + self.emit(Instruction::Break); } ast::Statement::Continue => { + + if !self.in_loop { + return Err(CompileError::SyntaxErr(String::from("continue"))); + } + self.emit(Instruction::Continue); } ast::Statement::Return { value } => { diff --git a/vm/src/error.rs b/vm/src/error.rs index 811a33511..0b98ab816 100644 --- a/vm/src/error.rs +++ b/vm/src/error.rs @@ -15,6 +15,8 @@ pub enum CompileError { Parse(ParseError), // Multiple `*` detected StarArgs, + // Catches errors undetectable by the parser + SyntaxErr(String), } impl fmt::Display for CompileError { @@ -25,6 +27,7 @@ impl fmt::Display for CompileError { CompileError::ExpectExpr => write!(f, "Expecting expression, got statement"), CompileError::Parse(err) => err.fmt(f), CompileError::StarArgs => write!(f, "Two starred expressions in assignment"), + CompileError::SyntaxErr(expr) => write!(f, "Syntax Error: '{}' ouside loop", expr), } } } From 6229efca24070c218f8dd9587f57ac6d5c2a4d8a Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 19 Feb 2019 02:19:14 -0500 Subject: [PATCH 34/80] Updated Compilation phase to detect whether or not we are currently inside of a loop or not. This is useful to determine whether or not we can use looping specific keywords such as break or continue. --- tests/snippets/control_flow.py | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 tests/snippets/control_flow.py diff --git a/tests/snippets/control_flow.py b/tests/snippets/control_flow.py deleted file mode 100644 index e25d6eee2..000000000 --- a/tests/snippets/control_flow.py +++ /dev/null @@ -1,10 +0,0 @@ -def foo(): - sum = 0 - for i in range(10): - sum += i - for j in range(10): - sum += j - break - return sum - -assert foo() == 45 From 724d9c6dcb0e641b3f130c1021e8c28cb6d8d561 Mon Sep 17 00:00:00 2001 From: rmliddle Date: Tue, 19 Feb 2019 20:41:43 +1100 Subject: [PATCH 35/80] Fixed Inheritance on String & BytesIO to reflect CPython --- vm/src/stdlib/io.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index e254b2417..63627a10f 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -421,18 +421,18 @@ pub fn mk_module(ctx: &PyContext) -> PyObjectRef { }; ctx.set_attr(&py_mod, "TextIOWrapper", text_io_wrapper.clone()); - // BytesIO: in-memory bytes + //StringIO: in-memory text let string_io = { - let string_io = ctx.new_class("StringIO", io_base.clone()); + let string_io = ctx.new_class("StringIO", text_io_base.clone()); ctx.set_attr(&string_io, "__init__", ctx.new_rustfunc(string_io_init)); ctx.set_attr(&string_io, "getvalue", ctx.new_rustfunc(string_io_getvalue)); string_io }; ctx.set_attr(&py_mod, "StringIO", string_io); - // StringIO: in-memory text + //BytesIO: in-memory bytes let bytes_io = { - let bytes_io = ctx.new_class("BytesIO", io_base.clone()); + let bytes_io = ctx.new_class("BytesIO", buffered_io_base.clone()); ctx.set_attr(&bytes_io, "__init__", ctx.new_rustfunc(bytes_io_init)); ctx.set_attr(&bytes_io, "getvalue", ctx.new_rustfunc(bytes_io_getvalue)); bytes_io From 2963dd5b663d8381fcc7d05e1e51272ebbdeb632 Mon Sep 17 00:00:00 2001 From: janczer Date: Tue, 19 Feb 2019 20:38:38 +0100 Subject: [PATCH 36/80] Change error to panic in bytearray.clear --- vm/src/obj/objbytearray.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 186b2f17c..a6c5386c7 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -275,6 +275,6 @@ fn bytearray_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { value.clear(); Ok(vm.get_none()) } - _ => Err(vm.new_type_error("".to_string())), + _ => panic!("Bytearray has incorrect payload."), } } From 218cec98cbc95d7673897b58a4da235fa2cffa0a Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Tue, 19 Feb 2019 21:38:39 +0200 Subject: [PATCH 37/80] Add KeyError to builtins --- vm/src/builtins.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index d3aaa6ee0..80c4948af 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -831,6 +831,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { "ZeroDivisionError", ctx.exceptions.zero_division_error.clone(), ); + ctx.set_attr(&py_mod, "KeyError", ctx.exceptions.key_error.clone()); py_mod } From a451e4a5b339319eee3952df53cde7214924f94a Mon Sep 17 00:00:00 2001 From: Chris Wood Date: Tue, 19 Feb 2019 14:48:23 -0500 Subject: [PATCH 38/80] Hopefully fixed rustfmt issues --- vm/src/compile.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vm/src/compile.rs b/vm/src/compile.rs index b02f15e3d..02ab3b4d8 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -571,19 +571,15 @@ impl Compiler { self.set_label(end_label); } ast::Statement::Break => { - if !self.in_loop { return Err(CompileError::SyntaxErr(String::from("break"))); } - self.emit(Instruction::Break); } ast::Statement::Continue => { - if !self.in_loop { return Err(CompileError::SyntaxErr(String::from("continue"))); } - self.emit(Instruction::Continue); } ast::Statement::Return { value } => { From 8e5073e524f17e7c6a98fe2e304a48d4bfc4fac3 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Tue, 19 Feb 2019 17:58:57 -0600 Subject: [PATCH 39/80] Convert `bytes` and `bytearray`s to `Uint8Array`s --- wasm/lib/src/convert.rs | 45 ++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index 78dc3495f..944e446fd 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -1,4 +1,5 @@ use js_sys::{Array, ArrayBuffer, Object, Reflect, Uint8Array}; +use rustpython_vm::obj::{objbytes, objtype}; use rustpython_vm::pyobject::{self, PyFuncArgs, PyObjectRef, PyResult}; use rustpython_vm::VirtualMachine; use vm_class::{AccessibleVM, WASMVirtualMachine}; @@ -16,10 +17,10 @@ pub fn js_py_typeerror(vm: &mut VirtualMachine, js_err: JsValue) -> PyObjectRef pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue { if let Some(ref wasm_id) = vm.wasm_id { - let wasm_vm = WASMVirtualMachine { - id: wasm_id.clone(), - }; - if rustpython_vm::obj::objtype::isinstance(&py_obj, &vm.ctx.function_type()) { + if objtype::isinstance(&py_obj, &vm.ctx.function_type()) { + let wasm_vm = WASMVirtualMachine { + id: wasm_id.clone(), + }; let closure = move |args: Option, kwargs: Option| -> Result { let py_obj = py_obj.clone(); @@ -55,19 +56,31 @@ pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue { return func; } } - let dumps = rustpython_vm::import::import( - vm, - std::path::PathBuf::default(), - "json", - &Some("dumps".into()), - ) - .expect("Couldn't get json.dumps function"); - match vm.invoke(dumps, pyobject::PyFuncArgs::new(vec![py_obj], vec![])) { - Ok(value) => { - let json = vm.to_pystr(&value).unwrap(); - js_sys::JSON::parse(&json).unwrap_or(JsValue::UNDEFINED) + if objtype::isinstance(&py_obj, &vm.ctx.bytes_type()) + || objtype::isinstance(&py_obj, &vm.ctx.bytearray_type()) + { + let bytes = objbytes::get_value(&py_obj); + let arr = Uint8Array::new_with_length(bytes.len() as u32); + for (i, byte) in bytes.iter().enumerate() { + Reflect::set(&arr, &(i as u32).into(), &(*byte).into()) + .expect("setting Uint8Array value failed"); + } + arr.into() + } else { + let dumps = rustpython_vm::import::import( + vm, + std::path::PathBuf::default(), + "json", + &Some("dumps".into()), + ) + .expect("Couldn't get json.dumps function"); + match vm.invoke(dumps, pyobject::PyFuncArgs::new(vec![py_obj], vec![])) { + Ok(value) => { + let json = vm.to_pystr(&value).unwrap(); + js_sys::JSON::parse(&json).unwrap_or(JsValue::UNDEFINED) + } + Err(_) => JsValue::UNDEFINED, } - Err(_) => JsValue::UNDEFINED, } } From 9092d1f30b6d6eb9d8960808f607d74a6db08424 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 19 Feb 2019 21:11:50 -0500 Subject: [PATCH 40/80] Updated to fix corner case with inner function --- vm/src/compile.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 02ab3b4d8..0563ad9bb 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -662,6 +662,7 @@ impl Compiler { name: &str, args: &ast::Parameters, ) -> Result { + self.in_loop = false; let have_kwargs = !args.defaults.is_empty(); if have_kwargs { // Construct a tuple: From 9face190abb206b87186ee9ea0c55e4df3a72d77 Mon Sep 17 00:00:00 2001 From: Joey Date: Tue, 19 Feb 2019 19:40:34 -0800 Subject: [PATCH 41/80] Fix continue statement --- tests/snippets/control_flow.py | 23 +++++++++++++++++++++++ vm/src/frame.rs | 13 +++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/snippets/control_flow.py b/tests/snippets/control_flow.py index e25d6eee2..a0ac46613 100644 --- a/tests/snippets/control_flow.py +++ b/tests/snippets/control_flow.py @@ -1,3 +1,5 @@ +# break from a nested for loop + def foo(): sum = 0 for i in range(10): @@ -8,3 +10,24 @@ def foo(): return sum assert foo() == 45 + + +# continue statement + +def primes(limit): + """Finds all the primes from 2 up to a given number using the Sieve of Eratosthenes.""" + sieve = [False] * (limit + 1) + for i in range(2, limit + 1): + if sieve[i]: + continue + yield i + + for j in range(2 * i, limit + 1, i): + sieve[j] = True + + +assert list(primes(1)) == [] +assert list(primes(2)) == [2] +assert list(primes(10)) == [2, 3, 5, 7] +assert list(primes(13)) == [2, 3, 5, 7, 11, 13] + diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 4c0749999..b1374b2f3 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -542,7 +542,10 @@ impl Frame { bytecode::Instruction::Break => { let block = self.unwind_loop(vm); if let BlockType::Loop { end, .. } = block.typ { + self.pop_block(); self.jump(end); + } else { + unreachable!() } Ok(None) } @@ -555,7 +558,7 @@ impl Frame { if let BlockType::Loop { start, .. } = block.typ { self.jump(start); } else { - assert!(false); + unreachable!(); } Ok(None) } @@ -745,7 +748,7 @@ impl Frame { fn unwind_loop(&mut self, vm: &mut VirtualMachine) -> Block { loop { - let block = self.pop_block().expect("not in a loop"); + let block = self.current_block().cloned().expect("not in a loop"); match block.typ { BlockType::Loop { .. } => break block, BlockType::TryExcept { .. } => { @@ -760,6 +763,8 @@ impl Frame { } }, } + + self.pop_block(); } } @@ -1080,6 +1085,10 @@ impl Frame { Some(block) } + fn current_block(&self) -> Option<&Block> { + self.blocks.last() + } + pub fn push_value(&mut self, obj: PyObjectRef) { self.stack.push(obj); } From bfdb82b5c1719b0d05521e48eeaa50434a9476ac Mon Sep 17 00:00:00 2001 From: janczer Date: Tue, 19 Feb 2019 18:35:08 +0100 Subject: [PATCH 42/80] Add pop to bytearray --- tests/snippets/bytearray.py | 10 ++++++++++ vm/src/obj/objbytearray.rs | 13 +++++++++++++ vm/src/obj/objbytes.rs | 12 ++++++++++++ 3 files changed, 35 insertions(+) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index 7ad36662e..30f2fa690 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -33,3 +33,13 @@ assert not bytearray(b'is Not title casE').istitle() a = bytearray(b'abcd') a.clear() assert len(a) == 0 + +b = bytearray(b'test') +assert len(b) == 4 +b.pop() +assert len(b) == 3 + +c = bytearray([123, 255, 111]) +assert len(c) == 3 +c.pop() +assert len(c) == 2 diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index a6c5386c7..cf99d6b6c 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -7,6 +7,7 @@ use super::super::pyobject::{ use super::objint; use super::super::vm::VirtualMachine; +use super::objbytes::get_mut_value; use super::objbytes::get_value; use super::objtype; use num_traits::ToPrimitive; @@ -100,6 +101,7 @@ pub fn init(context: &PyContext) { "clear", context.new_rustfunc(bytearray_clear), ); + context.set_attr(&bytearray_type, "pop", context.new_rustfunc(bytearray_pop)); } fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -278,3 +280,14 @@ fn bytearray_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { _ => panic!("Bytearray has incorrect payload."), } } + +fn bytearray_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]); + let mut value = get_mut_value(obj); + + if let Some(i) = value.pop() { + Ok(vm.ctx.new_int(i)) + } else { + Err(vm.new_index_error("pop from empty bytearray".to_string())) + } +} diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 6c8ab30ed..459e83fe0 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -6,8 +6,10 @@ use super::objint; use super::objtype; use num_traits::ToPrimitive; use std::cell::Ref; +use std::cell::RefMut; use std::hash::{Hash, Hasher}; use std::ops::Deref; +use std::ops::DerefMut; // Binary data support @@ -188,6 +190,16 @@ pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a }) } +pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { + RefMut::map(obj.borrow_mut(), |py_obj| { + if let PyObjectPayload::Bytes { ref mut value } = py_obj.payload { + value + } else { + panic!("Inner error getting int {:?}", obj); + } + }) +} + fn bytes_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]); let value = get_value(obj); From 24176f7bbb8b4e6caecbdd5f23e70c4bb6686c0f Mon Sep 17 00:00:00 2001 From: janczer Date: Wed, 20 Feb 2019 06:57:53 +0100 Subject: [PATCH 43/80] Add more test for bytearray.pop and fix the panic message --- tests/snippets/bytearray.py | 9 +++++++++ vm/src/obj/objbytes.rs | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index 30f2fa690..1b0830f33 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -43,3 +43,12 @@ c = bytearray([123, 255, 111]) assert len(c) == 3 c.pop() assert len(c) == 2 +c.pop() +c.pop() + +try: + c.pop() +except IndexError: + pass +else: + assert False diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 459e83fe0..11a0c7b0b 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -185,7 +185,7 @@ pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a if let PyObjectPayload::Bytes { ref value } = py_obj.payload { value } else { - panic!("Inner error getting int {:?}", obj); + panic!("Inner error getting bytearray {:?}", obj); } }) } @@ -195,7 +195,7 @@ pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut if let PyObjectPayload::Bytes { ref mut value } = py_obj.payload { value } else { - panic!("Inner error getting int {:?}", obj); + panic!("Inner error getting bytearray {:?}", obj); } }) } From 51f6ec23252d22e4baa5e9c3936f1008c9c7bbbc Mon Sep 17 00:00:00 2001 From: janczer Date: Wed, 20 Feb 2019 07:10:42 +0100 Subject: [PATCH 44/80] Add checking if value more then 255 in bytearraya --- tests/snippets/bytearray.py | 7 +++++++ vm/src/obj/objbytearray.rs | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index 7ad36662e..e43e7baff 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -33,3 +33,10 @@ assert not bytearray(b'is Not title casE').istitle() a = bytearray(b'abcd') a.clear() assert len(a) == 0 + +try: + bytearray([400]) +except ValueError: + pass +else: + assert False diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index a6c5386c7..27140b0c5 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -119,7 +119,11 @@ fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let mut data_bytes = vec![]; for elem in elements.iter() { let v = objint::to_int(vm, elem, 10)?; - data_bytes.push(v.to_u8().unwrap()); + if let Some(i) = v.to_u8() { + data_bytes.push(i); + } else { + return Err(vm.new_value_error("byte must be in range(0, 256)".to_string())); + } } data_bytes // return Err(vm.new_type_error("Cannot construct bytes".to_string())); From 2ad4dddd163a5865ae7f5ed714cd5a920846eaee Mon Sep 17 00:00:00 2001 From: rmliddle Date: Wed, 20 Feb 2019 21:00:50 +1100 Subject: [PATCH 45/80] README Update --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index de013376c..ce6e41489 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:. [![Build Status](https://travis-ci.org/RustPython/RustPython.svg?branch=master)](https://travis-ci.org/RustPython/RustPython) +[![Build Status](https://dev.azure.com/ryan0463/ryan/_apis/build/status/RustPython.RustPython?branchName=master)](https://dev.azure.com/ryan0463/ryan/_build/latest?definitionId=1&branchName=master) [![codecov](https://codecov.io/gh/RustPython/RustPython/branch/master/graph/badge.svg)](https://codecov.io/gh/RustPython/RustPython) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Contributors](https://img.shields.io/github/contributors/RustPython/RustPython.svg)](https://github.com/RustPython/RustPython/graphs/contributors) @@ -26,6 +27,14 @@ Or use the interactive shell: >>>>> 2+2 4 +# Disclaimer + + RustPython is in a development phase and should not used in production or a fault intolerant setting. + + Our current build supports only a subset of Python syntax. + + Contribution is also more than welcome! See our contribution section for more information on this. + # Goals - Full Python-3 environment entirely in Rust (not CPython bindings) @@ -33,7 +42,7 @@ Or use the interactive shell: # Documentation -Currently the project is in an early phase, and so is the documentation. +Currently along with other areas of the project, documentation is still in an early phase. You can read the [online documentation](https://rustpython.github.io/website/rustpython/index.html) for the latest code on master. @@ -63,7 +72,9 @@ If you wish to update the online documentation. Push directly to the `release` b # Contributing -To start contributing, there are a lot of things that need to be done. +Contributions are more than welcome, and in many cases we are happy to guide contributors through PRs or on gitter. + +With that in mind, please note this project is maintained by voulenteers, some of the best ways to get started are below: Most tasks are listed in the [issue tracker](https://github.com/RustPython/RustPython/issues). Check issues labeled with `good first issue` if you wish to start coding. From 6be7623a9495febdc80a39825416f7fd0db71452 Mon Sep 17 00:00:00 2001 From: rmliddle Date: Wed, 20 Feb 2019 21:36:56 +1100 Subject: [PATCH 46/80] Spelling Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce6e41489..a49d39499 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ If you wish to update the online documentation. Push directly to the `release` b Contributions are more than welcome, and in many cases we are happy to guide contributors through PRs or on gitter. -With that in mind, please note this project is maintained by voulenteers, some of the best ways to get started are below: +With that in mind, please note this project is maintained by volunteers, some of the best ways to get started are below: Most tasks are listed in the [issue tracker](https://github.com/RustPython/RustPython/issues). Check issues labeled with `good first issue` if you wish to start coding. From df76ffe116cb5b9ac36c3412ed9e4f3a401165c5 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 20 Feb 2019 08:44:30 -0800 Subject: [PATCH 47/80] Replace most relative imports with 2018-style crate --- parser/src/parser.rs | 10 +++--- src/main.rs | 5 +-- vm/src/builtins.rs | 21 ++++++------ vm/src/compile.rs | 12 +++---- vm/src/dictdatatype.rs | 8 ++--- vm/src/eval.rs | 6 ++-- vm/src/exceptions.rs | 10 +++--- vm/src/frame.rs | 24 +++++++------- vm/src/import.rs | 8 ++--- vm/src/obj/objbool.rs | 6 ++-- vm/src/obj/objbytearray.rs | 6 ++-- vm/src/obj/objbytes.rs | 8 ++--- vm/src/obj/objcode.rs | 8 ++--- vm/src/obj/objcomplex.rs | 8 ++--- vm/src/obj/objdict.rs | 10 +++--- vm/src/obj/objenumerate.rs | 6 ++-- vm/src/obj/objfilter.rs | 10 +++--- vm/src/obj/objfloat.rs | 8 ++--- vm/src/obj/objframe.rs | 8 ++--- vm/src/obj/objfunction.rs | 6 ++-- vm/src/obj/objgenerator.rs | 8 ++--- vm/src/obj/objint.rs | 12 +++---- vm/src/obj/objiter.rs | 6 ++-- vm/src/obj/objlist.rs | 10 +++--- vm/src/obj/objmap.rs | 8 ++--- vm/src/obj/objmemory.rs | 6 ++-- vm/src/obj/objnone.rs | 4 +-- vm/src/obj/objobject.rs | 8 ++--- vm/src/obj/objproperty.rs | 4 +-- vm/src/obj/objrange.rs | 8 ++--- vm/src/obj/objsequence.rs | 6 ++-- vm/src/obj/objset.rs | 8 ++--- vm/src/obj/objslice.rs | 8 ++--- vm/src/obj/objstr.rs | 10 +++--- vm/src/obj/objsuper.rs | 4 +-- vm/src/obj/objtuple.rs | 6 ++-- vm/src/obj/objtype.rs | 10 +++--- vm/src/obj/objzip.rs | 8 ++--- vm/src/pyobject.rs | 64 ++++++++++++++++++------------------ vm/src/stdlib/ast.rs | 6 ++-- vm/src/stdlib/io.rs | 12 +++---- vm/src/stdlib/json.rs | 6 ++-- vm/src/stdlib/keyword.rs | 6 ++-- vm/src/stdlib/math.rs | 6 ++-- vm/src/stdlib/mod.rs | 2 +- vm/src/stdlib/os.rs | 12 +++---- vm/src/stdlib/pystruct.rs | 6 ++-- vm/src/stdlib/random.rs | 6 ++-- vm/src/stdlib/re.rs | 6 ++-- vm/src/stdlib/string.rs | 2 +- vm/src/stdlib/time_module.rs | 6 ++-- vm/src/stdlib/tokenize.rs | 6 ++-- vm/src/stdlib/types.rs | 8 ++--- vm/src/stdlib/weakref.rs | 6 ++-- vm/src/vm.rs | 28 ++++++++-------- 55 files changed, 245 insertions(+), 265 deletions(-) diff --git a/parser/src/parser.rs b/parser/src/parser.rs index ec9cba45e..fb8f2f0e5 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -1,10 +1,10 @@ use std::iter; -use super::ast; -use super::error::ParseError; -use super::lexer; -use super::python; -use super::token; +use crate::ast; +use crate::error::ParseError; +use crate::lexer; +use crate::python; +use crate::token; /* * Parse python code. diff --git a/src/main.rs b/src/main.rs index 90e4788cf..1c87719e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,10 +19,7 @@ use rustpython_vm::{ util, VirtualMachine, }; use rustyline::{error::ReadlineError, Editor}; -use std::{ - error::Error, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; fn main() { env_logger::init(); diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 18cc80646..3266b2fbc 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -4,24 +4,23 @@ // use std::ops::Deref; use std::char; -use std::error::Error; use std::io::{self, Write}; -use super::compile; -use super::obj::objbool; -use super::obj::objdict; -use super::obj::objint; -use super::obj::objiter; -use super::obj::objstr; -use super::obj::objtype; +use crate::compile; +use crate::obj::objbool; +use crate::obj::objdict; +use crate::obj::objint; +use crate::obj::objiter; +use crate::obj::objstr; +use crate::obj::objtype; -use super::pyobject::{ +use crate::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, Scope, TypeProtocol, }; -use super::stdlib::io::io_open; +use crate::stdlib::io::io_open; -use super::vm::VirtualMachine; +use crate::vm::VirtualMachine; use num_traits::{Signed, ToPrimitive}; fn get_locals(vm: &mut VirtualMachine) -> PyObjectRef { diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 99fcde36e..bb4c670e0 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -5,9 +5,9 @@ //! https://github.com/python/cpython/blob/master/Python/compile.c //! https://github.com/micropython/micropython/blob/master/py/compile.c -use super::bytecode::{self, CallType, CodeObject, Instruction}; -use super::error::CompileError; -use super::pyobject::{PyObject, PyObjectPayload, PyObjectRef}; +use crate::bytecode::{self, CallType, CodeObject, Instruction}; +use crate::error::CompileError; +use crate::pyobject::{PyObject, PyObjectPayload, PyObjectRef}; use num_complex::Complex64; use rustpython_parser::{ast, parser}; @@ -1401,10 +1401,10 @@ impl Compiler { #[cfg(test)] mod tests { - use super::bytecode::CodeObject; - use super::bytecode::Constant::*; - use super::bytecode::Instruction::*; use super::Compiler; + use crate::bytecode::CodeObject; + use crate::bytecode::Constant::*; + use crate::bytecode::Instruction::*; use rustpython_parser::parser; fn compile_exec(source: &str) -> CodeObject { let mut compiler = Compiler::new(); diff --git a/vm/src/dictdatatype.rs b/vm/src/dictdatatype.rs index 3c4dee22a..a94208104 100644 --- a/vm/src/dictdatatype.rs +++ b/vm/src/dictdatatype.rs @@ -1,7 +1,7 @@ -use super::obj::objbool; -use super::obj::objint; -use super::pyobject::{IdProtocol, PyObjectRef, PyResult}; -use super::vm::VirtualMachine; +use crate::obj::objbool; +use crate::obj::objint; +use crate::pyobject::{IdProtocol, PyObjectRef, PyResult}; +use crate::vm::VirtualMachine; use num_traits::ToPrimitive; /// Ordered dictionary implementation. /// Inspired by: https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html diff --git a/vm/src/eval.rs b/vm/src/eval.rs index de075e05f..30c6034f5 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -2,9 +2,9 @@ extern crate rustpython_parser; use std::error::Error; -use super::compile; -use super::pyobject::{PyObjectRef, PyResult}; -use super::vm::VirtualMachine; +use crate::compile; +use crate::pyobject::{PyObjectRef, PyResult}; +use crate::vm::VirtualMachine; pub fn eval( vm: &mut VirtualMachine, diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 6780c07e0..cf3018426 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -1,10 +1,10 @@ -use super::obj::objsequence; -use super::obj::objstr; -use super::obj::objtype; -use super::pyobject::{ +use crate::obj::objsequence; +use crate::obj::objstr; +use crate::obj::objtype; +use crate::pyobject::{ create_type, AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, }; -use super::vm::VirtualMachine; +use crate::vm::VirtualMachine; fn exception_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let zelf = args.args[0].clone(); diff --git a/vm/src/frame.rs b/vm/src/frame.rs index b1374b2f3..5de7f6809 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -5,21 +5,21 @@ use std::fmt; use std::mem; use std::path::PathBuf; -use super::builtins; -use super::bytecode; -use super::import::{import, import_module}; -use super::obj::objbool; -use super::obj::objcode; -use super::obj::objdict; -use super::obj::objiter; -use super::obj::objlist; -use super::obj::objstr; -use super::obj::objtype; -use super::pyobject::{ +use crate::builtins; +use crate::bytecode; +use crate::import::{import, import_module}; +use crate::obj::objbool; +use crate::obj::objcode; +use crate::obj::objdict; +use crate::obj::objiter; +use crate::obj::objlist; +use crate::obj::objstr; +use crate::obj::objtype; +use crate::pyobject::{ DictProtocol, IdProtocol, ParentProtocol, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::vm::VirtualMachine; +use crate::vm::VirtualMachine; use num_bigint::BigInt; #[derive(Clone, Debug)] diff --git a/vm/src/import.rs b/vm/src/import.rs index 31a4101d5..b0b53156c 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -5,11 +5,11 @@ use std::error::Error; use std::path::PathBuf; -use super::compile; -use super::pyobject::{AttributeProtocol, DictProtocol, PyResult}; -use super::util; -use super::vm::VirtualMachine; +use crate::compile; use crate::obj::{objsequence, objstr}; +use crate::pyobject::{AttributeProtocol, DictProtocol, PyResult}; +use crate::util; +use crate::vm::VirtualMachine; fn import_uncached_module( vm: &mut VirtualMachine, diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index dbec65a7c..c5c9cb43b 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -1,8 +1,8 @@ -use super::super::pyobject::{ +use super::objtype; +use crate::pyobject::{ PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objtype; +use crate::vm::VirtualMachine; use num_traits::Zero; pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result { diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 180f6ef1a..9222dd8dc 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -1,15 +1,13 @@ //! Implementation of the python bytearray object. -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; use super::objint; -use super::super::vm::VirtualMachine; use super::objbytes::get_mut_value; use super::objbytes::get_value; use super::objtype; +use crate::vm::VirtualMachine; use num_traits::ToPrimitive; // Binary data support diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 11a0c7b0b..f63a9c80d 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -1,9 +1,9 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objint; use super::objtype; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_traits::ToPrimitive; use std::cell::Ref; use std::cell::RefMut; diff --git a/vm/src/obj/objcode.rs b/vm/src/obj/objcode.rs index d98eeab2d..4310caf83 100644 --- a/vm/src/obj/objcode.rs +++ b/vm/src/obj/objcode.rs @@ -2,12 +2,12 @@ */ -use super::super::bytecode; -use super::super::pyobject::{ +use super::objtype; +use crate::bytecode; +use crate::pyobject::{ IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objtype; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let code_type = &context.code_type; diff --git a/vm/src/obj/objcomplex.rs b/vm/src/obj/objcomplex.rs index c3035cd7c..a7b1aaac9 100644 --- a/vm/src/obj/objcomplex.rs +++ b/vm/src/obj/objcomplex.rs @@ -1,10 +1,10 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objfloat; use super::objint; use super::objtype; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_complex::Complex64; use num_traits::ToPrimitive; diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 84b6a0ab9..42e188b46 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -1,11 +1,11 @@ -use super::super::pyobject::{ - PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TypeProtocol, -}; -use super::super::vm::{ReprGuard, VirtualMachine}; use super::objiter; use super::objstr; use super::objtype; +use crate::pyobject::{ + PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, +}; +use crate::vm::{ReprGuard, VirtualMachine}; use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; diff --git a/vm/src/obj/objenumerate.rs b/vm/src/obj/objenumerate.rs index 40e444be4..98a1aef04 100644 --- a/vm/src/obj/objenumerate.rs +++ b/vm/src/obj/objenumerate.rs @@ -1,10 +1,8 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objint; use super::objiter; use super::objtype; // Required for arg_check! to use isinstance +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; use num_bigint::BigInt; use num_traits::Zero; use std::ops::AddAssign; diff --git a/vm/src/obj/objfilter.rs b/vm/src/obj/objfilter.rs index 60598bfa8..71f5e47cc 100644 --- a/vm/src/obj/objfilter.rs +++ b/vm/src/obj/objfilter.rs @@ -1,10 +1,10 @@ -use super::super::pyobject::{ - IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objbool; use super::objiter; -use super::objtype; // Required for arg_check! to use isinstance +use super::objtype; +use crate::pyobject::{ + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance fn filter_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 74e950615..f299251f1 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -1,11 +1,11 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objbytes; use super::objint; use super::objstr; use super::objtype; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_bigint::ToBigInt; use num_traits::ToPrimitive; diff --git a/vm/src/obj/objframe.rs b/vm/src/obj/objframe.rs index 43a88e2ec..a30ffa8d4 100644 --- a/vm/src/obj/objframe.rs +++ b/vm/src/obj/objframe.rs @@ -2,12 +2,12 @@ */ -use super::super::frame::Frame; -use super::super::pyobject::{ +use super::objtype; +use crate::frame::Frame; +use crate::pyobject::{ PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objtype; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let frame_type = &context.frame_type; diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index f74aa11d1..bc69826ac 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,8 +1,8 @@ -use super::super::pyobject::{ +use super::objtype; +use crate::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objtype; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let function_type = &context.function_type; diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index b1a726844..be04777f3 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -2,12 +2,12 @@ * The mythical generator. */ -use super::super::frame::{ExecutionResult, Frame}; -use super::super::pyobject::{ +use super::objtype; +use crate::frame::{ExecutionResult, Frame}; +use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objtype; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let generator_type = &context.generator_type; diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 697dc03ac..b5e38d830 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -1,12 +1,12 @@ -use super::super::format::FormatSpec; -use super::super::pyobject::{ - FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objfloat; use super::objstr; use super::objtype; +use crate::format::FormatSpec; +use crate::pyobject::{ + FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_bigint::{BigInt, ToBigInt}; use num_integer::Integer; use num_traits::{Pow, Signed, ToPrimitive, Zero}; diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs index 9fbc3a5d6..a3e30a152 100644 --- a/vm/src/obj/objiter.rs +++ b/vm/src/obj/objiter.rs @@ -2,11 +2,11 @@ * Various types to support iteration. */ -use super::super::pyobject::{ +use super::objbool; +use crate::pyobject::{ PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objbool; +use crate::vm::VirtualMachine; // use super::objstr; use super::objtype; // Required for arg_check! to use isinstance diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 431ae6eb4..53f0d7498 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -1,8 +1,3 @@ -use super::super::pyobject::{ - IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TypeProtocol, -}; -use super::super::vm::{ReprGuard, VirtualMachine}; use super::objbool; use super::objint; use super::objsequence::{ @@ -11,6 +6,11 @@ use super::objsequence::{ }; use super::objstr; use super::objtype; +use crate::pyobject::{ + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, +}; +use crate::vm::{ReprGuard, VirtualMachine}; use num_traits::ToPrimitive; // set_item: diff --git a/vm/src/obj/objmap.rs b/vm/src/obj/objmap.rs index 472c223cf..1e9d5c384 100644 --- a/vm/src/obj/objmap.rs +++ b/vm/src/obj/objmap.rs @@ -1,9 +1,7 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objiter; -use super::objtype; // Required for arg_check! to use isinstance +use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance fn map_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { no_kwargs!(vm, args); diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index 5976208ff..deb204bde 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -1,9 +1,7 @@ use super::objtype; -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(cls, None), (bytes_object, None)]); diff --git a/vm/src/obj/objnone.rs b/vm/src/obj/objnone.rs index d9aa6361f..fb990b201 100644 --- a/vm/src/obj/objnone.rs +++ b/vm/src/obj/objnone.rs @@ -1,6 +1,6 @@ -use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; -use super::super::vm::VirtualMachine; use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let none_type = &context.none.typ(); diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 0bbcac5d1..62f31b8c2 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -1,10 +1,10 @@ -use super::super::pyobject::{ +use super::objstr; +use super::objtype; +use crate::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; -use super::objstr; -use super::objtype; +use crate::vm::VirtualMachine; use std::cell::RefCell; use std::collections::HashMap; diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 92d7bacba..3adef7ece 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -2,9 +2,9 @@ */ -use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; -use super::super::vm::VirtualMachine; use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let property_type = &context.property_type; diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs index c95407f62..c5075ccbd 100644 --- a/vm/src/obj/objrange.rs +++ b/vm/src/obj/objrange.rs @@ -1,9 +1,9 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objint; use super::objtype; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_bigint::{BigInt, Sign}; use num_integer::Integer; use num_traits::{One, Signed, ToPrimitive, Zero}; diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index eed4ca60d..b52c8e04d 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -1,9 +1,7 @@ -use super::super::pyobject::{ - IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objbool; use super::objint; +use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; use num_bigint::BigInt; use num_traits::{One, Signed, ToPrimitive, Zero}; use std::cell::{Ref, RefMut}; diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index a7a036995..a0f600fec 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -2,15 +2,15 @@ * Builtin set type with a sequence of unique items. */ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::{ReprGuard, VirtualMachine}; use super::objbool; use super::objint; use super::objiter; use super::objstr; use super::objtype; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::{ReprGuard, VirtualMachine}; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::hash::{Hash, Hasher}; diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs index 547e252ba..318d85fa3 100644 --- a/vm/src/obj/objslice.rs +++ b/vm/src/obj/objslice.rs @@ -1,9 +1,9 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objint; use super::objtype; // Required for arg_check! to use isinstance +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_bigint::BigInt; fn slice_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index a0b651f5e..9c2051e6f 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1,11 +1,11 @@ -use super::super::format::{FormatParseError, FormatPart, FormatString}; -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objint; use super::objsequence::PySliceableSequence; use super::objtype; +use crate::format::{FormatParseError, FormatPart, FormatString}; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use num_traits::ToPrimitive; use std::cell::Ref; use std::hash::{Hash, Hasher}; diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index dd752c959..79c516d4c 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -6,9 +6,9 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/ */ -use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; -use super::super::vm::VirtualMachine; use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { let super_type = &context.super_type; diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index be5df653c..81e3b9959 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -1,7 +1,3 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::{ReprGuard, VirtualMachine}; use super::objbool; use super::objint; use super::objsequence::{ @@ -9,6 +5,8 @@ use super::objsequence::{ }; use super::objstr; use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::vm::{ReprGuard, VirtualMachine}; use std::hash::{Hash, Hasher}; fn tuple_lt(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 95c493a45..aa7618e38 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -1,11 +1,11 @@ -use super::super::pyobject::{ - AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, - PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objdict; use super::objstr; use super::objtype; // Required for arg_check! to use isinstance +use crate::pyobject::{ + AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, + PyObjectRef, PyResult, TypeProtocol, +}; +use crate::vm::VirtualMachine; use std::cell::RefCell; use std::collections::HashMap; diff --git a/vm/src/obj/objzip.rs b/vm/src/obj/objzip.rs index bb10b55d7..337c7cecd 100644 --- a/vm/src/obj/objzip.rs +++ b/vm/src/obj/objzip.rs @@ -1,9 +1,7 @@ -use super::super::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, -}; -use super::super::vm::VirtualMachine; use super::objiter; -use super::objtype; // Required for arg_check! to use isinstance +use super::objtype; +use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance fn zip_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { no_kwargs!(vm, args); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 4ec2058e4..0158028d0 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,35 +1,35 @@ -use super::bytecode; -use super::exceptions; -use super::frame::Frame; -use super::obj::objbool; -use super::obj::objbytearray; -use super::obj::objbytes; -use super::obj::objcode; -use super::obj::objcomplex; -use super::obj::objdict; -use super::obj::objenumerate; -use super::obj::objfilter; -use super::obj::objfloat; -use super::obj::objframe; -use super::obj::objfunction; -use super::obj::objgenerator; -use super::obj::objint; -use super::obj::objiter; -use super::obj::objlist; -use super::obj::objmap; -use super::obj::objmemory; -use super::obj::objnone; -use super::obj::objobject; -use super::obj::objproperty; -use super::obj::objrange; -use super::obj::objset; -use super::obj::objslice; -use super::obj::objstr; -use super::obj::objsuper; -use super::obj::objtuple; -use super::obj::objtype; -use super::obj::objzip; -use super::vm::VirtualMachine; +use crate::bytecode; +use crate::exceptions; +use crate::frame::Frame; +use crate::obj::objbool; +use crate::obj::objbytearray; +use crate::obj::objbytes; +use crate::obj::objcode; +use crate::obj::objcomplex; +use crate::obj::objdict; +use crate::obj::objenumerate; +use crate::obj::objfilter; +use crate::obj::objfloat; +use crate::obj::objframe; +use crate::obj::objfunction; +use crate::obj::objgenerator; +use crate::obj::objint; +use crate::obj::objiter; +use crate::obj::objlist; +use crate::obj::objmap; +use crate::obj::objmemory; +use crate::obj::objnone; +use crate::obj::objobject; +use crate::obj::objproperty; +use crate::obj::objrange; +use crate::obj::objset; +use crate::obj::objslice; +use crate::obj::objstr; +use crate::obj::objsuper; +use crate::obj::objtuple; +use crate::obj::objtype; +use crate::obj::objzip; +use crate::vm::VirtualMachine; use num_bigint::BigInt; use num_bigint::ToBigInt; use num_complex::Complex64; diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 3073d0a44..eda853b17 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -6,9 +6,9 @@ extern crate rustpython_parser; use self::rustpython_parser::{ast, parser}; -use super::super::obj::{objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objstr, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; use num_complex::Complex64; use std::ops::Deref; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 63627a10f..6345c56a0 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -13,18 +13,18 @@ use num_bigint::ToBigInt; use num_traits::ToPrimitive; //custom imports -use super::super::obj::objbytes; -use super::super::obj::objint; -use super::super::obj::objstr; -use super::super::obj::objtype; use super::os; +use crate::obj::objbytes; +use crate::obj::objint; +use crate::obj::objstr; +use crate::obj::objtype; -use super::super::pyobject::{ +use crate::pyobject::{ AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::vm::VirtualMachine; +use crate::vm::VirtualMachine; fn compute_c_flag(mode: &str) -> u16 { match mode { diff --git a/vm/src/stdlib/json.rs b/vm/src/stdlib/json.rs index f71210933..53507e81d 100644 --- a/vm/src/stdlib/json.rs +++ b/vm/src/stdlib/json.rs @@ -5,12 +5,12 @@ use serde::de::{DeserializeSeed, Visitor}; use serde::ser::{SerializeMap, SerializeSeq}; use serde_json; -use super::super::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype}; -use super::super::pyobject::{ +use crate::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype}; +use crate::pyobject::{ create_type, DictProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::super::VirtualMachine; +use crate::VirtualMachine; use num_traits::cast::ToPrimitive; // We need to have a VM available to serialise a PyObject based on its subclass, so we implement diff --git a/vm/src/stdlib/keyword.rs b/vm/src/stdlib/keyword.rs index c34876c56..a609538cd 100644 --- a/vm/src/stdlib/keyword.rs +++ b/vm/src/stdlib/keyword.rs @@ -4,9 +4,9 @@ extern crate rustpython_parser; use self::rustpython_parser::lexer; -use super::super::obj::{objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objstr, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; fn keyword_iskeyword(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]); diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index eedae4f78..a38698356 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -3,9 +3,9 @@ * */ -use super::super::obj::{objfloat, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objfloat, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; use statrs::function::erf::{erf, erfc}; use statrs::function::gamma::{gamma, ln_gamma}; use std; diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index 159d1cd53..2c915c84e 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -14,7 +14,7 @@ mod types; mod weakref; use std::collections::HashMap; -use super::pyobject::{PyContext, PyObjectRef}; +use crate::pyobject::{PyContext, PyObjectRef}; pub type StdlibInitFunc = fn(&PyContext) -> PyObjectRef; diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 83e770f2c..f3d993165 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -8,13 +8,13 @@ use std::io::ErrorKind; use num_traits::cast::ToPrimitive; //custom imports -use super::super::obj::objint; -use super::super::obj::objstr; -use super::super::obj::objtype; -// use super::super::obj::objdict; +use crate::obj::objint; +use crate::obj::objstr; +use crate::obj::objtype; +// use crate::obj::objdict; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::vm::VirtualMachine; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; #[cfg(target_family = "unix")] pub fn raw_file_number(handle: File) -> i64 { diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs index 1178649e1..8c12674cf 100644 --- a/vm/src/stdlib/pystruct.rs +++ b/vm/src/stdlib/pystruct.rs @@ -10,9 +10,9 @@ extern crate byteorder; use self::byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use super::super::obj::{objbool, objbytes, objfloat, objint, objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objbool, objbytes, objfloat, objint, objstr, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; use num_bigint::BigInt; use num_traits::ToPrimitive; use std::io::{Cursor, Read, Write}; diff --git a/vm/src/stdlib/random.rs b/vm/src/stdlib/random.rs index 417cf8fa2..38c4f16ec 100644 --- a/vm/src/stdlib/random.rs +++ b/vm/src/stdlib/random.rs @@ -2,10 +2,10 @@ extern crate rand; -use super::super::obj::{objfloat, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objfloat, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::stdlib::random::rand::distributions::{Distribution, Normal}; +use crate::VirtualMachine; pub fn mk_module(ctx: &PyContext) -> PyObjectRef { let py_mod = ctx.new_module(&"random".to_string(), ctx.new_scope(None)); diff --git a/vm/src/stdlib/re.rs b/vm/src/stdlib/re.rs index d05c50e0f..476764738 100644 --- a/vm/src/stdlib/re.rs +++ b/vm/src/stdlib/re.rs @@ -8,9 +8,9 @@ extern crate regex; use self::regex::Regex; -use super::super::obj::{objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objstr, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; fn re_match(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // TODO: diff --git a/vm/src/stdlib/string.rs b/vm/src/stdlib/string.rs index 16fb3e0bd..07f62b497 100644 --- a/vm/src/stdlib/string.rs +++ b/vm/src/stdlib/string.rs @@ -3,7 +3,7 @@ * */ -use super::super::pyobject::{PyContext, PyObjectRef}; +use crate::pyobject::{PyContext, PyObjectRef}; pub fn mk_module(ctx: &PyContext) -> PyObjectRef { let py_mod = ctx.new_module(&"string".to_string(), ctx.new_scope(None)); diff --git a/vm/src/stdlib/time_module.rs b/vm/src/stdlib/time_module.rs index a36560fa5..a3496d9e5 100644 --- a/vm/src/stdlib/time_module.rs +++ b/vm/src/stdlib/time_module.rs @@ -1,8 +1,8 @@ //! The python `time` module. -use super::super::obj::{objfloat, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objfloat, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; use std::thread; use std::time::{Duration, SystemTime, UNIX_EPOCH}; diff --git a/vm/src/stdlib/tokenize.rs b/vm/src/stdlib/tokenize.rs index c190cc2a1..66d03daf9 100644 --- a/vm/src/stdlib/tokenize.rs +++ b/vm/src/stdlib/tokenize.rs @@ -7,9 +7,9 @@ use std::iter::FromIterator; use self::rustpython_parser::lexer; -use super::super::obj::{objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::VirtualMachine; +use crate::obj::{objstr, objtype}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; fn tokenize_tokenize(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(readline, Some(vm.ctx.str_type()))]); diff --git a/vm/src/stdlib/types.rs b/vm/src/stdlib/types.rs index a744d89b7..b5a0997c3 100644 --- a/vm/src/stdlib/types.rs +++ b/vm/src/stdlib/types.rs @@ -2,11 +2,9 @@ * Dynamic type creation and names for built in types. */ -use super::super::obj::{objsequence, objstr, objtype}; -use super::super::pyobject::{ - PyAttributes, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, -}; -use super::super::VirtualMachine; +use crate::obj::{objsequence, objstr, objtype}; +use crate::pyobject::{PyAttributes, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::VirtualMachine; fn types_new_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( diff --git a/vm/src/stdlib/weakref.rs b/vm/src/stdlib/weakref.rs index 8f407675b..65248879e 100644 --- a/vm/src/stdlib/weakref.rs +++ b/vm/src/stdlib/weakref.rs @@ -5,12 +5,12 @@ //! - [rust weak struct](https://doc.rust-lang.org/std/rc/struct.Weak.html) //! -use super::super::obj::objtype; -use super::super::pyobject::{ +use crate::obj::objtype; +use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyObjectWeakRef, PyResult, TypeProtocol, }; -use super::super::VirtualMachine; +use crate::VirtualMachine; use std::rc::Rc; pub fn mk_module(ctx: &PyContext) -> PyObjectRef { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 5302bbf4c..f6d8c37c9 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -10,22 +10,22 @@ use std::collections::hash_map::HashMap; use std::collections::hash_set::HashSet; use std::sync::{Mutex, MutexGuard}; -use super::builtins; -use super::bytecode; -use super::frame::Frame; -use super::obj::objbool; -use super::obj::objcode; -use super::obj::objgenerator; -use super::obj::objiter; -use super::obj::objsequence; -use super::obj::objstr; -use super::obj::objtype; -use super::pyobject::{ +use crate::builtins; +use crate::bytecode; +use crate::frame::Frame; +use crate::obj::objbool; +use crate::obj::objcode; +use crate::obj::objgenerator; +use crate::obj::objiter; +use crate::obj::objsequence; +use crate::obj::objstr; +use crate::obj::objtype; +use crate::pyobject::{ AttributeProtocol, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; -use super::stdlib; -use super::sysmodule; +use crate::stdlib; +use crate::sysmodule; // use objects::objects; @@ -812,8 +812,8 @@ impl Drop for ReprGuard { #[cfg(test)] mod tests { - use super::super::obj::{objint, objstr}; use super::VirtualMachine; + use crate::obj::{objint, objstr}; use num_bigint::ToBigInt; #[test] From b833c0895195cbe31168e84d9f859bee41eab06b Mon Sep 17 00:00:00 2001 From: janczer Date: Tue, 19 Feb 2019 18:27:18 +0100 Subject: [PATCH 48/80] Add bytearray.{lower, upper} --- tests/snippets/bytearray.py | 10 ++++++++-- vm/src/obj/objbytearray.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/tests/snippets/bytearray.py b/tests/snippets/bytearray.py index 8654c8cc3..563da2c53 100644 --- a/tests/snippets/bytearray.py +++ b/tests/snippets/bytearray.py @@ -18,13 +18,19 @@ assert not bytearray(b'abc1').isalpha() assert bytearray(b'1234567890').isdigit() assert not bytearray(b'12ab').isdigit() -assert bytearray(b'lower').islower() +l = bytearray(b'lower') +assert l.islower() +assert not l.isupper() +assert l.upper().isupper() assert not bytearray(b'Super Friends').islower() assert bytearray(b' \n\t').isspace() assert not bytearray(b'\td\n').isspace() -assert bytearray(b'UPPER').isupper() +b = bytearray(b'UPPER') +assert b.isupper() +assert not b.islower() +assert b.lower().islower() assert not bytearray(b'tuPpEr').isupper() assert bytearray(b'Is Title Case').istitle() diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 180f6ef1a..10e08ff3f 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -102,6 +102,16 @@ pub fn init(context: &PyContext) { context.new_rustfunc(bytearray_clear), ); context.set_attr(&bytearray_type, "pop", context.new_rustfunc(bytearray_pop)); + context.set_attr( + &bytearray_type, + "lower", + context.new_rustfunc(bytearray_lower), + ); + context.set_attr( + &bytearray_type, + "upper", + context.new_rustfunc(bytearray_upper), + ); } fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -188,7 +198,7 @@ fn bytearray_islower(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { !bytes.is_empty() && bytes .iter() - .filter(|x| char::from(**x).is_whitespace()) + .filter(|x| !char::from(**x).is_whitespace()) .all(|x| char::from(*x).is_lowercase()), )) } @@ -295,3 +305,21 @@ fn bytearray_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Err(vm.new_index_error("pop from empty bytearray".to_string())) } } + +fn bytearray_lower(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]); + let value = get_value(obj).to_vec().to_ascii_lowercase(); + Ok(PyObject::new( + PyObjectPayload::Bytes { value }, + vm.ctx.bytearray_type(), + )) +} + +fn bytearray_upper(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]); + let value = get_value(obj).to_vec().to_ascii_uppercase(); + Ok(PyObject::new( + PyObjectPayload::Bytes { value }, + vm.ctx.bytearray_type(), + )) +} From 8c222af65bfc11ddc0cffcd3cfc99fd1f37e21b3 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Wed, 20 Feb 2019 22:33:52 -0600 Subject: [PATCH 49/80] Include details about thread_local! for WASM --- wasm/lib/src/vm_class.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index 8a6593f67..3d63beaa6 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -29,7 +29,9 @@ impl StoredVirtualMachine { } } -// It's fine that it's thread local, since WASM doesn't even have threads yet +// It's fine that it's thread local, since WASM doesn't even have threads yet. thread_local! probably +// gets compiled down to a normal-ish static varible, like Atomic* types: +// https://rustwasm.github.io/2018/10/24/multithreading-rust-and-wasm.html#atomic-instructions thread_local! { static STORED_VMS: PyRef>> = Rc::default(); static ACTIVE_VMS: PyRef> = Rc::default(); From 4b03e6d706277b919183d772150403548b14736c Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 12:47:30 +0000 Subject: [PATCH 50/80] Add Display implementation for CodeObject. --- vm/src/bytecode.rs | 132 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/vm/src/bytecode.rs b/vm/src/bytecode.rs index 951659f06..1e0b85f13 100644 --- a/vm/src/bytecode.rs +++ b/vm/src/bytecode.rs @@ -8,7 +8,7 @@ use num_bigint::BigInt; use num_complex::Complex64; use rustpython_parser::ast; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fmt; /// Primary container of a single code object. Each python function has @@ -173,6 +173,8 @@ pub enum Instruction { }, } +use self::Instruction::*; + #[derive(Debug, Clone, PartialEq)] pub enum CallType { Positional(usize), @@ -277,17 +279,123 @@ impl CodeObject { } } -impl fmt::Debug for CodeObject { +impl fmt::Display for CodeObject { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let inst_str = self - .instructions - .iter() - .zip(self.locations.iter()) - .enumerate() - .map(|(i, inst)| format!("Inst {}: {:?}", i, inst)) - .collect::>() - .join("\n"); - let labelmap_str = format!("label_map: {:?}", self.label_map); - write!(f, "Code Object {{ \n{}\n{} }}", inst_str, labelmap_str) + let label_targets: HashSet<&usize> = self.label_map.values().collect(); + for (offset, instruction) in self.instructions.iter().enumerate() { + let arrow = if label_targets.contains(&offset) { + ">>" + } else { + " " + }; + write!(f, " {} {:5} ", arrow, offset)?; + instruction.fmt_dis(f, &self.label_map)?; + } + Ok(()) + } +} + +impl Instruction { + fn fmt_dis(&self, f: &mut fmt::Formatter, label_map: &HashMap) -> fmt::Result { + macro_rules! w { + ($variant:ident) => { + write!(f, "{:20}\n", stringify!($variant)) + }; + ($variant:ident, $var:expr) => { + write!(f, "{:20} ({})\n", stringify!($variant), $var) + }; + ($variant:ident, $var1:expr, $var2:expr) => { + write!(f, "{:20} ({}, {})\n", stringify!($variant), $var1, $var2) + }; + } + + match self { + Import { name, symbol } => w!(Import, name, format!("{:?}", symbol)), + ImportStar { name } => w!(ImportStar, name), + LoadName { name } => w!(LoadName, name), + StoreName { name } => w!(StoreName, name), + DeleteName { name } => w!(DeleteName, name), + StoreSubscript => w!(StoreSubscript), + DeleteSubscript => w!(DeleteSubscript), + StoreAttr { name } => w!(StoreAttr, name), + DeleteAttr { name } => w!(DeleteAttr, name), + LoadConst { value } => w!(LoadConst, value), + UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)), + BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace), + LoadAttr { name } => w!(LoadAttr, name), + CompareOperation { op } => w!(CompareOperation, format!("{:?}", op)), + Pop => w!(Pop), + Rotate { amount } => w!(Rotate, amount), + Duplicate => w!(Duplicate), + GetIter => w!(GetIter), + Pass => w!(Pass), + Continue => w!(Continue), + Break => w!(Break), + Jump { target } => w!(Jump, label_map[target]), + JumpIf { target } => w!(JumpIf, label_map[target]), + JumpIfFalse { target } => w!(JumpIfFalse, label_map[target]), + MakeFunction { flags } => w!(MakeFunction, format!("{:?}", flags)), + CallFunction { typ } => w!(CallFunction, format!("{:?}", typ)), + ForIter { target } => w!(ForIter, label_map[target]), + ReturnValue => w!(ReturnValue), + YieldValue => w!(YieldValue), + YieldFrom => w!(YieldFrom), + SetupLoop { start, end } => w!(SetupLoop, label_map[start], label_map[end]), + SetupExcept { handler } => w!(SetupExcept, handler), + SetupWith { end } => w!(SetupWith, end), + CleanupWith { end } => w!(CleanupWith, end), + PopBlock => w!(PopBlock), + Raise { argc } => w!(Raise, argc), + BuildString { size } => w!(BuildString, size), + BuildTuple { size, unpack } => w!(BuildTuple, size, unpack), + BuildList { size, unpack } => w!(BuildList, size, unpack), + BuildSet { size, unpack } => w!(BuildSet, size, unpack), + BuildMap { size, unpack } => w!(BuildMap, size, unpack), + BuildSlice { size } => w!(BuildSlice, size), + ListAppend { i } => w!(ListAppend, i), + SetAdd { i } => w!(SetAdd, i), + MapAdd { i } => w!(MapAdd, i), + PrintExpr => w!(PrintExpr), + LoadBuildClass => w!(LoadBuildClass), + StoreLocals => w!(StoreLocals), + UnpackSequence { size } => w!(UnpackSequence, size), + UnpackEx { before, after } => w!(UnpackEx, before, after), + Unpack => w!(Unpack), + FormatValue { spec } => w!(FormatValue, spec), + } + } +} + +impl fmt::Display for Constant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Constant::Integer { value } => write!(f, "{}", value), + Constant::Float { value } => write!(f, "{}", value), + Constant::Complex { value } => write!(f, "{}", value), + Constant::Boolean { value } => write!(f, "{}", value), + Constant::String { value } => write!(f, "{:?}", value), + Constant::Bytes { value } => write!(f, "{:?}", value), + Constant::Code { code } => write!(f, "{:?}", code), + Constant::Tuple { elements } => write!( + f, + "({})", + elements + .iter() + .map(|e| format!("{}", e)) + .collect::>() + .join(", ") + ), + Constant::None => write!(f, "None"), + } + } +} + +impl fmt::Debug for CodeObject { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "", + self.obj_name, self.source_path, self.first_line_number + ) } } From 5ebfd55b20d55f29b4a4d091bf4853549b813dba Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 12:48:33 +0000 Subject: [PATCH 51/80] Add extremely minimal dis module. --- tests/snippets/dismod.py | 10 ++++++++++ vm/src/stdlib/dis.rs | 18 ++++++++++++++++++ vm/src/stdlib/mod.rs | 2 ++ 3 files changed, 30 insertions(+) create mode 100644 tests/snippets/dismod.py create mode 100644 vm/src/stdlib/dis.rs diff --git a/tests/snippets/dismod.py b/tests/snippets/dismod.py new file mode 100644 index 000000000..cc9c1f63b --- /dev/null +++ b/tests/snippets/dismod.py @@ -0,0 +1,10 @@ +import dis + +dis.disassemble(compile("5 + x + 5 or 2", "", "eval")) +print("\n") +dis.disassemble(compile("def f(x):\n return 1", "", "exec")) +print("\n") +dis.disassemble(compile("if a:\n 1 or 2\nelif x == 'hello':\n 3\nelse:\n 4", "", "exec")) +print("\n") +dis.disassemble(compile("f(x=1, y=2)", "", "eval")) +print("\n") diff --git a/vm/src/stdlib/dis.rs b/vm/src/stdlib/dis.rs new file mode 100644 index 000000000..ec95725e7 --- /dev/null +++ b/vm/src/stdlib/dis.rs @@ -0,0 +1,18 @@ +use super::super::obj::objcode; +use super::super::obj::objtype; +use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use super::super::vm::VirtualMachine; + +fn dis_disassemble(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(co, Some(vm.ctx.code_type()))]); + + let code = objcode::get_value(co); + print!("{}", code); + Ok(vm.get_none()) +} + +pub fn mk_module(ctx: &PyContext) -> PyObjectRef { + let py_mod = ctx.new_module("dis", ctx.new_scope(None)); + ctx.set_attr(&py_mod, "disassemble", ctx.new_rustfunc(dis_disassemble)); + py_mod +} diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index 159d1cd53..9b6158d21 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -1,4 +1,5 @@ mod ast; +mod dis; pub mod io; mod json; mod keyword; @@ -21,6 +22,7 @@ pub type StdlibInitFunc = fn(&PyContext) -> PyObjectRef; pub fn get_module_inits() -> HashMap { let mut modules = HashMap::new(); modules.insert("ast".to_string(), ast::mk_module as StdlibInitFunc); + modules.insert("dis".to_string(), dis::mk_module as StdlibInitFunc); modules.insert("io".to_string(), io::mk_module as StdlibInitFunc); modules.insert("json".to_string(), json::mk_module as StdlibInitFunc); modules.insert("keyword".to_string(), keyword::mk_module as StdlibInitFunc); From 0175780cc3cbf784bdefa384e436404083e389e5 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 14:05:16 +0000 Subject: [PATCH 52/80] py_module macro to make modules definitions more declarative. --- vm/src/macros.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 2b06a825d..af2d26b98 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -105,3 +105,15 @@ macro_rules! no_kwargs { } }; } + +macro_rules! py_module { + ( $ctx:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)* }) => { + { + let py_mod = $ctx.new_module($module_name, $ctx.new_scope(None)); + $( + $ctx.set_attr(&py_mod, $name, $value); + )* + py_mod + } + } +} From 727b895930920a3d83151759c6df15de7f08a626 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 14:06:24 +0000 Subject: [PATCH 53/80] Use py_module for math. --- vm/src/stdlib/math.rs | 92 +++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index eedae4f78..362b4cd1c 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -172,57 +172,55 @@ fn math_lgamma(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn mk_module(ctx: &PyContext) -> PyObjectRef { - let py_mod = ctx.new_module(&"math".to_string(), ctx.new_scope(None)); + py_module!(ctx, "math", { + // Number theory functions: + "fabs" => ctx.new_rustfunc(math_fabs), + "isfinite" => ctx.new_rustfunc(math_isfinite), + "isinf" => ctx.new_rustfunc(math_isinf), + "isnan" => ctx.new_rustfunc(math_isnan), - // Number theory functions: - ctx.set_attr(&py_mod, "fabs", ctx.new_rustfunc(math_fabs)); - ctx.set_attr(&py_mod, "isfinite", ctx.new_rustfunc(math_isfinite)); - ctx.set_attr(&py_mod, "isinf", ctx.new_rustfunc(math_isinf)); - ctx.set_attr(&py_mod, "isnan", ctx.new_rustfunc(math_isnan)); + // Power and logarithmic functions: + "exp" => ctx.new_rustfunc(math_exp), + "expm1" => ctx.new_rustfunc(math_expm1), + "log" => ctx.new_rustfunc(math_log), + "log1p" => ctx.new_rustfunc(math_log1p), + "log2" => ctx.new_rustfunc(math_log2), + "log10" => ctx.new_rustfunc(math_log10), + "pow" => ctx.new_rustfunc(math_pow), + "sqrt" => ctx.new_rustfunc(math_sqrt), - // Power and logarithmic functions: - ctx.set_attr(&py_mod, "exp", ctx.new_rustfunc(math_exp)); - ctx.set_attr(&py_mod, "expm1", ctx.new_rustfunc(math_expm1)); - ctx.set_attr(&py_mod, "log", ctx.new_rustfunc(math_log)); - ctx.set_attr(&py_mod, "log1p", ctx.new_rustfunc(math_log1p)); - ctx.set_attr(&py_mod, "log2", ctx.new_rustfunc(math_log2)); - ctx.set_attr(&py_mod, "log10", ctx.new_rustfunc(math_log10)); - ctx.set_attr(&py_mod, "pow", ctx.new_rustfunc(math_pow)); - ctx.set_attr(&py_mod, "sqrt", ctx.new_rustfunc(math_sqrt)); + // Trigonometric functions: + "acos" => ctx.new_rustfunc(math_acos), + "asin" => ctx.new_rustfunc(math_asin), + "atan" => ctx.new_rustfunc(math_atan), + "atan2" => ctx.new_rustfunc(math_atan2), + "cos" => ctx.new_rustfunc(math_cos), + "hypot" => ctx.new_rustfunc(math_hypot), + "sin" => ctx.new_rustfunc(math_sin), + "tan" => ctx.new_rustfunc(math_tan), - // Trigonometric functions: - ctx.set_attr(&py_mod, "acos", ctx.new_rustfunc(math_acos)); - ctx.set_attr(&py_mod, "asin", ctx.new_rustfunc(math_asin)); - ctx.set_attr(&py_mod, "atan", ctx.new_rustfunc(math_atan)); - ctx.set_attr(&py_mod, "atan2", ctx.new_rustfunc(math_atan2)); - ctx.set_attr(&py_mod, "cos", ctx.new_rustfunc(math_cos)); - ctx.set_attr(&py_mod, "hypot", ctx.new_rustfunc(math_hypot)); - ctx.set_attr(&py_mod, "sin", ctx.new_rustfunc(math_sin)); - ctx.set_attr(&py_mod, "tan", ctx.new_rustfunc(math_tan)); + "degrees" => ctx.new_rustfunc(math_degrees), + "radians" => ctx.new_rustfunc(math_radians), - ctx.set_attr(&py_mod, "degrees", ctx.new_rustfunc(math_degrees)); - ctx.set_attr(&py_mod, "radians", ctx.new_rustfunc(math_radians)); + // Hyperbolic functions: + "acosh" => ctx.new_rustfunc(math_acosh), + "asinh" => ctx.new_rustfunc(math_asinh), + "atanh" => ctx.new_rustfunc(math_atanh), + "cosh" => ctx.new_rustfunc(math_cosh), + "sinh" => ctx.new_rustfunc(math_sinh), + "tanh" => ctx.new_rustfunc(math_tanh), - // Hyperbolic functions: - ctx.set_attr(&py_mod, "acosh", ctx.new_rustfunc(math_acosh)); - ctx.set_attr(&py_mod, "asinh", ctx.new_rustfunc(math_asinh)); - ctx.set_attr(&py_mod, "atanh", ctx.new_rustfunc(math_atanh)); - ctx.set_attr(&py_mod, "cosh", ctx.new_rustfunc(math_cosh)); - ctx.set_attr(&py_mod, "sinh", ctx.new_rustfunc(math_sinh)); - ctx.set_attr(&py_mod, "tanh", ctx.new_rustfunc(math_tanh)); + // Special functions: + "erf" => ctx.new_rustfunc(math_erf), + "erfc" => ctx.new_rustfunc(math_erfc), + "gamma" => ctx.new_rustfunc(math_gamma), + "lgamma" => ctx.new_rustfunc(math_lgamma), - // Special functions: - ctx.set_attr(&py_mod, "erf", ctx.new_rustfunc(math_erf)); - ctx.set_attr(&py_mod, "erfc", ctx.new_rustfunc(math_erfc)); - ctx.set_attr(&py_mod, "gamma", ctx.new_rustfunc(math_gamma)); - ctx.set_attr(&py_mod, "lgamma", ctx.new_rustfunc(math_lgamma)); - - // Constants: - ctx.set_attr(&py_mod, "pi", ctx.new_float(std::f64::consts::PI)); // 3.14159... - ctx.set_attr(&py_mod, "e", ctx.new_float(std::f64::consts::E)); // 2.71.. - ctx.set_attr(&py_mod, "tau", ctx.new_float(2.0 * std::f64::consts::PI)); - ctx.set_attr(&py_mod, "inf", ctx.new_float(std::f64::INFINITY)); - ctx.set_attr(&py_mod, "nan", ctx.new_float(std::f64::NAN)); - - py_mod + // Constants: + "pi" => ctx.new_float(std::f64::consts::PI), // 3.14159... + "e" => ctx.new_float(std::f64::consts::E), // 2.71.. + "tau" => ctx.new_float(2.0 * std::f64::consts::PI), + "inf" => ctx.new_float(std::f64::INFINITY), + "nan" => ctx.new_float(std::f64::NAN) + }) } From 55148d7d5aab087f2907fa9f556e057995ed0adf Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 14:06:43 +0000 Subject: [PATCH 54/80] Use py_module for random. --- vm/src/stdlib/random.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/vm/src/stdlib/random.rs b/vm/src/stdlib/random.rs index 417cf8fa2..d982e5340 100644 --- a/vm/src/stdlib/random.rs +++ b/vm/src/stdlib/random.rs @@ -8,17 +8,12 @@ use super::super::VirtualMachine; use crate::stdlib::random::rand::distributions::{Distribution, Normal}; pub fn mk_module(ctx: &PyContext) -> PyObjectRef { - let py_mod = ctx.new_module(&"random".to_string(), ctx.new_scope(None)); - ctx.set_attr(&py_mod, "gauss", ctx.new_rustfunc(random_gauss)); - ctx.set_attr( - &py_mod, - "normalvariate", - ctx.new_rustfunc(random_normalvariate), - ); - ctx.set_attr(&py_mod, "random", ctx.new_rustfunc(random_random)); - // py_mod.set_attr("weibull", ctx.new_rustfunc(random_weibullvariate)); - // TODO: implement more random functions. - py_mod + py_module!(ctx, "random", { + "guass" => ctx.new_rustfunc(random_gauss), + "normalvariate" => ctx.new_rustfunc(random_normalvariate), + "random" => ctx.new_rustfunc(random_random), + // "weibull", ctx.new_rustfunc(random_weibullvariate), + }) } fn random_gauss(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { From 7e40b7f6484f3a02575845fe59c16dce0e61a055 Mon Sep 17 00:00:00 2001 From: Joey Date: Thu, 21 Feb 2019 08:27:35 -0800 Subject: [PATCH 55/80] Compile error message cleanup --- parser/src/ast.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ vm/src/compile.rs | 8 ++++---- vm/src/error.rs | 29 ++++++++++++++++------------- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 558e9f6eb..e607c4e4b 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -219,6 +219,50 @@ pub enum Expression { None, } +impl Expression { + /// Returns a short name for the node suitable for use in error messages. + pub fn name(&self) -> &'static str { + use self::Expression::*; + use self::StringGroup::*; + + match self { + BoolOp { .. } | Binop { .. } | Unop { .. } => "operator", + Subscript { .. } => "subscript", + Yield { .. } | YieldFrom { .. } => "yield expression", + Compare { .. } => "comparison", + Attribute { .. } => "attribute", + Call { .. } => "function call", + Number { .. } + | String { + value: Constant { .. }, + } + | Bytes { .. } => "literal", + List { .. } => "list", + Tuple { .. } => "tuple", + Dict { .. } => "dict display", + Set { .. } => "set display", + Comprehension { kind, .. } => match **kind { + ComprehensionKind::List { .. } => "list comprehension", + ComprehensionKind::Dict { .. } => "dict comprehension", + ComprehensionKind::Set { .. } => "set comprehension", + ComprehensionKind::GeneratorExpression { .. } => "generator expression", + }, + Starred { .. } => "starred", + Slice { .. } => "slice", + String { + value: Joined { .. }, + } + | String { + value: FormattedValue { .. }, + } => "f-string expression", + Identifier { .. } => "named expression", + Lambda { .. } => "lambda", + IfExpression { .. } => "conditional expression", + True | False | None => "keyword", + } + } +} + /* * In cpython this is called arguments, but we choose parameters to * distinguish between function parameters and actual call arguments. diff --git a/vm/src/compile.rs b/vm/src/compile.rs index bb4c670e0..866b0dad7 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -573,13 +573,13 @@ impl Compiler { } ast::Statement::Break => { if !self.in_loop { - return Err(CompileError::SyntaxErr(String::from("break"))); + return Err(CompileError::InvalidBreak); } self.emit(Instruction::Break); } ast::Statement::Continue => { if !self.in_loop { - return Err(CompileError::SyntaxErr(String::from("continue"))); + return Err(CompileError::InvalidContinue); } self.emit(Instruction::Continue); } @@ -646,7 +646,7 @@ impl Compiler { self.emit(Instruction::DeleteSubscript); } _ => { - return Err(CompileError::Delete); + return Err(CompileError::Delete(target.name())); } } } @@ -766,7 +766,7 @@ impl Compiler { } } _ => { - return Err(CompileError::Assign(format!("{:?}", target))); + return Err(CompileError::Assign(target.name())); } } diff --git a/vm/src/error.rs b/vm/src/error.rs index 0b98ab816..70c8ff71e 100644 --- a/vm/src/error.rs +++ b/vm/src/error.rs @@ -5,29 +5,32 @@ use std::fmt; #[derive(Debug)] pub enum CompileError { - // Invalid assignment, cannot store value in target. - Assign(String), - // Invalid delete - Delete, - // Expected an expression got a statement + /// Invalid assignment, cannot store value in target. + Assign(&'static str), + /// Invalid delete + Delete(&'static str), + /// Expected an expression got a statement ExpectExpr, - // Parser error + /// Parser error Parse(ParseError), - // Multiple `*` detected + /// Multiple `*` detected StarArgs, - // Catches errors undetectable by the parser - SyntaxErr(String), + /// Break statement outside of loop. + InvalidBreak, + /// Continue statement outside of loop. + InvalidContinue, } impl fmt::Display for CompileError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - CompileError::Assign(expr) => write!(f, "Invalid assignment: {}", expr), - CompileError::Delete => write!(f, "Invalid delete statement"), + CompileError::Assign(target) => write!(f, "can't assign to {}", target), + CompileError::Delete(target) => write!(f, "can't delete {}", target), CompileError::ExpectExpr => write!(f, "Expecting expression, got statement"), - CompileError::Parse(err) => err.fmt(f), + CompileError::Parse(err) => write!(f, "{}", err), CompileError::StarArgs => write!(f, "Two starred expressions in assignment"), - CompileError::SyntaxErr(expr) => write!(f, "Syntax Error: '{}' ouside loop", expr), + CompileError::InvalidBreak => write!(f, "break outside loop"), + CompileError::InvalidContinue => write!(f, "continue outside loop"), } } } From a89b0593da5aa7145e68b784041854a1c536f47b Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Tue, 19 Feb 2019 21:31:09 +0200 Subject: [PATCH 56/80] Add set.pop --- tests/snippets/set.py | 7 +++++++ vm/src/obj/objset.rs | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index 48c6185d5..b2931aa5b 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -86,3 +86,10 @@ assert len(b) == 3 b.clear() assert len(a) == 3 assert len(b) == 0 + +a = set([1,2]) +b = a.pop() +assert b in [1,2] +c = a.pop() +assert (c in [1,2] and c != b) +assert_raises(KeyError, lambda: a.pop()) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index a0f600fec..9d6249d82 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -418,6 +418,20 @@ fn set_combine_inner( )) } +fn set_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]); + + let mut mut_obj = s.borrow_mut(); + + match mut_obj.payload { + PyObjectPayload::Set { ref mut elements } => match elements.clone().keys().next() { + Some(key) => Ok(elements.remove(key).unwrap()), + None => Err(vm.new_key_error("pop from an empty set".to_string())), + }, + _ => Err(vm.new_type_error("".to_string())), + } +} + fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); @@ -488,6 +502,7 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "discard", context.new_rustfunc(set_discard)); context.set_attr(&set_type, "clear", context.new_rustfunc(set_clear)); context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy)); + context.set_attr(&set_type, "pop", context.new_rustfunc(set_pop)); let frozenset_type = &context.frozenset_type; From 5f3664e87de846a358b1bfb243c2e362cfb1ea70 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Tue, 19 Feb 2019 22:06:17 +0200 Subject: [PATCH 57/80] Add set.update --- tests/snippets/set.py | 5 +++++ vm/src/obj/objset.rs | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index b2931aa5b..9601c059f 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -93,3 +93,8 @@ assert b in [1,2] c = a.pop() assert (c in [1,2] and c != b) assert_raises(KeyError, lambda: a.pop()) + +a = set([1,2,3]) +a.update([3,4,5]) +assert a == set([1,2,3,4,5]) +assert_raises(TypeError, lambda: a.update(1)) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 9d6249d82..9f1437216 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -432,6 +432,27 @@ fn set_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)] + ); + + let mut mut_obj = zelf.borrow_mut(); + + match mut_obj.payload { + PyObjectPayload::Set { ref mut elements } => { + let iterator = objiter::get_iter(vm, iterable)?; + while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) { + insert_into_set(vm, elements, &v)?; + } + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("set.update is called with no other".to_string())), + } +} + fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); @@ -503,6 +524,7 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "clear", context.new_rustfunc(set_clear)); context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy)); context.set_attr(&set_type, "pop", context.new_rustfunc(set_pop)); + context.set_attr(&set_type, "update", context.new_rustfunc(set_update)); let frozenset_type = &context.frozenset_type; From eec76ef8e802976262bde433ac6a45fe5c70b73d Mon Sep 17 00:00:00 2001 From: Joey Date: Thu, 21 Feb 2019 08:37:24 -0800 Subject: [PATCH 58/80] Don't require objtype import to use arg_check! macro --- vm/src/macros.rs | 2 +- vm/src/obj/objcode.rs | 1 - vm/src/obj/objenumerate.rs | 1 - vm/src/obj/objfilter.rs | 1 - vm/src/obj/objframe.rs | 1 - vm/src/obj/objfunction.rs | 1 - vm/src/obj/objgenerator.rs | 1 - vm/src/obj/objmap.rs | 1 - vm/src/obj/objmemory.rs | 2 -- vm/src/obj/objnone.rs | 1 - vm/src/obj/objproperty.rs | 1 - vm/src/obj/objslice.rs | 1 - vm/src/obj/objzip.rs | 1 - vm/src/stdlib/ast.rs | 2 +- vm/src/stdlib/io.rs | 1 - vm/src/stdlib/keyword.rs | 2 +- vm/src/stdlib/math.rs | 2 +- vm/src/stdlib/os.rs | 1 - vm/src/stdlib/random.rs | 2 +- vm/src/stdlib/re.rs | 2 +- vm/src/stdlib/time_module.rs | 2 +- vm/src/stdlib/tokenize.rs | 2 +- vm/src/stdlib/weakref.rs | 1 - vm/src/sysmodule.rs | 1 - 24 files changed, 8 insertions(+), 25 deletions(-) diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 2b06a825d..6394f7d8e 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -15,7 +15,7 @@ macro_rules! type_check { // None indicates that we have no type requirement (i.e. we accept any type) if let Some(expected_type) = $arg_type { let arg = &$args.args[$arg_count]; - if !objtype::isinstance(arg, &expected_type) { + if !$crate::obj::objtype::isinstance(arg, &expected_type) { let arg_typ = arg.typ(); let expected_type_name = $vm.to_pystr(&expected_type)?; let actual_type = $vm.to_pystr(&arg_typ)?; diff --git a/vm/src/obj/objcode.rs b/vm/src/obj/objcode.rs index 4310caf83..05d1b6238 100644 --- a/vm/src/obj/objcode.rs +++ b/vm/src/obj/objcode.rs @@ -2,7 +2,6 @@ */ -use super::objtype; use crate::bytecode; use crate::pyobject::{ IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, diff --git a/vm/src/obj/objenumerate.rs b/vm/src/obj/objenumerate.rs index 98a1aef04..9e5f369f1 100644 --- a/vm/src/obj/objenumerate.rs +++ b/vm/src/obj/objenumerate.rs @@ -1,6 +1,5 @@ use super::objint; use super::objiter; -use super::objtype; // Required for arg_check! to use isinstance use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; use num_bigint::BigInt; diff --git a/vm/src/obj/objfilter.rs b/vm/src/obj/objfilter.rs index 71f5e47cc..1fe163374 100644 --- a/vm/src/obj/objfilter.rs +++ b/vm/src/obj/objfilter.rs @@ -1,6 +1,5 @@ use super::objbool; use super::objiter; -use super::objtype; use crate::pyobject::{ IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol, }; diff --git a/vm/src/obj/objframe.rs b/vm/src/obj/objframe.rs index a30ffa8d4..3f9dd07d7 100644 --- a/vm/src/obj/objframe.rs +++ b/vm/src/obj/objframe.rs @@ -2,7 +2,6 @@ */ -use super::objtype; use crate::frame::Frame; use crate::pyobject::{ PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index bc69826ac..d59c7bb28 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,4 +1,3 @@ -use super::objtype; use crate::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyResult, TypeProtocol, }; diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index be04777f3..0f204e5ba 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -2,7 +2,6 @@ * The mythical generator. */ -use super::objtype; use crate::frame::{ExecutionResult, Frame}; use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, diff --git a/vm/src/obj/objmap.rs b/vm/src/obj/objmap.rs index 1e9d5c384..9ba88955b 100644 --- a/vm/src/obj/objmap.rs +++ b/vm/src/obj/objmap.rs @@ -1,5 +1,4 @@ use super::objiter; -use super::objtype; use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index deb204bde..8119f9fee 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -1,5 +1,3 @@ -use super::objtype; - use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; diff --git a/vm/src/obj/objnone.rs b/vm/src/obj/objnone.rs index fb990b201..2aceea915 100644 --- a/vm/src/obj/objnone.rs +++ b/vm/src/obj/objnone.rs @@ -1,4 +1,3 @@ -use super::objtype; use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 3adef7ece..0a952375d 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -2,7 +2,6 @@ */ -use super::objtype; use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; diff --git a/vm/src/obj/objslice.rs b/vm/src/obj/objslice.rs index 318d85fa3..19abc214f 100644 --- a/vm/src/obj/objslice.rs +++ b/vm/src/obj/objslice.rs @@ -1,5 +1,4 @@ use super::objint; -use super::objtype; // Required for arg_check! to use isinstance use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; diff --git a/vm/src/obj/objzip.rs b/vm/src/obj/objzip.rs index 337c7cecd..43005f416 100644 --- a/vm/src/obj/objzip.rs +++ b/vm/src/obj/objzip.rs @@ -1,5 +1,4 @@ use super::objiter; -use super::objtype; use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index eda853b17..682b297c6 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -6,7 +6,7 @@ extern crate rustpython_parser; use self::rustpython_parser::{ast, parser}; -use crate::obj::{objstr, objtype}; +use crate::obj::objstr; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; use num_complex::Complex64; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 6345c56a0..0d7a46ee0 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -17,7 +17,6 @@ use super::os; use crate::obj::objbytes; use crate::obj::objint; use crate::obj::objstr; -use crate::obj::objtype; use crate::pyobject::{ AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, diff --git a/vm/src/stdlib/keyword.rs b/vm/src/stdlib/keyword.rs index a609538cd..5d353fffa 100644 --- a/vm/src/stdlib/keyword.rs +++ b/vm/src/stdlib/keyword.rs @@ -4,7 +4,7 @@ extern crate rustpython_parser; use self::rustpython_parser::lexer; -use crate::obj::{objstr, objtype}; +use crate::obj::objstr; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index a38698356..b6b576eb8 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -3,7 +3,7 @@ * */ -use crate::obj::{objfloat, objtype}; +use crate::obj::objfloat; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; use statrs::function::erf::{erf, erfc}; diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index f3d993165..142816996 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -10,7 +10,6 @@ use num_traits::cast::ToPrimitive; //custom imports use crate::obj::objint; use crate::obj::objstr; -use crate::obj::objtype; // use crate::obj::objdict; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; diff --git a/vm/src/stdlib/random.rs b/vm/src/stdlib/random.rs index 38c4f16ec..1b6c67adc 100644 --- a/vm/src/stdlib/random.rs +++ b/vm/src/stdlib/random.rs @@ -2,7 +2,7 @@ extern crate rand; -use crate::obj::{objfloat, objtype}; +use crate::obj::objfloat; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::stdlib::random::rand::distributions::{Distribution, Normal}; use crate::VirtualMachine; diff --git a/vm/src/stdlib/re.rs b/vm/src/stdlib/re.rs index 476764738..0c0cef934 100644 --- a/vm/src/stdlib/re.rs +++ b/vm/src/stdlib/re.rs @@ -8,7 +8,7 @@ extern crate regex; use self::regex::Regex; -use crate::obj::{objstr, objtype}; +use crate::obj::objstr; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; diff --git a/vm/src/stdlib/time_module.rs b/vm/src/stdlib/time_module.rs index a3496d9e5..1f96a4ba4 100644 --- a/vm/src/stdlib/time_module.rs +++ b/vm/src/stdlib/time_module.rs @@ -1,6 +1,6 @@ //! The python `time` module. -use crate::obj::{objfloat, objtype}; +use crate::obj::objfloat; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; use std::thread; diff --git a/vm/src/stdlib/tokenize.rs b/vm/src/stdlib/tokenize.rs index 66d03daf9..cbd4a7870 100644 --- a/vm/src/stdlib/tokenize.rs +++ b/vm/src/stdlib/tokenize.rs @@ -7,7 +7,7 @@ use std::iter::FromIterator; use self::rustpython_parser::lexer; -use crate::obj::{objstr, objtype}; +use crate::obj::objstr; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; diff --git a/vm/src/stdlib/weakref.rs b/vm/src/stdlib/weakref.rs index 65248879e..0fc087867 100644 --- a/vm/src/stdlib/weakref.rs +++ b/vm/src/stdlib/weakref.rs @@ -5,7 +5,6 @@ //! - [rust weak struct](https://doc.rust-lang.org/std/rc/struct.Weak.html) //! -use crate::obj::objtype; use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyObjectWeakRef, PyResult, TypeProtocol, diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index e7aad4430..8ee1f52fe 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -1,4 +1,3 @@ -use crate::obj::objtype; use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; use std::rc::Rc; From a4b814e9a73d730666381f488926fbbc7455ab93 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Thu, 21 Feb 2019 18:55:22 +0200 Subject: [PATCH 59/80] Add set.intersection_update --- tests/snippets/set.py | 5 +++++ vm/src/obj/objset.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index 9601c059f..8e983fb6c 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -98,3 +98,8 @@ a = set([1,2,3]) a.update([3,4,5]) assert a == set([1,2,3,4,5]) assert_raises(TypeError, lambda: a.update(1)) + +a = set([1,2,3]) +a.intersection_update([2,3,4,5]) +assert a == set([2,3]) +assert_raises(TypeError, lambda: a.intersection_update(1)) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 9f1437216..07b7a8279 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -453,6 +453,29 @@ fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +fn set_intersection_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)] + ); + + let mut mut_obj = zelf.borrow_mut(); + + match mut_obj.payload { + PyObjectPayload::Set { ref mut elements } => { + for element in elements.clone().iter() { + let value = vm.call_method(iterable, "__contains__", vec![element.1.clone()])?; + if !objbool::get_value(&value) { + elements.remove(&element.0.clone()); + } + } + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("".to_string())), + } +} + fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); @@ -525,6 +548,11 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy)); context.set_attr(&set_type, "pop", context.new_rustfunc(set_pop)); context.set_attr(&set_type, "update", context.new_rustfunc(set_update)); + context.set_attr( + &set_type, + "intersection_update", + context.new_rustfunc(set_intersection_update), + ); let frozenset_type = &context.frozenset_type; From 1621d783264b98e906eb25e1901585069c4eb115 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Thu, 21 Feb 2019 19:02:05 +0200 Subject: [PATCH 60/80] Add set.difference_update --- tests/snippets/set.py | 5 +++++ vm/src/obj/objset.rs | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index 8e983fb6c..e090a1931 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -103,3 +103,8 @@ a = set([1,2,3]) a.intersection_update([2,3,4,5]) assert a == set([2,3]) assert_raises(TypeError, lambda: a.intersection_update(1)) + +a = set([1,2,3]) +a.difference_update([3,4,5]) +assert a == set([1,2]) +assert_raises(TypeError, lambda: a.difference_update(1)) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 07b7a8279..266ddf21c 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -454,6 +454,18 @@ fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn set_intersection_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_combine_update_inner(vm, args, SetCombineOperation::Intersection) +} + +fn set_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_combine_update_inner(vm, args, SetCombineOperation::Difference) +} + +fn set_combine_update_inner( + vm: &mut VirtualMachine, + args: PyFuncArgs, + op: SetCombineOperation, +) -> PyResult { arg_check!( vm, args, @@ -466,7 +478,11 @@ fn set_intersection_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResul PyObjectPayload::Set { ref mut elements } => { for element in elements.clone().iter() { let value = vm.call_method(iterable, "__contains__", vec![element.1.clone()])?; - if !objbool::get_value(&value) { + let should_remove = match op { + SetCombineOperation::Intersection => !objbool::get_value(&value), + SetCombineOperation::Difference => objbool::get_value(&value), + }; + if should_remove { elements.remove(&element.0.clone()); } } @@ -553,6 +569,11 @@ pub fn init(context: &PyContext) { "intersection_update", context.new_rustfunc(set_intersection_update), ); + context.set_attr( + &set_type, + "difference_update", + context.new_rustfunc(set_difference_update), + ); let frozenset_type = &context.frozenset_type; From 21b6616e8e3a031bf230286f97e9be4096443bd6 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Thu, 21 Feb 2019 19:33:20 +0200 Subject: [PATCH 61/80] Add set.symmetric_difference_update --- tests/snippets/set.py | 5 +++++ vm/src/obj/objset.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index e090a1931..be64d92db 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -108,3 +108,8 @@ a = set([1,2,3]) a.difference_update([3,4,5]) assert a == set([1,2]) assert_raises(TypeError, lambda: a.difference_update(1)) + +a = set([1,2,3]) +a.symmetric_difference_update([3,4,5]) +assert a == set([1,2,4,5]) +assert_raises(TypeError, lambda: a.difference_update(1)) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 266ddf21c..5854c94d7 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -492,6 +492,35 @@ fn set_combine_update_inner( } } +fn set_symmetric_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)] + ); + + let mut mut_obj = zelf.borrow_mut(); + + match mut_obj.payload { + PyObjectPayload::Set { ref mut elements } => { + let elements_original = elements.clone(); + let iterator = objiter::get_iter(vm, iterable)?; + while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) { + insert_into_set(vm, elements, &v)?; + } + for element in elements_original.iter() { + let value = vm.call_method(iterable, "__contains__", vec![element.1.clone()])?; + if objbool::get_value(&value) { + elements.remove(&element.0.clone()); + } + } + + Ok(vm.get_none()) + } + _ => Err(vm.new_type_error("".to_string())), + } +} + fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); @@ -574,6 +603,11 @@ pub fn init(context: &PyContext) { "difference_update", context.new_rustfunc(set_difference_update), ); + context.set_attr( + &set_type, + "symmetric_difference_update", + context.new_rustfunc(set_symmetric_difference_update), + ); let frozenset_type = &context.frozenset_type; From 0c1057f0796d5888c1b35a56254591dc3a92c392 Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 13:46:18 -0500 Subject: [PATCH 62/80] Added real/imag attributes to int type. --- vm/src/obj/objint.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 697dc03ac..1f5c56131 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -608,6 +608,18 @@ fn int_conjugate(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_int(v)) } +fn int_real(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]); + let value = BigInt::from_pyobj(zelf); + Ok(vm.ctx.new_int(value)) +} + +fn int_imag(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]); + let value = BigInt::from(0); + Ok(vm.ctx.new_int(value)) +} + pub fn init(context: &PyContext) { let int_doc = "int(x=0) -> integer int(x, base=10) -> integer @@ -680,4 +692,6 @@ Base 0 means to interpret the base from the string as an integer literal. ); context.set_attr(&int_type, "__doc__", context.new_str(int_doc.to_string())); context.set_attr(&int_type, "conjugate", context.new_rustfunc(int_conjugate)); + context.set_attr(&int_type, "real", context.new_property(int_real)); + context.set_attr(&int_type, "imag", context.new_property(int_imag)); } From 852dd1086a46c945e9f7e9e7e0e21ed2a2bebe0b Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 14:11:23 -0500 Subject: [PATCH 63/80] Added tests to imag/real attributes. --- tests/snippets/ints.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/snippets/ints.py b/tests/snippets/ints.py index bc0eef52a..9aa83eba4 100644 --- a/tests/snippets/ints.py +++ b/tests/snippets/ints.py @@ -32,6 +32,11 @@ assert (2).__rmul__(1) == 2 assert (2).__truediv__(1) == 2.0 assert (2).__rtruediv__(1) == 0.5 +# real/imag attributes +assert (1).real == 1 +assert (1).imag == 0 + + assert (1).__eq__(1.0) == NotImplemented assert (1).__ne__(1.0) == NotImplemented assert (1).__gt__(1.0) == NotImplemented From 81a9e6984db0b21df9725e4b26a5756f98835748 Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 14:47:36 -0500 Subject: [PATCH 64/80] Changed syntax in testutils.py that is introduced in 3.6 to a backwards compatible version. --- tests/snippets/testutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py index b5b69b867..8ce02017a 100644 --- a/tests/snippets/testutils.py +++ b/tests/snippets/testutils.py @@ -14,7 +14,7 @@ def assert_raises(exc_type, expr, msg=None): except exc_type: pass else: - failmsg = f'{exc_type.__name__} was not raised' + failmsg = '%s was not raised' % exc_type.__name__ if msg is not None: - failmsg += f': {msg}' + failmsg += ': %s' % msg assert False, failmsg From 365680c27232c7a7a7447c7a8e66f8c200355d3b Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 15:55:18 -0500 Subject: [PATCH 65/80] Changed to syntax RustPython supports. --- tests/snippets/testutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py index 8ce02017a..f00a4977b 100644 --- a/tests/snippets/testutils.py +++ b/tests/snippets/testutils.py @@ -14,7 +14,7 @@ def assert_raises(exc_type, expr, msg=None): except exc_type: pass else: - failmsg = '%s was not raised' % exc_type.__name__ + failmsg = '{!s} was not raised'.format(exc_type.__name__) if msg is not None: - failmsg += ': %s' % msg + failmsg += ': {!s}'.formt(msg) assert False, failmsg From 999ca431d5f68f29c211fa6860c1799ffa278a2d Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 16:03:07 -0500 Subject: [PATCH 66/80] Fixed typo. --- tests/snippets/testutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py index f00a4977b..3c039f4f1 100644 --- a/tests/snippets/testutils.py +++ b/tests/snippets/testutils.py @@ -16,5 +16,5 @@ def assert_raises(exc_type, expr, msg=None): else: failmsg = '{!s} was not raised'.format(exc_type.__name__) if msg is not None: - failmsg += ': {!s}'.formt(msg) + failmsg += ': {!s}'.format(msg) assert False, failmsg From d420c7f4003f5e15d7f84a33e44743f83522fd08 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 21:04:42 +0000 Subject: [PATCH 67/80] dis - use py_module. --- vm/src/stdlib/dis.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/vm/src/stdlib/dis.rs b/vm/src/stdlib/dis.rs index ec95725e7..5e1a30b03 100644 --- a/vm/src/stdlib/dis.rs +++ b/vm/src/stdlib/dis.rs @@ -1,7 +1,6 @@ -use super::super::obj::objcode; -use super::super::obj::objtype; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; -use super::super::vm::VirtualMachine; +use crate::obj::objcode; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; +use crate::vm::VirtualMachine; fn dis_disassemble(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(co, Some(vm.ctx.code_type()))]); @@ -12,7 +11,7 @@ fn dis_disassemble(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn mk_module(ctx: &PyContext) -> PyObjectRef { - let py_mod = ctx.new_module("dis", ctx.new_scope(None)); - ctx.set_attr(&py_mod, "disassemble", ctx.new_rustfunc(dis_disassemble)); - py_mod + py_module!(ctx, "dis", { + "disassemble" => ctx.new_rustfunc(dis_disassemble) + }) } From 2c97a50e6e3435b9316b1c0bea4579375a9b439d Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 21:05:00 +0000 Subject: [PATCH 68/80] sys - use py_module. --- vm/src/sysmodule.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index 8ee1f52fe..1e07b4d9b 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -49,9 +49,6 @@ pub fn mk_module(ctx: &PyContext) -> PyObjectRef { }; let path = ctx.new_list(path_list); - let modules = ctx.new_dict(); - - let sys_name = "sys"; let sys_doc = "This module provides access to some objects used or maintained by the interpreter and to functions that interact strongly with the interpreter. @@ -121,20 +118,22 @@ setprofile() -- set the global profiling function setrecursionlimit() -- set the max recursion depth for the interpreter settrace() -- set the global debug tracing function "; - let sys_mod = ctx.new_module(&sys_name, ctx.new_scope(None)); + let modules = ctx.new_dict(); + let sys_name = "sys"; + let sys_mod = py_module!(ctx, sys_name, { + "argv" => argv(ctx), + "getrefcount" => ctx.new_rustfunc(sys_getrefcount), + "getsizeof" => ctx.new_rustfunc(sys_getsizeof), + "maxsize" => ctx.new_int(std::usize::MAX), + "path" => path, + "ps1" => ctx.new_str(">>>>> ".to_string()), + "ps2" => ctx.new_str("..... ".to_string()), + "__doc__" => ctx.new_str(sys_doc.to_string()), + "_getframe" => ctx.new_rustfunc(getframe), + }); ctx.set_item(&modules, sys_name, sys_mod.clone()); - ctx.set_attr(&sys_mod, "modules", modules); - ctx.set_attr(&sys_mod, "argv", argv(ctx)); - ctx.set_attr(&sys_mod, "getrefcount", ctx.new_rustfunc(sys_getrefcount)); - ctx.set_attr(&sys_mod, "getsizeof", ctx.new_rustfunc(sys_getsizeof)); - ctx.set_attr(&sys_mod, "maxsize", ctx.new_int(std::usize::MAX)); - ctx.set_attr(&sys_mod, "path", path); - ctx.set_attr(&sys_mod, "ps1", ctx.new_str(">>>>> ".to_string())); - ctx.set_attr(&sys_mod, "ps2", ctx.new_str("..... ".to_string())); - ctx.set_attr(&sys_mod, "__doc__", ctx.new_str(sys_doc.to_string())); - ctx.set_attr(&sys_mod, "_getframe", ctx.new_rustfunc(getframe)); sys_mod } From 2ab90b234a3afd79d395875580411d9a660924ac Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 21:05:46 +0000 Subject: [PATCH 69/80] Fix unused variable warning in objint. --- vm/src/obj/objint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 7e3da093e..de53f5082 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -615,7 +615,7 @@ fn int_real(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn int_imag(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]); + arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.int_type()))]); let value = BigInt::from(0); Ok(vm.ctx.new_int(value)) } From 0cbcc70359d186cf15ff1cda5eb0a38f2a0ce490 Mon Sep 17 00:00:00 2001 From: Adam Kelly Date: Thu, 21 Feb 2019 21:14:08 +0000 Subject: [PATCH 70/80] builtins - use py_module. --- vm/src/builtins.rs | 213 ++++++++++++++++++--------------------------- 1 file changed, 85 insertions(+), 128 deletions(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 3266b2fbc..8dc455ccd 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -702,137 +702,94 @@ fn builtin_sum(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // builtin___import__ pub fn make_module(ctx: &PyContext) -> PyObjectRef { - let mod_name = "__builtins__"; - let py_mod = ctx.new_module(mod_name, ctx.new_scope(None)); + py_module!(ctx, "__builtins__", { + //set __name__ fixes: https://github.com/RustPython/RustPython/issues/146 + "__name__" => ctx.new_str(String::from("__main__")), - //set __name__ fixes: https://github.com/RustPython/RustPython/issues/146 - ctx.set_attr(&py_mod, "__name__", ctx.new_str(String::from("__main__"))); + "abs" => ctx.new_rustfunc(builtin_abs), + "all" => ctx.new_rustfunc(builtin_all), + "any" => ctx.new_rustfunc(builtin_any), + "bin" => ctx.new_rustfunc(builtin_bin), + "bool" => ctx.bool_type(), + "bytearray" => ctx.bytearray_type(), + "bytes" => ctx.bytes_type(), + "callable" => ctx.new_rustfunc(builtin_callable), + "chr" => ctx.new_rustfunc(builtin_chr), + "classmethod" => ctx.classmethod_type(), + "compile" => ctx.new_rustfunc(builtin_compile), + "complex" => ctx.complex_type(), + "delattr" => ctx.new_rustfunc(builtin_delattr), + "dict" => ctx.dict_type(), + "divmod" => ctx.new_rustfunc(builtin_divmod), + "dir" => ctx.new_rustfunc(builtin_dir), + "enumerate" => ctx.enumerate_type(), + "eval" => ctx.new_rustfunc(builtin_eval), + "exec" => ctx.new_rustfunc(builtin_exec), + "float" => ctx.float_type(), + "frozenset" => ctx.frozenset_type(), + "filter" => ctx.filter_type(), + "format" => ctx.new_rustfunc(builtin_format), + "getattr" => ctx.new_rustfunc(builtin_getattr), + "hasattr" => ctx.new_rustfunc(builtin_hasattr), + "hash" => ctx.new_rustfunc(builtin_hash), + "hex" => ctx.new_rustfunc(builtin_hex), + "id" => ctx.new_rustfunc(builtin_id), + "int" => ctx.int_type(), + "isinstance" => ctx.new_rustfunc(builtin_isinstance), + "issubclass" => ctx.new_rustfunc(builtin_issubclass), + "iter" => ctx.new_rustfunc(builtin_iter), + "len" => ctx.new_rustfunc(builtin_len), + "list" => ctx.list_type(), + "locals" => ctx.new_rustfunc(builtin_locals), + "map" => ctx.map_type(), + "max" => ctx.new_rustfunc(builtin_max), + "memoryview" => ctx.memoryview_type(), + "min" => ctx.new_rustfunc(builtin_min), + "object" => ctx.object(), + "oct" => ctx.new_rustfunc(builtin_oct), + "open" => ctx.new_rustfunc(io_open), + "ord" => ctx.new_rustfunc(builtin_ord), + "next" => ctx.new_rustfunc(builtin_next), + "pow" => ctx.new_rustfunc(builtin_pow), + "print" => ctx.new_rustfunc(builtin_print), + "property" => ctx.property_type(), + "range" => ctx.range_type(), + "repr" => ctx.new_rustfunc(builtin_repr), + "reversed" => ctx.new_rustfunc(builtin_reversed), + "round" => ctx.new_rustfunc(builtin_round), + "set" => ctx.set_type(), + "setattr" => ctx.new_rustfunc(builtin_setattr), + "slice" => ctx.slice_type(), + "staticmethod" => ctx.staticmethod_type(), + "str" => ctx.str_type(), + "sum" => ctx.new_rustfunc(builtin_sum), + "super" => ctx.super_type(), + "tuple" => ctx.tuple_type(), + "type" => ctx.type_type(), + "zip" => ctx.zip_type(), - ctx.set_attr(&py_mod, "abs", ctx.new_rustfunc(builtin_abs)); - ctx.set_attr(&py_mod, "all", ctx.new_rustfunc(builtin_all)); - ctx.set_attr(&py_mod, "any", ctx.new_rustfunc(builtin_any)); - ctx.set_attr(&py_mod, "bin", ctx.new_rustfunc(builtin_bin)); - ctx.set_attr(&py_mod, "bool", ctx.bool_type()); - ctx.set_attr(&py_mod, "bytearray", ctx.bytearray_type()); - ctx.set_attr(&py_mod, "bytes", ctx.bytes_type()); - ctx.set_attr(&py_mod, "callable", ctx.new_rustfunc(builtin_callable)); - ctx.set_attr(&py_mod, "chr", ctx.new_rustfunc(builtin_chr)); - ctx.set_attr(&py_mod, "classmethod", ctx.classmethod_type()); - ctx.set_attr(&py_mod, "compile", ctx.new_rustfunc(builtin_compile)); - ctx.set_attr(&py_mod, "complex", ctx.complex_type()); - ctx.set_attr(&py_mod, "delattr", ctx.new_rustfunc(builtin_delattr)); - ctx.set_attr(&py_mod, "dict", ctx.dict_type()); - ctx.set_attr(&py_mod, "divmod", ctx.new_rustfunc(builtin_divmod)); - ctx.set_attr(&py_mod, "dir", ctx.new_rustfunc(builtin_dir)); - ctx.set_attr(&py_mod, "enumerate", ctx.enumerate_type()); - ctx.set_attr(&py_mod, "eval", ctx.new_rustfunc(builtin_eval)); - ctx.set_attr(&py_mod, "exec", ctx.new_rustfunc(builtin_exec)); - ctx.set_attr(&py_mod, "float", ctx.float_type()); - ctx.set_attr(&py_mod, "frozenset", ctx.frozenset_type()); - ctx.set_attr(&py_mod, "filter", ctx.filter_type()); - ctx.set_attr(&py_mod, "format", ctx.new_rustfunc(builtin_format)); - ctx.set_attr(&py_mod, "getattr", ctx.new_rustfunc(builtin_getattr)); - ctx.set_attr(&py_mod, "hasattr", ctx.new_rustfunc(builtin_hasattr)); - ctx.set_attr(&py_mod, "hash", ctx.new_rustfunc(builtin_hash)); - ctx.set_attr(&py_mod, "hex", ctx.new_rustfunc(builtin_hex)); - ctx.set_attr(&py_mod, "id", ctx.new_rustfunc(builtin_id)); - ctx.set_attr(&py_mod, "int", ctx.int_type()); - ctx.set_attr(&py_mod, "isinstance", ctx.new_rustfunc(builtin_isinstance)); - ctx.set_attr(&py_mod, "issubclass", ctx.new_rustfunc(builtin_issubclass)); - ctx.set_attr(&py_mod, "iter", ctx.new_rustfunc(builtin_iter)); - ctx.set_attr(&py_mod, "len", ctx.new_rustfunc(builtin_len)); - ctx.set_attr(&py_mod, "list", ctx.list_type()); - ctx.set_attr(&py_mod, "locals", ctx.new_rustfunc(builtin_locals)); - ctx.set_attr(&py_mod, "map", ctx.map_type()); - ctx.set_attr(&py_mod, "max", ctx.new_rustfunc(builtin_max)); - ctx.set_attr(&py_mod, "memoryview", ctx.memoryview_type()); - ctx.set_attr(&py_mod, "min", ctx.new_rustfunc(builtin_min)); - ctx.set_attr(&py_mod, "object", ctx.object()); - ctx.set_attr(&py_mod, "oct", ctx.new_rustfunc(builtin_oct)); - ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(io_open)); - ctx.set_attr(&py_mod, "ord", ctx.new_rustfunc(builtin_ord)); - ctx.set_attr(&py_mod, "next", ctx.new_rustfunc(builtin_next)); - ctx.set_attr(&py_mod, "pow", ctx.new_rustfunc(builtin_pow)); - ctx.set_attr(&py_mod, "print", ctx.new_rustfunc(builtin_print)); - ctx.set_attr(&py_mod, "property", ctx.property_type()); - ctx.set_attr(&py_mod, "range", ctx.range_type()); - ctx.set_attr(&py_mod, "repr", ctx.new_rustfunc(builtin_repr)); - ctx.set_attr(&py_mod, "reversed", ctx.new_rustfunc(builtin_reversed)); - ctx.set_attr(&py_mod, "round", ctx.new_rustfunc(builtin_round)); - ctx.set_attr(&py_mod, "set", ctx.set_type()); - ctx.set_attr(&py_mod, "setattr", ctx.new_rustfunc(builtin_setattr)); - ctx.set_attr(&py_mod, "slice", ctx.slice_type()); - ctx.set_attr(&py_mod, "staticmethod", ctx.staticmethod_type()); - ctx.set_attr(&py_mod, "str", ctx.str_type()); - ctx.set_attr(&py_mod, "sum", ctx.new_rustfunc(builtin_sum)); - ctx.set_attr(&py_mod, "super", ctx.super_type()); - ctx.set_attr(&py_mod, "tuple", ctx.tuple_type()); - ctx.set_attr(&py_mod, "type", ctx.type_type()); - ctx.set_attr(&py_mod, "zip", ctx.zip_type()); + // Constants + "NotImplemented" => ctx.not_implemented.clone(), - // Constants - ctx.set_attr(&py_mod, "NotImplemented", ctx.not_implemented.clone()); - - // Exceptions: - ctx.set_attr( - &py_mod, - "BaseException", - ctx.exceptions.base_exception_type.clone(), - ); - ctx.set_attr(&py_mod, "Exception", ctx.exceptions.exception_type.clone()); - ctx.set_attr( - &py_mod, - "ArithmeticError", - ctx.exceptions.arithmetic_error.clone(), - ); - ctx.set_attr( - &py_mod, - "AssertionError", - ctx.exceptions.assertion_error.clone(), - ); - ctx.set_attr( - &py_mod, - "AttributeError", - ctx.exceptions.attribute_error.clone(), - ); - ctx.set_attr(&py_mod, "NameError", ctx.exceptions.name_error.clone()); - ctx.set_attr( - &py_mod, - "OverflowError", - ctx.exceptions.overflow_error.clone(), - ); - ctx.set_attr( - &py_mod, - "RuntimeError", - ctx.exceptions.runtime_error.clone(), - ); - ctx.set_attr( - &py_mod, - "NotImplementedError", - ctx.exceptions.not_implemented_error.clone(), - ); - ctx.set_attr(&py_mod, "TypeError", ctx.exceptions.type_error.clone()); - ctx.set_attr(&py_mod, "ValueError", ctx.exceptions.value_error.clone()); - ctx.set_attr(&py_mod, "IndexError", ctx.exceptions.index_error.clone()); - ctx.set_attr(&py_mod, "ImportError", ctx.exceptions.import_error.clone()); - ctx.set_attr( - &py_mod, - "FileNotFoundError", - ctx.exceptions.file_not_found_error.clone(), - ); - ctx.set_attr( - &py_mod, - "StopIteration", - ctx.exceptions.stop_iteration.clone(), - ); - ctx.set_attr( - &py_mod, - "ZeroDivisionError", - ctx.exceptions.zero_division_error.clone(), - ); - ctx.set_attr(&py_mod, "KeyError", ctx.exceptions.key_error.clone()); - - py_mod + // Exceptions: + "BaseException" => ctx.exceptions.base_exception_type.clone(), + "Exception" => ctx.exceptions.exception_type.clone(), + "ArithmeticError" => ctx.exceptions.arithmetic_error.clone(), + "AssertionError" => ctx.exceptions.assertion_error.clone(), + "AttributeError" => ctx.exceptions.attribute_error.clone(), + "NameError" => ctx.exceptions.name_error.clone(), + "OverflowError" => ctx.exceptions.overflow_error.clone(), + "RuntimeError" => ctx.exceptions.runtime_error.clone(), + "NotImplementedError" => ctx.exceptions.not_implemented_error.clone(), + "TypeError" => ctx.exceptions.type_error.clone(), + "ValueError" => ctx.exceptions.value_error.clone(), + "IndexError" => ctx.exceptions.index_error.clone(), + "ImportError" => ctx.exceptions.import_error.clone(), + "FileNotFoundError" => ctx.exceptions.file_not_found_error.clone(), + "StopIteration" => ctx.exceptions.stop_iteration.clone(), + "ZeroDivisionError" => ctx.exceptions.zero_division_error.clone(), + "KeyError" => ctx.exceptions.key_error.clone(), + }) } pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { From 38b4c10833810ffc47fa78af95edfefe8dfe99eb Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 19:28:46 -0500 Subject: [PATCH 71/80] Added the ability to do addition between complex numbers and ints. --- tests/snippets/builtin_complex.py | 4 ++++ vm/src/obj/objcomplex.rs | 2 ++ vm/src/obj/objint.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/tests/snippets/builtin_complex.py b/tests/snippets/builtin_complex.py index 6447c1f5b..b979637d7 100644 --- a/tests/snippets/builtin_complex.py +++ b/tests/snippets/builtin_complex.py @@ -38,3 +38,7 @@ assert b.real == 0 assert a.imag == 4 assert b.imag == 4 + +# int and complex addition +assert 1 + 1j == complex(1, 1) +assert 1j + 1 == complex(1, 1) diff --git a/vm/src/obj/objcomplex.rs b/vm/src/obj/objcomplex.rs index a7b1aaac9..ecdbbdb08 100644 --- a/vm/src/obj/objcomplex.rs +++ b/vm/src/obj/objcomplex.rs @@ -106,6 +106,8 @@ fn complex_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let v1 = get_value(i); if objtype::isinstance(i2, &vm.ctx.complex_type()) { Ok(vm.ctx.new_complex(v1 + get_value(i2))) + } else if objtype::isinstance(i2, &vm.ctx.int_type()) { + Ok(vm.ctx.new_complex(Complex64::new(v1.re + objint::get_value(i2).to_f64().unwrap(), v1.im))) } else { Err(vm.new_type_error(format!("Cannot add {} and {}", i.borrow(), i2.borrow()))) } diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index b5e38d830..935980de1 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -1,6 +1,7 @@ use super::objfloat; use super::objstr; use super::objtype; +use super::objcomplex; use crate::format::FormatSpec; use crate::pyobject::{ FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, @@ -10,6 +11,7 @@ use crate::vm::VirtualMachine; use num_bigint::{BigInt, ToBigInt}; use num_integer::Integer; use num_traits::{Pow, Signed, ToPrimitive, Zero}; +use num_complex::Complex64; use std::hash::{Hash, Hasher}; // This proxy allows for easy switching between types. @@ -289,6 +291,8 @@ fn int_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); if objtype::isinstance(other, &vm.ctx.int_type()) { Ok(vm.ctx.new_int(get_value(zelf) + get_value(other))) + } else if objtype::isinstance(other, &vm.ctx.complex_type()) { + Ok(vm.ctx.new_complex(Complex64::new(get_value(zelf).to_f64().unwrap() + objcomplex::get_value(other).re, objcomplex::get_value(other).im))) } else { Ok(vm.ctx.not_implemented()) } From b5188672208c3166a4444423996af62f76d0afb3 Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Thu, 21 Feb 2019 23:41:43 -0300 Subject: [PATCH 72/80] fix typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a49d39499..b060a29e9 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Or use the interactive shell: # Disclaimer - RustPython is in a development phase and should not used in production or a fault intolerant setting. + RustPython is in a development phase and should not be used in production or a fault intolerant setting. Our current build supports only a subset of Python syntax. @@ -55,7 +55,7 @@ $ cargo doc --no-deps --all # Excluding all dependencies Documentation HTML files can then be found in the `target/doc` directory. -If you wish to update the online documentation. Push directly to the `release` branch (or ask a maintainer to do so), this will trigger a Travis build that updates the documentation and WebAssembly demo page. +If you wish to update the online documentation, push directly to the `release` branch (or ask a maintainer to do so). This will trigger a Travis build that updates the documentation and WebAssembly demo page. # Code organization @@ -79,7 +79,7 @@ With that in mind, please note this project is maintained by volunteers, some of Most tasks are listed in the [issue tracker](https://github.com/RustPython/RustPython/issues). Check issues labeled with `good first issue` if you wish to start coding. -Another approach is to checkout the sourcecode: builtin functions and object methods are often the simplest +Another approach is to checkout the source code: builtin functions and object methods are often the simplest and easiest way to contribute. You can also simply run @@ -97,7 +97,7 @@ $ pipenv install $ pipenv run pytest -v ``` -There also are some unittests, you can run those will cargo: +There also are some unit tests, you can run those will cargo: ```shell $ cargo test --all From 9e176902b95dd33765d0e2baf35fac69da310f09 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Thu, 21 Feb 2019 23:25:05 -0600 Subject: [PATCH 73/80] Use crate:: imports --- wasm/lib/src/convert.rs | 2 +- wasm/lib/src/lib.rs | 2 +- wasm/lib/src/vm_class.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index 944e446fd..be3a8ad80 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -1,8 +1,8 @@ +use crate::vm_class::{AccessibleVM, WASMVirtualMachine}; use js_sys::{Array, ArrayBuffer, Object, Reflect, Uint8Array}; use rustpython_vm::obj::{objbytes, objtype}; use rustpython_vm::pyobject::{self, PyFuncArgs, PyObjectRef, PyResult}; use rustpython_vm::VirtualMachine; -use vm_class::{AccessibleVM, WASMVirtualMachine}; use wasm_bindgen::{closure::Closure, prelude::*, JsCast}; pub fn py_str_err(vm: &mut VirtualMachine, py_err: &PyObjectRef) -> String { diff --git a/wasm/lib/src/lib.rs b/wasm/lib/src/lib.rs index 240e7861c..2c69866e9 100644 --- a/wasm/lib/src/lib.rs +++ b/wasm/lib/src/lib.rs @@ -11,7 +11,7 @@ extern crate web_sys; use js_sys::{Object, Reflect, TypeError}; use wasm_bindgen::prelude::*; -pub use vm_class::*; +pub use crate::vm_class::*; const PY_EVAL_VM_ID: &str = "__py_eval_vm"; diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index 8a6593f67..6139dd3c8 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -1,4 +1,5 @@ -use convert; +use crate::convert; +use crate::wasm_builtins::{self, setup_wasm_builtins}; use js_sys::{SyntaxError, TypeError}; use rustpython_vm::{ compile, @@ -9,7 +10,6 @@ use std::cell::RefCell; use std::collections::HashMap; use std::rc::{Rc, Weak}; use wasm_bindgen::prelude::*; -use wasm_builtins::{self, setup_wasm_builtins}; pub(crate) struct StoredVirtualMachine { pub vm: VirtualMachine, From f333c75fd6d2ec963bc326ab89cb82ca690f00b2 Mon Sep 17 00:00:00 2001 From: Adam Gutglick Date: Thu, 21 Feb 2019 19:28:46 -0500 Subject: [PATCH 74/80] Added the ability to do addition between complex numbers and ints. --- tests/snippets/builtin_complex.py | 2 ++ vm/src/obj/objcomplex.rs | 29 ++++++++++++++++++++++++++++- vm/src/obj/objint.rs | 4 ---- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/snippets/builtin_complex.py b/tests/snippets/builtin_complex.py index b979637d7..c073f7433 100644 --- a/tests/snippets/builtin_complex.py +++ b/tests/snippets/builtin_complex.py @@ -42,3 +42,5 @@ assert b.imag == 4 # int and complex addition assert 1 + 1j == complex(1, 1) assert 1j + 1 == complex(1, 1) +assert (1j + 1) + 3 == complex(4, 1) +assert 3 + (1j + 1) == complex(4, 1) diff --git a/vm/src/obj/objcomplex.rs b/vm/src/obj/objcomplex.rs index ecdbbdb08..9182f7bc2 100644 --- a/vm/src/obj/objcomplex.rs +++ b/vm/src/obj/objcomplex.rs @@ -17,6 +17,11 @@ pub fn init(context: &PyContext) { context.set_attr(&complex_type, "__abs__", context.new_rustfunc(complex_abs)); context.set_attr(&complex_type, "__add__", context.new_rustfunc(complex_add)); + context.set_attr( + &complex_type, + "__radd__", + context.new_rustfunc(complex_radd), + ); context.set_attr(&complex_type, "__eq__", context.new_rustfunc(complex_eq)); context.set_attr(&complex_type, "__neg__", context.new_rustfunc(complex_neg)); context.set_attr(&complex_type, "__new__", context.new_rustfunc(complex_new)); @@ -107,7 +112,29 @@ fn complex_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if objtype::isinstance(i2, &vm.ctx.complex_type()) { Ok(vm.ctx.new_complex(v1 + get_value(i2))) } else if objtype::isinstance(i2, &vm.ctx.int_type()) { - Ok(vm.ctx.new_complex(Complex64::new(v1.re + objint::get_value(i2).to_f64().unwrap(), v1.im))) + Ok(vm.ctx.new_complex(Complex64::new( + v1.re + objint::get_value(i2).to_f64().unwrap(), + v1.im, + ))) + } else { + Err(vm.new_type_error(format!("Cannot add {} and {}", i.borrow(), i2.borrow()))) + } +} + +fn complex_radd(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(i, Some(vm.ctx.complex_type())), (i2, None)] + ); + + let v1 = get_value(i); + + if objtype::isinstance(i2, &vm.ctx.int_type()) { + Ok(vm.ctx.new_complex(Complex64::new( + v1.re + objint::get_value(i2).to_f64().unwrap(), + v1.im, + ))) } else { Err(vm.new_type_error(format!("Cannot add {} and {}", i.borrow(), i2.borrow()))) } diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 935980de1..b5e38d830 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -1,7 +1,6 @@ use super::objfloat; use super::objstr; use super::objtype; -use super::objcomplex; use crate::format::FormatSpec; use crate::pyobject::{ FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, @@ -11,7 +10,6 @@ use crate::vm::VirtualMachine; use num_bigint::{BigInt, ToBigInt}; use num_integer::Integer; use num_traits::{Pow, Signed, ToPrimitive, Zero}; -use num_complex::Complex64; use std::hash::{Hash, Hasher}; // This proxy allows for easy switching between types. @@ -291,8 +289,6 @@ fn int_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { ); if objtype::isinstance(other, &vm.ctx.int_type()) { Ok(vm.ctx.new_int(get_value(zelf) + get_value(other))) - } else if objtype::isinstance(other, &vm.ctx.complex_type()) { - Ok(vm.ctx.new_complex(Complex64::new(get_value(zelf).to_f64().unwrap() + objcomplex::get_value(other).re, objcomplex::get_value(other).im))) } else { Ok(vm.ctx.not_implemented()) } From 7cf25440fa4d45e72a5cc601990410c595bcca87 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Fri, 22 Feb 2019 16:16:06 +0200 Subject: [PATCH 75/80] Add set.__iter__ --- tests/snippets/set.py | 7 +++++++ vm/src/obj/objset.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index be64d92db..d3583a324 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -99,6 +99,13 @@ a.update([3,4,5]) assert a == set([1,2,3,4,5]) assert_raises(TypeError, lambda: a.update(1)) +a = set([1,2,3]) +b = set() +for e in a: + assert e == 1 or e == 2 or e == 3 + b.add(e) +assert a == b + a = set([1,2,3]) a.intersection_update([2,3,4,5]) assert a == set([2,3]) diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 5854c94d7..3db9b1d1f 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -521,6 +521,22 @@ fn set_symmetric_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> } } +fn set_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(zelf, Some(vm.ctx.set_type()))]); + + let items = get_elements(zelf).values().map(|x| x.clone()).collect(); + let set_list = vm.ctx.new_list(items); + let iter_obj = PyObject::new( + PyObjectPayload::Iterator { + position: 0, + iterated_obj: set_list, + }, + vm.ctx.iter_type(), + ); + + Ok(iter_obj) +} + fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); @@ -608,6 +624,7 @@ pub fn init(context: &PyContext) { "symmetric_difference_update", context.new_rustfunc(set_symmetric_difference_update), ); + context.set_attr(&set_type, "__iter__", context.new_rustfunc(set_iter)); let frozenset_type = &context.frozenset_type; From fc10560308ed31a78e2137a21a022470076c9276 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Fri, 22 Feb 2019 12:59:24 +0200 Subject: [PATCH 76/80] Add set.{__ior__,__iand__,__isub__,__ixor__} --- tests/snippets/set.py | 40 ++++++++++++++++++++++++++++++++++++++++ vm/src/obj/objset.rs | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index d3583a324..84754bca8 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -106,17 +106,57 @@ for e in a: b.add(e) assert a == b +a = set([1,2,3]) +a |= set([3,4,5]) +assert a == set([1,2,3,4,5]) +try: + a |= 1 +except TypeError: + pass +else: + assert False, "TypeError not raised" + a = set([1,2,3]) a.intersection_update([2,3,4,5]) assert a == set([2,3]) assert_raises(TypeError, lambda: a.intersection_update(1)) +a = set([1,2,3]) +a &= set([2,3,4,5]) +assert a == set([2,3]) +try: + a &= 1 +except TypeError: + pass +else: + assert False, "TypeError not raised" + a = set([1,2,3]) a.difference_update([3,4,5]) assert a == set([1,2]) assert_raises(TypeError, lambda: a.difference_update(1)) +a = set([1,2,3]) +a -= set([3,4,5]) +assert a == set([1,2]) +try: + a -= 1 +except TypeError: + pass +else: + assert False, "TypeError not raised" + a = set([1,2,3]) a.symmetric_difference_update([3,4,5]) assert a == set([1,2,4,5]) assert_raises(TypeError, lambda: a.difference_update(1)) + +a = set([1,2,3]) +a ^= set([3,4,5]) +assert a == set([1,2,4,5]) +try: + a ^= 1 +except TypeError: + pass +else: + assert False, "TypeError not raised" diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index 3db9b1d1f..ebae2b44c 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -433,6 +433,11 @@ fn set_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_ior(vm, args)?; + Ok(vm.get_none()) +} + +fn set_ior(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, args, @@ -447,17 +452,27 @@ fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) { insert_into_set(vm, elements, &v)?; } - Ok(vm.get_none()) } - _ => Err(vm.new_type_error("set.update is called with no other".to_string())), + _ => return Err(vm.new_type_error("set.update is called with no other".to_string())), } + Ok(zelf.clone()) } fn set_intersection_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_combine_update_inner(vm, args, SetCombineOperation::Intersection)?; + Ok(vm.get_none()) +} + +fn set_iand(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { set_combine_update_inner(vm, args, SetCombineOperation::Intersection) } fn set_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_combine_update_inner(vm, args, SetCombineOperation::Difference)?; + Ok(vm.get_none()) +} + +fn set_isub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { set_combine_update_inner(vm, args, SetCombineOperation::Difference) } @@ -486,13 +501,18 @@ fn set_combine_update_inner( elements.remove(&element.0.clone()); } } - Ok(vm.get_none()) } - _ => Err(vm.new_type_error("".to_string())), + _ => return Err(vm.new_type_error("".to_string())), } + Ok(zelf.clone()) } fn set_symmetric_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + set_ixor(vm, args)?; + Ok(vm.get_none()) +} + +fn set_ixor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, args, @@ -514,11 +534,11 @@ fn set_symmetric_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> elements.remove(&element.0.clone()); } } - - Ok(vm.get_none()) } - _ => Err(vm.new_type_error("".to_string())), + _ => return Err(vm.new_type_error("".to_string())), } + + Ok(zelf.clone()) } fn set_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -609,21 +629,25 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy)); context.set_attr(&set_type, "pop", context.new_rustfunc(set_pop)); context.set_attr(&set_type, "update", context.new_rustfunc(set_update)); + context.set_attr(&set_type, "__ior__", context.new_rustfunc(set_ior)); context.set_attr( &set_type, "intersection_update", context.new_rustfunc(set_intersection_update), ); + context.set_attr(&set_type, "__iand__", context.new_rustfunc(set_iand)); context.set_attr( &set_type, "difference_update", context.new_rustfunc(set_difference_update), ); + context.set_attr(&set_type, "__isub__", context.new_rustfunc(set_isub)); context.set_attr( &set_type, "symmetric_difference_update", context.new_rustfunc(set_symmetric_difference_update), ); + context.set_attr(&set_type, "__ixor__", context.new_rustfunc(set_ixor)); context.set_attr(&set_type, "__iter__", context.new_rustfunc(set_iter)); let frozenset_type = &context.frozenset_type; From 7fa0a0cee3a658bb9fd824e0894fefb4458ccdef Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Fri, 22 Feb 2019 22:59:15 -0600 Subject: [PATCH 77/80] Fix open in new make_module --- vm/src/builtins.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index c1b1364f7..a14925add 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -749,7 +749,6 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { "min" => ctx.new_rustfunc(builtin_min), "object" => ctx.object(), "oct" => ctx.new_rustfunc(builtin_oct), - "open" => ctx.new_rustfunc(io_open), "ord" => ctx.new_rustfunc(builtin_ord), "next" => ctx.new_rustfunc(builtin_next), "pow" => ctx.new_rustfunc(builtin_pow), From 09e2a7a493671a4078b8aab904e0eb64bb4d40b6 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sat, 23 Feb 2019 00:02:12 -0600 Subject: [PATCH 78/80] Add js_name for .set_stdout() --- wasm/lib/src/vm_class.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index f17f1bf72..5af38ef39 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -239,6 +239,7 @@ impl WASMVirtualMachine { ) } + #[wasm_bindgen(js_name = setStdout)] pub fn set_stdout(&self, stdout: JsValue) -> Result<(), JsValue> { self.with( move |StoredVirtualMachine { From e0f222cf4f9d3fe85022ecbc5a25cf47b23a9b30 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sat, 23 Feb 2019 00:20:15 -0600 Subject: [PATCH 79/80] Don't hold on to a PyObjectRef from a python -> js closure --- wasm/lib/src/convert.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index be3a8ad80..df63c959e 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -21,10 +21,16 @@ pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue { let wasm_vm = WASMVirtualMachine { id: wasm_id.clone(), }; + let mut py_obj = Some(py_obj); let closure = move |args: Option, kwargs: Option| -> Result { - let py_obj = py_obj.clone(); - wasm_vm.assert_valid()?; + let py_obj = match wasm_vm.assert_valid() { + Ok(_) => py_obj.clone().expect("py_obj to be valid if VM is valid"), + Err(err) => { + py_obj = None; + return Err(err); + } + }; let acc_vm = AccessibleVM::from(wasm_vm.clone()); let vm = &mut acc_vm .upgrade() @@ -47,7 +53,7 @@ pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue { pyresult_to_jsresult(vm, result) }; let closure = Closure::wrap(Box::new(closure) - as Box, Option) -> Result>); + as Box, Option) -> Result>); let func = closure.as_ref().clone(); // TODO: Come up with a way of managing closure handles From b530733c1a954f692d83bbc8e0f336ffd82be984 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Sat, 23 Feb 2019 13:11:26 +0200 Subject: [PATCH 80/80] Add assertRaises context manager to testutils --- tests/snippets/set.py | 26 +++++--------------------- tests/snippets/testutils.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/snippets/set.py b/tests/snippets/set.py index 84754bca8..a7a20b0ef 100644 --- a/tests/snippets/set.py +++ b/tests/snippets/set.py @@ -1,4 +1,4 @@ -from testutils import assert_raises +from testutils import assert_raises, assertRaises assert set([1,2]) == set([1,2]) assert not set([1,2,3]) == set([1,2]) @@ -109,12 +109,8 @@ assert a == b a = set([1,2,3]) a |= set([3,4,5]) assert a == set([1,2,3,4,5]) -try: +with assertRaises(TypeError): a |= 1 -except TypeError: - pass -else: - assert False, "TypeError not raised" a = set([1,2,3]) a.intersection_update([2,3,4,5]) @@ -124,12 +120,8 @@ assert_raises(TypeError, lambda: a.intersection_update(1)) a = set([1,2,3]) a &= set([2,3,4,5]) assert a == set([2,3]) -try: +with assertRaises(TypeError): a &= 1 -except TypeError: - pass -else: - assert False, "TypeError not raised" a = set([1,2,3]) a.difference_update([3,4,5]) @@ -139,12 +131,8 @@ assert_raises(TypeError, lambda: a.difference_update(1)) a = set([1,2,3]) a -= set([3,4,5]) assert a == set([1,2]) -try: +with assertRaises(TypeError): a -= 1 -except TypeError: - pass -else: - assert False, "TypeError not raised" a = set([1,2,3]) a.symmetric_difference_update([3,4,5]) @@ -154,9 +142,5 @@ assert_raises(TypeError, lambda: a.difference_update(1)) a = set([1,2,3]) a ^= set([3,4,5]) assert a == set([1,2,4,5]) -try: +with assertRaises(TypeError): a ^= 1 -except TypeError: - pass -else: - assert False, "TypeError not raised" diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py index 3c039f4f1..8237ceb62 100644 --- a/tests/snippets/testutils.py +++ b/tests/snippets/testutils.py @@ -18,3 +18,19 @@ def assert_raises(exc_type, expr, msg=None): if msg is not None: failmsg += ': {!s}'.format(msg) assert False, failmsg + + +class assertRaises: + def __init__(self, expected): + self.expected = expected + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if exc_type is None: + failmsg = '{!s} was not raised'.format(self.expected.__name_) + assert False, failmsg + if not issubclass(exc_type, self.expected): + return False + return True