diff --git a/Cargo.lock b/Cargo.lock index b1342cd72..25a156c8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -709,6 +709,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tests/snippets/basic_types.py b/tests/snippets/basic_types.py index 1298c4ed3..006669b3f 100644 --- a/tests/snippets/basic_types.py +++ b/tests/snippets/basic_types.py @@ -44,6 +44,9 @@ assert int() == 0 a = complex(2, 4) assert type(a) is complex assert type(a + a) is complex +assert repr(a) == '(2+4j)' +a = 10j +assert repr(a) == '10j' a = 1 assert a.conjugate() == a diff --git a/tests/snippets/builtin_filter.py b/tests/snippets/builtin_filter.py new file mode 100644 index 000000000..d0b5ccd5c --- /dev/null +++ b/tests/snippets/builtin_filter.py @@ -0,0 +1,32 @@ +assert list(filter(lambda x: ((x % 2) == 0), [0, 1, 2])) == [0, 2] + +# None implies identity +assert list(filter(None, [0, 1, 2])) == [1, 2] + +assert type(filter(None, [])) == filter + + +# test infinite iterator +class Counter(object): + counter = 0 + + def __next__(self): + self.counter += 1 + return self.counter + + def __iter__(self): + return self + + +it = filter(lambda x: ((x % 2) == 0), Counter()) +assert next(it) == 2 +assert next(it) == 4 + + +def predicate(x): + if x == 0: + raise StopIteration() + return True + + +assert list(filter(predicate, [1, 2, 0, 4, 5])) == [1, 2] diff --git a/tests/snippets/builtin_map.py b/tests/snippets/builtin_map.py new file mode 100644 index 000000000..0de8d2c59 --- /dev/null +++ b/tests/snippets/builtin_map.py @@ -0,0 +1,34 @@ +a = list(map(str, [1, 2, 3])) +assert a == ['1', '2', '3'] + + +b = list(map(lambda x, y: x + y, [1, 2, 4], [3, 5])) +assert b == [4, 7] + +assert type(map(lambda x: x, [])) == map + + +# test infinite iterator +class Counter(object): + counter = 0 + + def __next__(self): + self.counter += 1 + return self.counter + + def __iter__(self): + return self + + +it = map(lambda x: x+1, Counter()) +assert next(it) == 2 +assert next(it) == 3 + + +def mapping(x): + if x == 0: + raise StopIteration() + return x + + +assert list(map(mapping, [1, 2, 0, 4, 5])) == [1, 2] diff --git a/tests/snippets/builtin_range.py b/tests/snippets/builtin_range.py index d1df0871b..8d0ab0b65 100644 --- a/tests/snippets/builtin_range.py +++ b/tests/snippets/builtin_range.py @@ -1,5 +1,36 @@ +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 + assert range(2**63+1)[2**63] == 9223372036854775808 +# len tests assert len(range(10, 5)) == 0, 'Range with no elements should have length = 0' assert len(range(10, 5, -2)) == 3, 'Expected length 3, for elements: 10, 8, 6' assert len(range(5, 10, 2)) == 3, 'Expected length 3, for elements: 5, 7, 9' + +# index tests +assert range(10).index(6) == 6 +assert range(4, 10).index(6) == 2 +assert range(4, 10, 2).index(6) == 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) diff --git a/tests/snippets/builtins.py b/tests/snippets/builtins.py index bbf116abc..539b49ef7 100644 --- a/tests/snippets/builtins.py +++ b/tests/snippets/builtins.py @@ -1,8 +1,4 @@ - -a = list(map(str, [1, 2, 3])) -assert a == ['1', '2', '3'] - -x = sum(map(int, a)) +x = sum(map(int, ['1', '2', '3'])) assert x == 6 assert callable(type) @@ -15,8 +11,6 @@ assert type(frozenset) is type assert list(zip(['a', 'b', 'c'], range(3), [9, 8, 7, 99])) == [('a', 0, 9), ('b', 1, 8), ('c', 2, 7)] -assert list(filter(lambda x: ((x % 2) == 0), [0, 1, 2])) == [0, 2] - assert 3 == eval('1+2') code = compile('5+3', 'x.py', 'eval') diff --git a/tests/snippets/math.py b/tests/snippets/math.py index 9b31c1860..09f3ed3b3 100644 --- a/tests/snippets/math.py +++ b/tests/snippets/math.py @@ -18,4 +18,12 @@ assert -a == -4 assert +a == 4 # import math -# print(math.cos(1.2)) +# assert(math.exp(2) == math.exp(2.0)) +# assert(math.exp(True) == math.exp(1.0)) +# +# class Conversible(): +# def __float__(self): +# print("Converting to float now!") +# return 1.1111 +# +# assert math.log(1.1111) == math.log(Conversible()) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 59e10da64..fe278edb7 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -8,6 +8,7 @@ bitflags = "1.0.4" num-complex = "0.2" num-bigint = "0.2.1" num-traits = "0.2" +num-integer = "0.1.39" rand = "0.5" log = "0.3" rustpython_parser = {path = "../parser"} diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index fb1d84c32..15f1db308 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -301,29 +301,6 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { vm.run_code_obj(code_obj, scope) } -fn builtin_filter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(function, None), (iterable, None)]); - - // TODO: process one element at a time from iterators. - let iterable = vm.extract_elements(iterable)?; - - let mut new_items = vec![]; - for element in iterable { - // apply function: - let args = PyFuncArgs { - args: vec![element.clone()], - kwargs: vec![], - }; - let result = vm.invoke(function.clone(), args)?; - let result = objbool::boolval(vm, result)?; - if result { - new_items.push(element); - } - } - - Ok(vm.ctx.new_list(new_items)) -} - fn builtin_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -428,33 +405,6 @@ fn builtin_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.get_locals()) } -fn builtin_map(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(function, None), (iter_target, None)]); - let iterator = objiter::get_iter(vm, iter_target)?; - let mut elements = vec![]; - loop { - match vm.call_method(&iterator, "__next__", vec![]) { - Ok(v) => { - // Now apply function: - let mapped_value = vm.invoke( - function.clone(), - PyFuncArgs { - args: vec![v], - kwargs: vec![], - }, - )?; - elements.push(mapped_value); - } - Err(_) => break, - } - } - - trace!("Mapped elements: {:?}", elements); - - // TODO: when iterators are implemented, we can improve this function. - Ok(vm.ctx.new_list(elements)) -} - fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let candidates = if args.args.len() > 1 { args.args.clone() @@ -465,7 +415,7 @@ fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { return Err(vm.new_type_error("Expected 1 or more arguments".to_string())); }; - if candidates.len() == 0 { + if candidates.is_empty() { let default = args.get_optional_kwarg("default"); if default.is_none() { return Err(vm.new_value_error("max() arg is an empty sequence".to_string())); @@ -516,7 +466,7 @@ fn builtin_min(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { return Err(vm.new_type_error("Expected 1 or more arguments".to_string())); }; - if candidates.len() == 0 { + if candidates.is_empty() { let default = args.get_optional_kwarg("default"); if default.is_none() { return Err(vm.new_value_error("min() arg is an empty sequence".to_string())); @@ -749,7 +699,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { 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.new_rustfunc(builtin_filter)); + 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)); @@ -763,7 +713,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { 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.new_rustfunc(builtin_map)); + 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)); @@ -829,6 +779,11 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { 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, + "StopIteration", + ctx.exceptions.stop_iteration.clone(), + ); ctx.set_attr( &py_mod, "ZeroDivisionError", diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 71439463d..b0c2423cf 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -674,14 +674,14 @@ impl Compiler { Ok(flags) } - fn prepare_decorators(&mut self, decorator_list: &Vec) -> Result<(), String> { + fn prepare_decorators(&mut self, decorator_list: &[ast::Expression]) -> Result<(), String> { for decorator in decorator_list { self.compile_expression(decorator)?; } Ok(()) } - fn apply_decorators(&mut self, decorator_list: &Vec) { + fn apply_decorators(&mut self, decorator_list: &[ast::Expression]) { // Apply decorators: for _ in decorator_list { self.emit(Instruction::CallFunction { @@ -1036,8 +1036,8 @@ impl Compiler { fn compile_call( &mut self, function: &ast::Expression, - args: &Vec, - keywords: &Vec, + args: &[ast::Expression], + keywords: &[ast::Keyword], ) -> Result<(), String> { self.compile_expression(function)?; let count = args.len() + keywords.len(); @@ -1123,7 +1123,7 @@ impl Compiler { // Given a vector of expr / star expr generate code which gives either // a list of expressions on the stack, or a list of tuples. - fn gather_elements(&mut self, elements: &Vec) -> Result { + fn gather_elements(&mut self, elements: &[ast::Expression]) -> Result { // First determine if we have starred elements: let has_stars = elements.iter().any(|e| { if let ast::Expression::Starred { .. } = e { @@ -1153,10 +1153,10 @@ impl Compiler { fn compile_comprehension( &mut self, kind: &ast::ComprehensionKind, - generators: &Vec, + generators: &[ast::Comprehension], ) -> Result<(), String> { // We must have at least one generator: - assert!(generators.len() > 0); + assert!(!generators.is_empty()); let name = match kind { ast::ComprehensionKind::GeneratorExpression { .. } => "", @@ -1201,8 +1201,7 @@ impl Compiler { let mut loop_labels = vec![]; for generator in generators { - let first = loop_labels.len() == 0; - if first { + if loop_labels.is_empty() { // Load iterator onto stack (passed as first argument): self.emit(Instruction::LoadName { name: String::from(".0"), diff --git a/vm/src/format.rs b/vm/src/format.rs index 37f8bfa57..5b4035ef7 100644 --- a/vm/src/format.rs +++ b/vm/src/format.rs @@ -87,7 +87,7 @@ fn parse_align(text: &str) -> (Option, &str) { fn parse_fill_and_align(text: &str) -> (Option, Option, &str) { let char_indices: Vec<(usize, char)> = text.char_indices().take(3).collect(); - if char_indices.len() == 0 { + if char_indices.is_empty() { (None, None, text) } else if char_indices.len() == 1 { let (maybe_align, remaining) = parse_align(text); @@ -438,14 +438,14 @@ impl FormatString { fn parse_literal(text: &str) -> Result<(FormatPart, &str), FormatParseError> { let mut cur_text = text; let mut result_string = String::new(); - while cur_text.len() > 0 { + while !cur_text.is_empty() { match FormatString::parse_literal_single(cur_text) { Ok((next_char, remaining)) => { result_string.push(next_char); cur_text = remaining; } Err(err) => { - if result_string.len() > 0 { + if !result_string.is_empty() { return Ok((FormatPart::Literal(result_string.to_string()), cur_text)); } else { return Err(err); @@ -467,7 +467,7 @@ impl FormatString { String::new() }; - if arg_part.len() == 0 { + if arg_part.is_empty() { return Ok(FormatPart::AutoSpec(format_spec)); } @@ -500,7 +500,7 @@ impl FormatString { pub fn from_str(text: &str) -> Result { let mut cur_text: &str = text; let mut parts: Vec = Vec::new(); - while cur_text.len() > 0 { + while !cur_text.is_empty() { // Try to parse both literals and bracketed format parts util we // run out of text cur_text = FormatString::parse_literal(cur_text) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 2c8ada87b..b8914a66b 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -522,7 +522,7 @@ impl Frame { bytecode::Instruction::Break => { let block = self.unwind_loop(vm); - if let Block::Loop { start: _, end } = block { + if let Block::Loop { end, .. } = block { self.jump(end); } Ok(None) @@ -533,7 +533,7 @@ impl Frame { } bytecode::Instruction::Continue => { let block = self.unwind_loop(vm); - if let Block::Loop { start, end: _ } = block { + if let Block::Loop { start, .. } = block { self.jump(start); } else { assert!(false); @@ -708,8 +708,7 @@ impl Frame { // TODO: execute finally handler } Some(Block::With { - end: _, - context_manager, + context_manager, .. }) => { match self.with_exit(vm, &context_manager, None) { Ok(..) => {} @@ -728,13 +727,12 @@ impl Frame { loop { let block = self.pop_block(); match block { - Some(Block::Loop { start: _, end: __ }) => break block.unwrap(), + Some(Block::Loop { .. }) => break block.unwrap(), Some(Block::TryExcept { .. }) => { // TODO: execute finally handler } Some(Block::With { - end: _, - context_manager, + context_manager, .. }) => match self.with_exit(vm, &context_manager, None) { Ok(..) => {} Err(exc) => { diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 7c1df250e..107ac3896 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -12,6 +12,7 @@ extern crate log; // extern crate env_logger; extern crate num_bigint; extern crate num_complex; +extern crate num_integer; extern crate num_traits; extern crate serde; extern crate serde_json; diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index 03017a30b..a60ce79ff 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -6,6 +6,7 @@ pub mod objbytes; pub mod objcode; pub mod objcomplex; pub mod objdict; +pub mod objfilter; pub mod objfloat; pub mod objframe; pub mod objfunction; @@ -13,6 +14,7 @@ pub mod objgenerator; pub mod objint; pub mod objiter; pub mod objlist; +pub mod objmap; pub mod objmemory; pub mod objobject; pub mod objproperty; diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 594361532..f3a2fafb8 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -30,13 +30,13 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result PyResult { @@ -101,3 +102,17 @@ fn bytes_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let data = String::from_utf8(value.to_vec()).unwrap(); Ok(vm.new_str(format!("b'{}'", data))) } + +fn bytes_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]); + + let iter_obj = PyObject::new( + PyObjectPayload::Iterator { + position: 0, + iterated_obj: obj.clone(), + }, + vm.ctx.iter_type(), + ); + + Ok(iter_obj) +} diff --git a/vm/src/obj/objcode.rs b/vm/src/obj/objcode.rs index 757e1aca3..eb20d1335 100644 --- a/vm/src/obj/objcode.rs +++ b/vm/src/obj/objcode.rs @@ -10,7 +10,7 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref code_type = context.code_type; + let code_type = &context.code_type; context.set_attr(code_type, "__new__", context.new_rustfunc(code_new)); context.set_attr(code_type, "__repr__", context.new_rustfunc(code_repr)); } diff --git a/vm/src/obj/objcomplex.rs b/vm/src/obj/objcomplex.rs index aa6d53e4a..bc624d50f 100644 --- a/vm/src/obj/objcomplex.rs +++ b/vm/src/obj/objcomplex.rs @@ -7,7 +7,7 @@ use super::objtype; use num_complex::Complex64; pub fn init(context: &PyContext) { - let ref complex_type = context.complex_type; + let complex_type = &context.complex_type; context.set_attr(&complex_type, "__add__", context.new_rustfunc(complex_add)); context.set_attr(&complex_type, "__new__", context.new_rustfunc(complex_new)); context.set_attr( @@ -85,5 +85,10 @@ fn complex_conjugate(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn complex_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(obj, Some(vm.ctx.complex_type()))]); let v = get_value(obj); - Ok(vm.new_str(v.to_string())) + let repr = if v.re == 0. { + format!("{}j", v.im) + } else { + format!("({}+{}j)", v.re, v.im) + }; + Ok(vm.new_str(repr)) } diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index 02f98fa44..b547eb906 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -284,7 +284,7 @@ pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: } pub fn init(context: &PyContext) { - let ref dict_type = context.dict_type; + let dict_type = &context.dict_type; context.set_attr(&dict_type, "__len__", context.new_rustfunc(dict_len)); context.set_attr( &dict_type, diff --git a/vm/src/obj/objfilter.rs b/vm/src/obj/objfilter.rs new file mode 100644 index 000000000..009d2ad2e --- /dev/null +++ b/vm/src/obj/objfilter.rs @@ -0,0 +1,83 @@ +use super::super::pyobject::{ + IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, + TypeProtocol, +}; +use super::super::vm::VirtualMachine; +use super::objbool; +use super::objiter; +use super::objtype; // Required for arg_check! to use isinstance + +pub fn filter_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(cls, None), (function, None), (iterable, None)] + ); + let iterator = objiter::get_iter(vm, iterable)?; + Ok(PyObject::new( + PyObjectPayload::FilterIterator { + predicate: function.clone(), + iterator, + }, + cls.clone(), + )) +} + +fn filter_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(filter, Some(vm.ctx.filter_type()))]); + // Return self: + Ok(filter.clone()) +} + +fn filter_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(filter, Some(vm.ctx.filter_type())), (needle, None)] + ); + objiter::contains(vm, filter, needle) +} + +fn filter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(filter, Some(vm.ctx.filter_type()))]); + + if let PyObjectPayload::FilterIterator { + ref mut predicate, + ref mut iterator, + } = filter.borrow_mut().payload + { + loop { + let next_obj = objiter::call_next(vm, iterator)?; + let predicate_value = if predicate.is(&vm.get_none()) { + next_obj.clone() + } else { + // the predicate itself can raise StopIteration which does stop the filter + // iteration + vm.invoke( + predicate.clone(), + PyFuncArgs { + args: vec![next_obj.clone()], + kwargs: vec![], + }, + )? + }; + if objbool::boolval(vm, predicate_value)? { + return Ok(next_obj); + } + } + } else { + panic!("filter doesn't have correct payload"); + } +} + +pub fn init(context: &PyContext) { + let filter_type = &context.filter_type; + context.set_attr( + &filter_type, + "__contains__", + context.new_rustfunc(filter_contains), + ); + context.set_attr(&filter_type, "__iter__", context.new_rustfunc(filter_iter)); + context.set_attr(&filter_type, "__new__", context.new_rustfunc(filter_new)); + context.set_attr(&filter_type, "__next__", context.new_rustfunc(filter_next)); +} diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index aa98b0d5e..4cb996a51 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -267,7 +267,7 @@ fn float_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref float_type = context.float_type; + let float_type = &context.float_type; context.set_attr(&float_type, "__eq__", context.new_rustfunc(float_eq)); context.set_attr(&float_type, "__lt__", context.new_rustfunc(float_lt)); context.set_attr(&float_type, "__le__", context.new_rustfunc(float_le)); diff --git a/vm/src/obj/objframe.rs b/vm/src/obj/objframe.rs index c9aa366b1..83417bb8e 100644 --- a/vm/src/obj/objframe.rs +++ b/vm/src/obj/objframe.rs @@ -10,7 +10,7 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref frame_type = context.frame_type; + let frame_type = &context.frame_type; context.set_attr(&frame_type, "__new__", context.new_rustfunc(frame_new)); context.set_attr(&frame_type, "__repr__", context.new_rustfunc(frame_repr)); context.set_attr(&frame_type, "f_locals", context.new_property(frame_flocals)); diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 925bb7123..b665e581a 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -6,17 +6,17 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref function_type = context.function_type; + let function_type = &context.function_type; context.set_attr(&function_type, "__get__", context.new_rustfunc(bind_method)); - let ref member_descriptor_type = context.member_descriptor_type; + let member_descriptor_type = &context.member_descriptor_type; context.set_attr( &member_descriptor_type, "__get__", context.new_rustfunc(member_get), ); - let ref classmethod_type = context.classmethod_type; + let classmethod_type = &context.classmethod_type; context.set_attr( &classmethod_type, "__get__", @@ -28,7 +28,7 @@ pub fn init(context: &PyContext) { context.new_rustfunc(classmethod_new), ); - let ref staticmethod_type = context.staticmethod_type; + let staticmethod_type = &context.staticmethod_type; context.set_attr( staticmethod_type, "__get__", diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index c98dcadf2..79c4830fa 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -10,7 +10,7 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref generator_type = context.generator_type; + let generator_type = &context.generator_type; context.set_attr( &generator_type, "__iter__", diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index c31709595..ca5788b57 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -205,9 +205,7 @@ fn int_lshift(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // i2 failed `to_usize()` conversion match get_value(i2) { - ref v if *v < BigInt::zero() => { - return Err(vm.new_value_error("negative shift count".to_string())); - } + ref v if *v < BigInt::zero() => Err(vm.new_value_error("negative shift count".to_string())), ref v if *v > BigInt::from(usize::max_value()) => { // TODO: raise OverflowError panic!("Failed converting {} to rust usize", get_value(i2)); @@ -237,9 +235,7 @@ fn int_rshift(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // i2 failed `to_usize()` conversion match get_value(i2) { - ref v if *v < BigInt::zero() => { - return Err(vm.new_value_error("negative shift count".to_string())); - } + ref v if *v < BigInt::zero() => Err(vm.new_value_error("negative shift count".to_string())), ref v if *v > BigInt::from(usize::max_value()) => { // TODO: raise OverflowError panic!("Failed converting {} to rust usize", get_value(i2)); @@ -524,7 +520,6 @@ fn int_conjugate(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref int_type = context.int_type; let int_doc = "int(x=0) -> integer int(x, base=10) -> integer @@ -539,6 +534,8 @@ by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int('0b100', base=0) 4"; + let int_type = &context.int_type; + context.set_attr(&int_type, "__eq__", context.new_rustfunc(int_eq)); context.set_attr(&int_type, "__lt__", context.new_rustfunc(int_lt)); context.set_attr(&int_type, "__le__", context.new_rustfunc(int_le)); diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs index 49497e9e9..b7368f7b2 100644 --- a/vm/src/obj/objiter.rs +++ b/vm/src/obj/objiter.rs @@ -23,6 +23,10 @@ pub fn get_iter(vm: &mut VirtualMachine, iter_target: &PyObjectRef) -> PyResult // return Err(type_error); } +pub fn call_next(vm: &mut VirtualMachine, iter_obj: &PyObjectRef) -> PyResult { + vm.call_method(iter_obj, "__next__", vec![]) +} + /* * Helper function to retrieve the next object (or none) from an iterator. */ @@ -30,7 +34,7 @@ pub fn get_next_object( vm: &mut VirtualMachine, iter_obj: &PyObjectRef, ) -> Result, PyObjectRef> { - let next_obj: PyResult = vm.call_method(iter_obj, "__next__", vec![]); + let next_obj: PyResult = call_next(vm, iter_obj); match next_obj { Ok(value) => Ok(Some(value)), @@ -61,6 +65,21 @@ pub fn get_all( Ok(elements) } +pub fn contains(vm: &mut VirtualMachine, iter: &PyObjectRef, needle: &PyObjectRef) -> PyResult { + loop { + if let Some(element) = get_next_object(vm, iter)? { + let equal = vm.call_method(needle, "__eq__", vec![element.clone()])?; + if objbool::get_value(&equal) { + return Ok(vm.new_bool(true)); + } else { + continue; + } + } else { + return Ok(vm.new_bool(false)); + } + } +} + // Sequence iterator: fn iter_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(iter_target, None)]); @@ -80,21 +99,7 @@ fn iter_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { args, required = [(iter, Some(vm.ctx.iter_type())), (needle, None)] ); - loop { - match vm.call_method(&iter, "__next__", vec![]) { - Ok(element) => match vm.call_method(needle, "__eq__", vec![element.clone()]) { - Ok(value) => { - if objbool::get_value(&value) { - return Ok(vm.new_bool(true)); - } else { - continue; - } - } - Err(_) => return Err(vm.new_type_error("".to_string())), - }, - Err(_) => return Ok(vm.new_bool(false)), - } - } + contains(vm, iter, needle) } fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -131,6 +136,20 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Err(stop_iteration) } } + + PyObjectPayload::Bytes { ref value } => { + if *position < value.len() { + let obj_ref = vm.ctx.new_int(value[*position].to_bigint().unwrap()); + *position += 1; + Ok(obj_ref) + } else { + let stop_iteration_type = vm.ctx.exceptions.stop_iteration.clone(); + let stop_iteration = + vm.new_exception(stop_iteration_type, "End of iterator".to_string()); + Err(stop_iteration) + } + } + _ => { panic!("NOT IMPL"); } @@ -141,7 +160,7 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref iter_type = context.iter_type; + let iter_type = &context.iter_type; context.set_attr( &iter_type, "__contains__", diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 4175b6005..a4f68d1bf 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -365,7 +365,7 @@ fn list_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref list_type = context.list_type; + let list_type = &context.list_type; context.set_attr(&list_type, "__add__", context.new_rustfunc(list_add)); context.set_attr( &list_type, diff --git a/vm/src/obj/objmap.rs b/vm/src/obj/objmap.rs new file mode 100644 index 000000000..ed6130643 --- /dev/null +++ b/vm/src/obj/objmap.rs @@ -0,0 +1,81 @@ +use super::super::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, +}; +use super::super::vm::VirtualMachine; +use super::objiter; +use super::objtype; // Required for arg_check! to use isinstance + +pub fn map_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + no_kwargs!(vm, args); + let cls = &args.args[0]; + if args.args.len() < 3 { + Err(vm.new_type_error("map() must have at least two arguments.".to_owned())) + } else { + let function = &args.args[1]; + let iterables = &args.args[2..]; + let iterators = iterables + .into_iter() + .map(|iterable| objiter::get_iter(vm, iterable)) + .collect::, _>>()?; + Ok(PyObject::new( + PyObjectPayload::MapIterator { + mapper: function.clone(), + iterators, + }, + cls.clone(), + )) + } +} + +fn map_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(map, Some(vm.ctx.map_type()))]); + // Return self: + Ok(map.clone()) +} + +fn map_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(map, Some(vm.ctx.map_type())), (needle, None)] + ); + objiter::contains(vm, map, needle) +} + +fn map_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args, required = [(map, Some(vm.ctx.map_type()))]); + + if let PyObjectPayload::MapIterator { + ref mut mapper, + ref mut iterators, + } = map.borrow_mut().payload + { + let next_objs = iterators + .iter() + .map(|iterator| objiter::call_next(vm, iterator)) + .collect::, _>>()?; + + // the mapper itself can raise StopIteration which does stop the map iteration + vm.invoke( + mapper.clone(), + PyFuncArgs { + args: next_objs, + kwargs: vec![], + }, + ) + } else { + panic!("map doesn't have correct payload"); + } +} + +pub fn init(context: &PyContext) { + let map_type = &context.map_type; + context.set_attr( + &map_type, + "__contains__", + context.new_rustfunc(map_contains), + ); + context.set_attr(&map_type, "__iter__", context.new_rustfunc(map_iter)); + context.set_attr(&map_type, "__new__", context.new_rustfunc(map_new)); + context.set_attr(&map_type, "__next__", context.new_rustfunc(map_next)); +} diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index f9b20e441..6005ba62d 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -17,7 +17,7 @@ pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(ctx: &PyContext) { - let ref memoryview_type = ctx.memoryview_type; + let memoryview_type = &ctx.memoryview_type; ctx.set_attr( &memoryview_type, "__new__", diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 5c425087e..f2668d23e 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -86,7 +86,9 @@ fn object_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref object = context.object; + let object = &context.object; + let object_doc = "The most base type"; + context.set_attr(&object, "__new__", context.new_rustfunc(new_instance)); context.set_attr(&object, "__init__", context.new_rustfunc(object_init)); context.set_attr(&object, "__eq__", context.new_rustfunc(object_eq)); @@ -105,6 +107,7 @@ pub fn init(context: &PyContext) { "__getattribute__", context.new_rustfunc(object_getattribute), ); + context.set_attr(&object, "__doc__", context.new_str(object_doc.to_string())); } fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { @@ -151,21 +154,19 @@ fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(obj_attr) } else if let Some(attr) = cls.get_attr(&name) { vm.call_get_descriptor(attr, obj.clone()) + } else if let Some(getter) = cls.get_attr("__getattr__") { + vm.invoke( + getter, + PyFuncArgs { + args: vec![cls, name_str.clone()], + kwargs: vec![], + }, + ) } else { - if let Some(getter) = cls.get_attr("__getattr__") { - vm.invoke( - getter, - PyFuncArgs { - args: vec![cls, name_str.clone()], - kwargs: vec![], - }, - ) - } else { - let attribute_error = vm.context().exceptions.attribute_error.clone(); - Err(vm.new_exception( - attribute_error, - format!("{} has no attribute '{}'", obj.borrow(), name), - )) - } + let attribute_error = vm.context().exceptions.attribute_error.clone(); + Err(vm.new_exception( + attribute_error, + format!("{} has no attribute '{}'", obj.borrow(), name), + )) } } diff --git a/vm/src/obj/objproperty.rs b/vm/src/obj/objproperty.rs index 71c1b5ab9..1d146889b 100644 --- a/vm/src/obj/objproperty.rs +++ b/vm/src/obj/objproperty.rs @@ -9,7 +9,7 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref property_type = context.property_type; + let property_type = &context.property_type; context.set_attr( &property_type, "__get__", diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs index cd255b29a..c07516410 100644 --- a/vm/src/obj/objrange.rs +++ b/vm/src/obj/objrange.rs @@ -5,6 +5,7 @@ use super::super::vm::VirtualMachine; use super::objint; use super::objtype; use num_bigint::{BigInt, Sign, ToBigInt}; +use num_integer::Integer; use num_traits::{One, Signed, ToPrimitive, Zero}; #[derive(Debug, Clone)] @@ -37,6 +38,20 @@ impl RangeType { self.try_len().unwrap() } + #[inline] + pub fn index_of(&self, value: &BigInt) -> Option { + if value < &self.start || value >= &self.end { + return None; + } + + let offset = value - &self.start; + if offset.is_multiple_of(&self.step) { + Some(offset / &self.step) + } else { + None + } + } + #[inline] pub fn is_empty(&self) -> bool { (self.start <= self.end && self.step.is_negative()) @@ -82,6 +97,7 @@ pub fn init(context: &PyContext) { context.new_rustfunc(range_getitem), ); context.set_attr(&range_type, "__repr__", context.new_rustfunc(range_repr)); + context.set_attr(&range_type, "index", context.new_rustfunc(range_index)); } fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -228,3 +244,23 @@ fn range_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.ctx.new_str(s)) } + +fn range_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(zelf, Some(vm.ctx.range_type())), (needle, None)] + ); + + if let PyObjectPayload::Range { ref range } = zelf.borrow().payload { + match needle.borrow().payload { + PyObjectPayload::Integer { ref value } => match range.index_of(value) { + Some(idx) => Ok(vm.ctx.new_int(idx)), + None => Err(vm.new_value_error(format!("{} is not in range", value))), + }, + _ => Err(vm.new_value_error("sequence.index(x): x not in sequence".to_string())), + } + } else { + unreachable!() + } +} diff --git a/vm/src/obj/objsequence.rs b/vm/src/obj/objsequence.rs index ff3ed6a01..c5504b22d 100644 --- a/vm/src/obj/objsequence.rs +++ b/vm/src/obj/objsequence.rs @@ -90,13 +90,10 @@ pub fn get_item( Err(vm.new_index_error("cannot fit 'int' into an index-sized integer".to_string())) } }, - PyObjectPayload::Slice { - start: _, - stop: _, - step: _, - } => Ok(PyObject::new( + + PyObjectPayload::Slice { .. } => Ok(PyObject::new( match &(sequence.borrow()).payload { - PyObjectPayload::Sequence { elements: _ } => PyObjectPayload::Sequence { + PyObjectPayload::Sequence { .. } => PyObjectPayload::Sequence { elements: elements.to_vec().get_slice_items(&subscript), }, ref payload => panic!("sequence get_item called for non-sequence: {:?}", payload), @@ -112,8 +109,8 @@ pub fn get_item( pub fn seq_equal( vm: &mut VirtualMachine, - zelf: &Vec, - other: &Vec, + zelf: &[PyObjectRef], + other: &[PyObjectRef], ) -> Result { if zelf.len() == other.len() { for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { @@ -131,8 +128,8 @@ pub fn seq_equal( pub fn seq_lt( vm: &mut VirtualMachine, - zelf: &Vec, - other: &Vec, + zelf: &[PyObjectRef], + other: &[PyObjectRef], ) -> Result { if zelf.len() == other.len() { for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { @@ -171,8 +168,8 @@ pub fn seq_lt( pub fn seq_gt( vm: &mut VirtualMachine, - zelf: &Vec, - other: &Vec, + zelf: &[PyObjectRef], + other: &[PyObjectRef], ) -> Result { if zelf.len() == other.len() { for (a, b) in Iterator::zip(zelf.iter(), other.iter()) { @@ -210,21 +207,21 @@ pub fn seq_gt( pub fn seq_ge( vm: &mut VirtualMachine, - zelf: &Vec, - other: &Vec, + zelf: &[PyObjectRef], + other: &[PyObjectRef], ) -> Result { Ok(seq_gt(vm, zelf, other)? || seq_equal(vm, zelf, other)?) } pub fn seq_le( vm: &mut VirtualMachine, - zelf: &Vec, - other: &Vec, + zelf: &[PyObjectRef], + other: &[PyObjectRef], ) -> Result { Ok(seq_lt(vm, zelf, other)? || seq_equal(vm, zelf, other)?) } -pub fn seq_mul(elements: &Vec, product: &PyObjectRef) -> Vec { +pub fn seq_mul(elements: &[PyObjectRef], product: &PyObjectRef) -> Vec { let counter = objint::get_value(&product).to_isize().unwrap(); let current_len = elements.len(); @@ -232,7 +229,7 @@ pub fn seq_mul(elements: &Vec, product: &PyObjectRef) -> Vec HashMap { } } -pub fn sequence_to_hashmap(iterable: &Vec) -> HashMap { +pub fn sequence_to_hashmap(iterable: &[PyObjectRef]) -> HashMap { let mut elements = HashMap::new(); for item in iterable { let key = item.get_id(); @@ -98,7 +98,7 @@ fn set_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.set_type()))]); let elements = get_elements(o); - let s = if elements.len() == 0 { + let s = if elements.is_empty() { "set()".to_string() } else { let mut str_parts = vec![]; @@ -136,7 +136,7 @@ fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]); let elements = get_elements(o); - let s = if elements.len() == 0 { + let s = if elements.is_empty() { "frozenset()".to_string() } else { let mut str_parts = vec![]; @@ -151,7 +151,7 @@ fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref set_type = context.set_type; + let set_type = &context.set_type; context.set_attr( &set_type, "__contains__", @@ -162,7 +162,7 @@ pub fn init(context: &PyContext) { context.set_attr(&set_type, "__repr__", context.new_rustfunc(set_repr)); context.set_attr(&set_type, "add", context.new_rustfunc(set_add)); - let ref frozenset_type = context.frozenset_type; + let frozenset_type = &context.frozenset_type; context.set_attr( &frozenset_type, "__contains__", diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 4eea5a966..f6e0fffd8 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -16,7 +16,7 @@ extern crate unicode_segmentation; use self::unicode_segmentation::UnicodeSegmentation; pub fn init(context: &PyContext) { - let ref str_type = context.str_type; + let str_type = &context.str_type; context.set_attr(&str_type, "__add__", context.new_rustfunc(str_add)); context.set_attr(&str_type, "__eq__", context.new_rustfunc(str_eq)); context.set_attr( @@ -208,7 +208,7 @@ fn str_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn str_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - if args.args.len() == 0 { + if args.args.is_empty() { return Err( vm.new_type_error("descriptor 'format' of 'str' object needs an argument".to_string()) ); @@ -238,9 +238,9 @@ fn str_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn call_object_format( vm: &mut VirtualMachine, argument: PyObjectRef, - format_spec: &String, + format_spec: &str, ) -> PyResult { - let returned_type = vm.ctx.new_str(format_spec.clone()); + let returned_type = vm.ctx.new_str(format_spec.to_string()); let result = vm.call_method(&argument, "__format__", vec![returned_type])?; if !objtype::isinstance(&result, &vm.ctx.str_type()) { let result_type = result.typ(); @@ -450,12 +450,8 @@ fn str_isidentifier(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { && !value.chars().nth(0).unwrap().is_digit(10) { for c in value.chars() { - if c != "_".chars().nth(0).unwrap() { - if !c.is_digit(10) { - if !c.is_alphabetic() { - is_identifier = false; - } - } + if c != "_".chars().nth(0).unwrap() && !c.is_digit(10) && !c.is_alphabetic() { + is_identifier = false; } } } else { @@ -1030,11 +1026,9 @@ pub fn subscript(vm: &mut VirtualMachine, value: &str, b: PyObjectRef) -> PyResu } } else { match &(*b.borrow()).payload { - &PyObjectPayload::Slice { - start: _, - stop: _, - step: _, - } => Ok(vm.new_str(value.to_string().get_slice_items(&b).to_string())), + &PyObjectPayload::Slice { .. } => { + Ok(vm.new_str(value.to_string().get_slice_items(&b).to_string())) + } _ => panic!( "TypeError: indexing type {:?} with index {:?} is not supported (yet?)", value, b @@ -1081,5 +1075,5 @@ fn make_title(s: &str) -> String { capitalize_char = true; } } - return titled_str; + titled_str } diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index 850f64c1a..377bfe604 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -11,7 +11,7 @@ use super::super::vm::VirtualMachine; use super::objtype; pub fn init(context: &PyContext) { - let ref super_type = context.super_type; + let super_type = &context.super_type; context.set_attr(&super_type, "__init__", context.new_rustfunc(super_init)); } diff --git a/vm/src/obj/objtuple.rs b/vm/src/obj/objtuple.rs index dc10020f4..fedbf85e3 100644 --- a/vm/src/obj/objtuple.rs +++ b/vm/src/obj/objtuple.rs @@ -275,7 +275,7 @@ pub fn tuple_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn init(context: &PyContext) { - let ref tuple_type = context.tuple_type; + let tuple_type = &context.tuple_type; context.set_attr(&tuple_type, "__add__", context.new_rustfunc(tuple_add)); context.set_attr(&tuple_type, "__eq__", context.new_rustfunc(tuple_eq)); context.set_attr( diff --git a/vm/src/obj/objtype.rs b/vm/src/obj/objtype.rs index 059b59ff4..9773cd60a 100644 --- a/vm/src/obj/objtype.rs +++ b/vm/src/obj/objtype.rs @@ -22,7 +22,7 @@ pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: } pub fn init(context: &PyContext) { - let ref type_type = context.type_type; + let type_type = &context.type_type; context.set_attr(&type_type, "__call__", context.new_rustfunc(type_call)); context.set_attr(&type_type, "__new__", context.new_rustfunc(type_new)); context.set_attr( @@ -89,12 +89,7 @@ pub fn issubclass(typ: &PyObjectRef, cls: &PyObjectRef) -> bool { } pub fn get_type_name(typ: &PyObjectRef) -> String { - if let PyObjectPayload::Class { - name, - dict: _, - mro: _, - } = &typ.borrow().payload - { + if let PyObjectPayload::Class { name, .. } = &typ.borrow().payload { name.clone() } else { panic!("Cannot get type_name of non-type type {:?}", typ); @@ -192,22 +187,20 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult Ok(cls_attr) } else if let Some(attr) = mcl.get_attr(&name) { vm.call_get_descriptor(attr, cls.clone()) + } else if let Some(getter) = cls.get_attr("__getattr__") { + vm.invoke( + getter, + PyFuncArgs { + args: vec![mcl, name_str.clone()], + kwargs: vec![], + }, + ) } else { - if let Some(getter) = cls.get_attr("__getattr__") { - vm.invoke( - getter, - PyFuncArgs { - args: vec![mcl, name_str.clone()], - kwargs: vec![], - }, - ) - } else { - let attribute_error = vm.context().exceptions.attribute_error.clone(); - Err(vm.new_exception( - attribute_error, - format!("{} has no attribute '{}'", cls.borrow(), name), - )) - } + let attribute_error = vm.context().exceptions.attribute_error.clone(); + Err(vm.new_exception( + attribute_error, + format!("{} has no attribute '{}'", cls.borrow(), name), + )) } } @@ -219,12 +212,7 @@ pub fn get_attributes(obj: &PyObjectRef) -> HashMap { let mut base_classes = objtype::base_classes(obj); base_classes.reverse(); for bc in base_classes { - if let PyObjectPayload::Class { - name: _, - dict, - mro: _, - } = &bc.borrow().payload - { + if let PyObjectPayload::Class { dict, .. } = &bc.borrow().payload { let elements = objdict::get_key_value_pairs(dict); for (name, value) in elements.iter() { let name = objstr::get_value(name); @@ -263,7 +251,7 @@ fn take_next_base( } if let Some(head) = next { - for ref mut item in &mut bases { + for item in &mut bases { if item[0].get_id() == head.get_id() { item.remove(0); } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 69fc083a5..245314093 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -7,6 +7,7 @@ use super::obj::objbytes; use super::obj::objcode; use super::obj::objcomplex; use super::obj::objdict; +use super::obj::objfilter; use super::obj::objfloat; use super::obj::objframe; use super::obj::objfunction; @@ -14,6 +15,7 @@ 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::objobject; use super::obj::objproperty; @@ -106,6 +108,7 @@ pub struct PyContext { pub classmethod_type: PyObjectRef, pub code_type: PyObjectRef, pub dict_type: PyObjectRef, + pub filter_type: PyObjectRef, pub float_type: PyObjectRef, pub frame_type: PyObjectRef, pub frozenset_type: PyObjectRef, @@ -116,6 +119,7 @@ pub struct PyContext { pub true_value: PyObjectRef, pub false_value: PyObjectRef, pub list_type: PyObjectRef, + pub map_type: PyObjectRef, pub memoryview_type: PyObjectRef, pub none: PyObjectRef, pub tuple_type: PyObjectRef, @@ -200,6 +204,8 @@ impl PyContext { let bytearray_type = create_type("bytearray", &type_type, &object_type, &dict_type); let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type); let iter_type = create_type("iter", &type_type, &object_type, &dict_type); + let filter_type = create_type("filter", &type_type, &object_type, &dict_type); + let map_type = create_type("map", &type_type, &object_type, &dict_type); let bool_type = create_type("bool", &type_type, &int_type, &dict_type); let memoryview_type = create_type("memoryview", &type_type, &object_type, &dict_type); let code_type = create_type("code", &type_type, &int_type, &dict_type); @@ -240,6 +246,8 @@ impl PyContext { false_value, tuple_type, iter_type, + filter_type, + map_type, dict_type, none: none, str_type: str_type, @@ -275,6 +283,8 @@ impl PyContext { objsuper::init(&context); objtuple::init(&context); objiter::init(&context); + objfilter::init(&context); + objmap::init(&context); objbool::init(&context); objcode::init(&context); objframe::init(&context); @@ -346,6 +356,14 @@ impl PyContext { self.iter_type.clone() } + pub fn filter_type(&self) -> PyObjectRef { + self.filter_type.clone() + } + + pub fn map_type(&self) -> PyObjectRef { + self.map_type.clone() + } + pub fn str_type(&self) -> PyObjectRef { self.str_type.clone() } @@ -436,17 +454,11 @@ impl PyContext { } pub fn new_tuple(&self, elements: Vec) -> PyObjectRef { - PyObject::new( - PyObjectPayload::Sequence { elements: elements }, - self.tuple_type(), - ) + PyObject::new(PyObjectPayload::Sequence { elements }, self.tuple_type()) } pub fn new_list(&self, elements: Vec) -> PyObjectRef { - PyObject::new( - PyObjectPayload::Sequence { elements: elements }, - self.list_type(), - ) + PyObject::new(PyObjectPayload::Sequence { elements }, self.list_type()) } pub fn new_set(&self, elements: Vec) -> PyObjectRef { @@ -469,12 +481,11 @@ impl PyContext { pub fn new_scope(&self, parent: Option) -> PyObjectRef { let locals = self.new_dict(); - let scope = Scope { - locals: locals, - parent: parent, - }; + + let scope = Scope { locals, parent }; + PyObject { - payload: PyObjectPayload::Scope { scope: scope }, + payload: PyObjectPayload::Scope { scope }, typ: None, } .into_ref() @@ -553,10 +564,7 @@ impl PyContext { pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef { PyObject::new( - PyObjectPayload::BoundMethod { - function: function, - object: object, - }, + PyObjectPayload::BoundMethod { function, object }, self.bound_method_type(), ) } @@ -581,10 +589,7 @@ impl PyContext { let key = self.new_str(key.to_string()); objdict::set_item_in_content(elements, &key, &v); } - PyObjectPayload::Module { - name: _, - ref mut dict, - } => self.set_item(dict, key, v), + PyObjectPayload::Module { ref mut dict, .. } => self.set_item(dict, key, v), PyObjectPayload::Scope { ref mut scope } => { self.set_item(&scope.locals, key, v); } @@ -601,13 +606,9 @@ impl PyContext { pub fn set_attr(&self, obj: &PyObjectRef, attr_name: &str, value: PyObjectRef) { match obj.borrow().payload { - PyObjectPayload::Module { name: _, ref dict } => self.set_item(dict, attr_name, value), + PyObjectPayload::Module { ref dict, .. } => self.set_item(dict, attr_name, value), PyObjectPayload::Instance { ref dict } => self.set_item(dict, attr_name, value), - PyObjectPayload::Class { - name: _, - ref dict, - mro: _, - } => self.set_item(dict, attr_name, value), + PyObjectPayload::Class { ref dict, .. } => self.set_item(dict, attr_name, value), ref payload => unimplemented!("set_attr unimplemented for: {:?}", payload), }; } @@ -717,7 +718,7 @@ impl AttributeProtocol for PyObjectRef { if let Some(item) = class_get_item(self, attr_name) { return Some(item); } - for ref class in mro { + for class in mro { if let Some(item) = class_get_item(class, attr_name) { return Some(item); } @@ -732,7 +733,7 @@ impl AttributeProtocol for PyObjectRef { fn has_attr(&self, attr_name: &str) -> bool { let obj = self.borrow(); match obj.payload { - PyObjectPayload::Module { name: _, ref dict } => dict.contains_key(attr_name), + PyObjectPayload::Module { ref dict, .. } => dict.contains_key(attr_name), PyObjectPayload::Class { ref mro, .. } => { class_has_item(self, attr_name) || mro.into_iter().any(|d| class_has_item(d, attr_name)) @@ -755,7 +756,7 @@ impl DictProtocol for PyObjectRef { PyObjectPayload::Dict { ref elements } => { objdict::content_contains_key_str(elements, k) } - PyObjectPayload::Module { name: _, ref dict } => dict.contains_key(k), + PyObjectPayload::Module { ref dict, .. } => dict.contains_key(k), PyObjectPayload::Scope { ref scope } => scope.locals.contains_key(k), ref payload => unimplemented!("TODO {:?}", payload), } @@ -764,7 +765,7 @@ impl DictProtocol for PyObjectRef { fn get_item(&self, k: &str) -> Option { match self.borrow().payload { PyObjectPayload::Dict { ref elements } => objdict::content_get_key_str(elements, k), - PyObjectPayload::Module { name: _, ref dict } => dict.get_item(k), + PyObjectPayload::Module { ref dict, .. } => dict.get_item(k), PyObjectPayload::Scope { ref scope } => scope.locals.get_item(k), _ => panic!("TODO"), } @@ -772,8 +773,8 @@ impl DictProtocol for PyObjectRef { fn get_key_value_pairs(&self) -> Vec<(PyObjectRef, PyObjectRef)> { match self.borrow().payload { - PyObjectPayload::Dict { elements: _ } => objdict::get_key_value_pairs(self), - PyObjectPayload::Module { name: _, ref dict } => dict.get_key_value_pairs(), + PyObjectPayload::Dict { .. } => objdict::get_key_value_pairs(self), + PyObjectPayload::Module { ref dict, .. } => dict.get_key_value_pairs(), PyObjectPayload::Scope { ref scope } => scope.locals.get_key_value_pairs(), _ => panic!("TODO"), } @@ -815,10 +816,7 @@ impl PyFuncArgs { for name in kwarg_names.iter().rev() { kwargs.push((name.clone(), args.pop().unwrap())); } - PyFuncArgs { - args: args, - kwargs: kwargs, - } + PyFuncArgs { args, kwargs } } pub fn insert(&self, item: PyObjectRef) -> PyFuncArgs { @@ -827,7 +825,7 @@ impl PyFuncArgs { kwargs: self.kwargs.clone(), }; args.args.insert(0, item); - return args; + args } pub fn shift(&mut self) -> PyObjectRef { @@ -886,6 +884,14 @@ pub enum PyObjectPayload { position: usize, iterated_obj: PyObjectRef, }, + FilterIterator { + predicate: PyObjectRef, + iterator: PyObjectRef, + }, + MapIterator { + mapper: PyObjectRef, + iterators: Vec, + }, Slice { start: Option, stop: Option, @@ -948,37 +954,28 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::Complex { ref value } => write!(f, "complex {}", value), PyObjectPayload::Bytes { ref value } => write!(f, "bytes/bytearray {:?}", value), PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj), - PyObjectPayload::Sequence { elements: _ } => write!(f, "list or tuple"), - PyObjectPayload::Dict { elements: _ } => write!(f, "dict"), - PyObjectPayload::Set { elements: _ } => write!(f, "set"), + PyObjectPayload::Sequence { .. } => write!(f, "list or tuple"), + PyObjectPayload::Dict { .. } => write!(f, "dict"), + PyObjectPayload::Set { .. } => write!(f, "set"), PyObjectPayload::WeakRef { .. } => write!(f, "weakref"), - PyObjectPayload::Iterator { - position: _, - iterated_obj: _, - } => write!(f, "iterator"), - PyObjectPayload::Slice { - start: _, - stop: _, - step: _, - } => write!(f, "slice"), - &PyObjectPayload::Range { range: _ } => write!(f, "range"), - &PyObjectPayload::Code { ref code } => write!(f, "code: {:?}", code), - &PyObjectPayload::Function { .. } => write!(f, "function"), - &PyObjectPayload::Generator { .. } => write!(f, "generator"), - &PyObjectPayload::BoundMethod { + PyObjectPayload::Range { .. } => write!(f, "range"), + PyObjectPayload::Iterator { .. } => write!(f, "iterator"), + PyObjectPayload::FilterIterator { .. } => write!(f, "filter"), + PyObjectPayload::MapIterator { .. } => write!(f, "map"), + PyObjectPayload::Slice { .. } => write!(f, "slice"), + PyObjectPayload::Code { ref code } => write!(f, "code: {:?}", code), + PyObjectPayload::Function { .. } => write!(f, "function"), + PyObjectPayload::Generator { .. } => write!(f, "generator"), + PyObjectPayload::BoundMethod { ref function, ref object, } => write!(f, "bound-method: {:?} of {:?}", function, object), - PyObjectPayload::Module { name: _, dict: _ } => write!(f, "module"), - PyObjectPayload::Scope { scope: _ } => write!(f, "scope"), + PyObjectPayload::Module { .. } => write!(f, "module"), + PyObjectPayload::Scope { .. } => write!(f, "scope"), PyObjectPayload::None => write!(f, "None"), - PyObjectPayload::Class { - ref name, - dict: _, - mro: _, - } => write!(f, "class {:?}", name), - PyObjectPayload::Instance { dict: _ } => write!(f, "instance"), - PyObjectPayload::RustFunction { function: _ } => write!(f, "rust function"), + PyObjectPayload::Class { ref name, .. } => write!(f, "class {:?}", name), + PyObjectPayload::Instance { .. } => write!(f, "instance"), + PyObjectPayload::RustFunction { .. } => write!(f, "rust function"), PyObjectPayload::Frame { .. } => write!(f, "frame"), } } @@ -1035,16 +1032,17 @@ impl PyObject { PyObjectPayload::Class { ref name, dict: ref _dict, - mro: _, + .. } => format!("", name), - PyObjectPayload::Instance { dict: _ } => format!(""), - PyObjectPayload::Code { code: _ } => format!(""), - PyObjectPayload::Function { .. } => format!(""), - PyObjectPayload::Generator { .. } => format!(""), - PyObjectPayload::Frame { .. } => format!(""), - PyObjectPayload::BoundMethod { .. } => format!(""), - PyObjectPayload::RustFunction { function: _ } => format!(""), - PyObjectPayload::Module { ref name, dict: _ } => format!("", name), + + PyObjectPayload::Instance { .. } => "".to_string(), + PyObjectPayload::Code { .. } => "".to_string(), + PyObjectPayload::Function { .. } => "".to_string(), + PyObjectPayload::Generator { .. } => "".to_string(), + PyObjectPayload::Frame { .. } => "".to_string(), + PyObjectPayload::BoundMethod { .. } => "".to_string(), + PyObjectPayload::RustFunction { .. } => "".to_string(), + PyObjectPayload::Module { ref name, .. } => format!("", name), PyObjectPayload::Scope { ref scope } => format!("", scope), PyObjectPayload::Slice { ref start, @@ -1060,6 +1058,8 @@ impl PyObject { position, iterated_obj.borrow_mut().str() ), + PyObjectPayload::FilterIterator { .. } => format!(""), + PyObjectPayload::MapIterator { .. } => format!(""), } } diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 107cc0ac9..6b9eb66c9 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -64,9 +64,8 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj ast::Statement::ClassDef { name, body, - bases: _, - keywords: _, decorator_list, + .. } => { let node = create_node(ctx, "ClassDef"); @@ -239,7 +238,7 @@ fn statement_to_ast(ctx: &PyContext, statement: &ast::LocatedStatement) -> PyObj node } -fn expressions_to_ast(ctx: &PyContext, expressions: &Vec) -> PyObjectRef { +fn expressions_to_ast(ctx: &PyContext, expressions: &[ast::Expression]) -> PyObjectRef { let mut py_expression_nodes = vec![]; for expression in expressions { py_expression_nodes.push(expression_to_ast(ctx, expression)); @@ -249,11 +248,7 @@ fn expressions_to_ast(ctx: &PyContext, expressions: &Vec) -> Py fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectRef { let node = match &expression { - ast::Expression::Call { - function, - args, - keywords: _, - } => { + ast::Expression::Call { function, args, .. } => { let node = create_node(ctx, "Call"); let py_func_ast = expression_to_ast(ctx, function); diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 765e899a8..c4391d116 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -26,7 +26,7 @@ use super::super::pyobject::{ use super::super::vm::VirtualMachine; -fn compute_c_flag(mode: &String) -> u16 { +fn compute_c_flag(mode: &str) -> u16 { match mode.as_ref() { "w" => 512, "x" => 512, @@ -295,7 +295,7 @@ pub fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { .filter(|a| raw_modes.contains(&a.to_string())) .collect(); - if modes.len() == 0 || modes.len() > 1 { + if modes.is_empty() || modes.len() > 1 { return Err(vm.new_value_error("Invalid Mode".to_string())); } diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index 50e7dbde9..eedae4f78 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -14,8 +14,8 @@ use std; macro_rules! make_math_func { ( $fname:ident, $fun:ident ) => { fn $fname(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let value = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let value = objfloat::make_float(vm, value)?; let value = value.$fun(); let value = vm.ctx.new_float(value); Ok(value) @@ -27,20 +27,20 @@ macro_rules! make_math_func { make_math_func!(math_fabs, abs); fn math_isfinite(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let value = objfloat::get_value(value).is_finite(); + arg_check!(vm, args, required = [(value, None)]); + let value = objfloat::make_float(vm, value)?.is_finite(); Ok(vm.ctx.new_bool(value)) } fn math_isinf(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let value = objfloat::get_value(value).is_infinite(); + arg_check!(vm, args, required = [(value, None)]); + let value = objfloat::make_float(vm, value)?.is_infinite(); Ok(vm.ctx.new_bool(value)) } fn math_isnan(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let value = objfloat::get_value(value).is_nan(); + arg_check!(vm, args, required = [(value, None)]); + let value = objfloat::make_float(vm, value)?.is_nan(); Ok(vm.ctx.new_bool(value)) } @@ -49,25 +49,20 @@ make_math_func!(math_exp, exp); make_math_func!(math_expm1, exp_m1); fn math_log(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [(x, Some(vm.ctx.float_type()))], - optional = [(base, Some(vm.ctx.float_type()))] - ); - let x = objfloat::get_value(x); + arg_check!(vm, args, required = [(x, None)], optional = [(base, None)]); + let x = objfloat::make_float(vm, x)?; match base { None => Ok(vm.ctx.new_float(x.ln())), Some(base) => { - let base = objfloat::get_value(base); + let base = objfloat::make_float(vm, base)?; Ok(vm.ctx.new_float(x.log(base))) } } } fn math_log1p(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(x, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(x); + arg_check!(vm, args, required = [(x, None)]); + let x = objfloat::make_float(vm, x)?; Ok(vm.ctx.new_float((x + 1.0).ln())) } @@ -75,16 +70,9 @@ make_math_func!(math_log2, log2); make_math_func!(math_log10, log10); fn math_pow(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [ - (x, Some(vm.ctx.float_type())), - (y, Some(vm.ctx.float_type())) - ] - ); - let x = objfloat::get_value(x); - let y = objfloat::get_value(y); + arg_check!(vm, args, required = [(x, None), (y, None)]); + let x = objfloat::make_float(vm, x)?; + let y = objfloat::make_float(vm, y)?; Ok(vm.ctx.new_float(x.powf(y))) } @@ -96,32 +84,18 @@ make_math_func!(math_asin, asin); make_math_func!(math_atan, atan); fn math_atan2(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [ - (y, Some(vm.ctx.float_type())), - (x, Some(vm.ctx.float_type())) - ] - ); - let y = objfloat::get_value(y); - let x = objfloat::get_value(x); + arg_check!(vm, args, required = [(y, None), (x, None)]); + let y = objfloat::make_float(vm, y)?; + let x = objfloat::make_float(vm, x)?; Ok(vm.ctx.new_float(y.atan2(x))) } make_math_func!(math_cos, cos); fn math_hypot(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!( - vm, - args, - required = [ - (x, Some(vm.ctx.float_type())), - (y, Some(vm.ctx.float_type())) - ] - ); - let x = objfloat::get_value(x); - let y = objfloat::get_value(y); + arg_check!(vm, args, required = [(x, None), (y, None)]); + let x = objfloat::make_float(vm, x)?; + let y = objfloat::make_float(vm, y)?; Ok(vm.ctx.new_float(x.hypot(y))) } @@ -129,14 +103,14 @@ make_math_func!(math_sin, sin); make_math_func!(math_tan, tan); fn math_degrees(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; Ok(vm.ctx.new_float(x * (180.0 / std::f64::consts::PI))) } fn math_radians(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; Ok(vm.ctx.new_float(x * (std::f64::consts::PI / 180.0))) } @@ -150,8 +124,8 @@ make_math_func!(math_tanh, tanh); // Special functions: fn math_erf(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; if x.is_nan() { Ok(vm.ctx.new_float(x)) @@ -161,8 +135,8 @@ fn math_erf(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn math_erfc(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; if x.is_nan() { Ok(vm.ctx.new_float(x)) @@ -172,32 +146,28 @@ fn math_erfc(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn math_gamma(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; if x.is_finite() { Ok(vm.ctx.new_float(gamma(x))) + } else if x.is_nan() || x.is_sign_positive() { + Ok(vm.ctx.new_float(x)) } else { - if x.is_nan() || x.is_sign_positive() { - Ok(vm.ctx.new_float(x)) - } else { - Ok(vm.ctx.new_float(std::f64::NAN)) - } + Ok(vm.ctx.new_float(std::f64::NAN)) } } fn math_lgamma(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(value, Some(vm.ctx.float_type()))]); - let x = objfloat::get_value(value); + arg_check!(vm, args, required = [(value, None)]); + let x = objfloat::make_float(vm, value)?; if x.is_finite() { Ok(vm.ctx.new_float(ln_gamma(x))) + } else if x.is_nan() { + Ok(vm.ctx.new_float(x)) } else { - if x.is_nan() { - Ok(vm.ctx.new_float(x)) - } else { - Ok(vm.ctx.new_float(std::f64::INFINITY)) - } + Ok(vm.ctx.new_float(std::f64::INFINITY)) } } diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs index fda1854f4..3c60e7976 100644 --- a/vm/src/stdlib/pystruct.rs +++ b/vm/src/stdlib/pystruct.rs @@ -169,7 +169,7 @@ fn pack_f64( } fn struct_pack(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - if args.args.len() < 1 { + if args.args.is_empty() { Err(vm.new_type_error(format!( "Expected at least 1 argument (got: {})", args.args.len() diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 3d56818c6..020c1d82b 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -174,7 +174,7 @@ impl VirtualMachine { pub fn get_builtin_scope(&mut self) -> PyObjectRef { let a2 = &*self.builtins.borrow(); match a2.payload { - PyObjectPayload::Module { name: _, ref dict } => dict.clone(), + PyObjectPayload::Module { ref dict, .. } => dict.clone(), _ => { panic!("OMG"); } @@ -260,11 +260,7 @@ impl VirtualMachine { ref scope, ref defaults, } => self.invoke_python_function(code, scope, defaults, args), - PyObjectPayload::Class { - name: _, - dict: _, - mro: _, - } => self.call_method_pyargs(&func_ref, "__call__", args), + PyObjectPayload::Class { .. } => self.call_method_pyargs(&func_ref, "__call__", args), PyObjectPayload::BoundMethod { ref function, ref object, diff --git a/wasm/demo/src/index.html b/wasm/demo/src/index.html index d87853bde..639bf1f7d 100644 --- a/wasm/demo/src/index.html +++ b/wasm/demo/src/index.html @@ -7,7 +7,7 @@

RustPython Demo

- RustPython is a Python interpreter writter in Rust. This demo is + RustPython is a Python interpreter written in Rust. This demo is compiled from Rust to WebAssembly so it runs in the browser.
Please input your Python code below and click Run, or you can open up your browser's devtools and play with @@ -44,7 +44,7 @@ while count < until:

  • stdout: either a string with a css selector - to a textarea element or a function that recieves a + to a textarea element or a function that receives a string when the print function is called in python. The default value is console.log.
  • @@ -57,7 +57,7 @@ while count < until:
  • - JS functions that get passed to python will recieve positional + JS functions that get passed to python will receive positional args as positional args and kwargs as the this argument
  • diff --git a/wasm/lib/README.md b/wasm/lib/README.md index b278e8cb9..6d2f89d93 100644 --- a/wasm/lib/README.md +++ b/wasm/lib/README.md @@ -28,7 +28,7 @@ pyEval(code, options?); - `vars?`: `{ [key: string]: any }`: Variables passed to the VM that can be accessed in Python with the variable `js_vars`. Functions do work, and - recieve the Python kwargs as the `this` argument. + receive the Python kwargs as the `this` argument. - `stdout?`: `(out: string) => void`: A function to replace the native print function, by default `console.log`. diff --git a/wasm/lib/src/lib.rs b/wasm/lib/src/lib.rs index 01e524c9d..f7da7edd1 100644 --- a/wasm/lib/src/lib.rs +++ b/wasm/lib/src/lib.rs @@ -11,7 +11,7 @@ use rustpython_vm::pyobject::{self, PyFuncArgs, PyObjectRef, PyResult}; use rustpython_vm::VirtualMachine; use wasm_bindgen::{prelude::*, JsCast}; -// Hack to comment out wasm-bindgen's typescript definitons +// Hack to comment out wasm-bindgen's typescript definitions #[wasm_bindgen(typescript_custom_section)] const TS_CMT_START: &'static str = "/*"; @@ -141,7 +141,7 @@ fn eval(vm: &mut VirtualMachine, source: &str, vars: PyObjectRef) -> PyResult { /// /// - `vars?`: `{ [key: string]: any }`: Variables passed to the VM that can be /// accessed in Python with the variable `js_vars`. Functions do work, and -/// recieve the Python kwargs as the `this` argument. +/// receive the Python kwargs as the `this` argument. /// - `stdout?`: `(out: string) => void`: A function to replace the native print /// function, by default `console.log`. pub fn eval_py(source: &str, options: Option) -> Result {