From 3196b6be73219eae356092c0dcf1683c920d1d06 Mon Sep 17 00:00:00 2001 From: zer0 Date: Thu, 9 May 2019 16:59:40 +0300 Subject: [PATCH 1/9] added str.translate --- vm/src/obj/objstr.rs | 50 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 56fc373c39..fe98d19c0a 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -16,7 +16,8 @@ use crate::pyobject::{ }; use crate::vm::VirtualMachine; -use super::objint; +use super::objnone::PyNone; +use super::objint::{self, PyInt}; use super::objsequence::PySliceableSequence; use super::objslice::PySlice; use super::objtype::{self, PyClassRef}; @@ -829,6 +830,36 @@ impl PyString { false } } + + // https://docs.python.org/3/library/stdtypes.html#str.translate + // Make it work for only subscribtable types + #[pymethod] + fn translate(&self, table: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let mut result = String::new(); + for c in self.value.chars() { + let args = PyFuncArgs::new(vec![vm.new_int(c as i32)], vec![]); + match vm.call_method(&table, "__getitem__", args) { + Ok(value) => { + if let Some(text) = value.payload::() { + result.extend(text.value.chars()); + } else if let Some(_) = value.payload::() { + // Do Nothing + } else if let Some(bigint) = value.payload::() { + match bigint.as_bigint() + .to_u32() + .and_then(std::char::from_u32) { + Some(ch) => result.push(ch as char), + None => return Err(vm.new_value_error(format!("character mapping must be in range(0x110000)"))), + } + } else { + return Err(vm.new_type_error("character mapping must return integer, None or str".to_owned())); + } + }, + _ => result.push(c), + } + } + Ok(result) + } } impl PyValue for PyString { @@ -1104,4 +1135,19 @@ mod tests { assert!(!PyString::from(s).istitle(&vm)); } } -} + + #[test] + fn str_translate() { + let vm = VirtualMachine::new(); + + let table = vm.context().new_dict(); + vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(97), vm.new_str("🎅".to_owned())]).unwrap(); + vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(98), vm.get_none()]).unwrap(); + vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(99), vm.new_str("xda".to_owned())]).unwrap(); + let text = PyString::from("abc"); + let translated = text.translate(table.into_object(), &vm).unwrap(); + assert_eq!(translated, "🎅xda".to_owned()); + let translated = text.translate(vm.new_int(3), &vm); + println!("{:?}", translated); + } +} \ No newline at end of file From 59ae590771c0389d77f535015917db0c3f67f9c3 Mon Sep 17 00:00:00 2001 From: zer0 Date: Thu, 9 May 2019 17:09:38 +0300 Subject: [PATCH 2/9] formatting --- parser/src/lexer.rs | 6 +----- vm/src/obj/objstr.rs | 43 ++++++++++++++++++++++++++++++------------ vm/src/obj/objsuper.rs | 6 ++---- whats_left.sh | 2 +- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index 11d30cbee7..d23198ca89 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -826,11 +826,7 @@ where } _ => { let tok_end = self.get_pos(); - return Some(Ok(( - tok_start, - Tok::DoubleSlash, - tok_end, - ))); + return Some(Ok((tok_start, Tok::DoubleSlash, tok_end))); } } } diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index fe98d19c0a..6bbb9903d2 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -16,8 +16,8 @@ use crate::pyobject::{ }; use crate::vm::VirtualMachine; -use super::objnone::PyNone; use super::objint::{self, PyInt}; +use super::objnone::PyNone; use super::objsequence::PySliceableSequence; use super::objslice::PySlice; use super::objtype::{self, PyClassRef}; @@ -845,16 +845,20 @@ impl PyString { } else if let Some(_) = value.payload::() { // Do Nothing } else if let Some(bigint) = value.payload::() { - match bigint.as_bigint() - .to_u32() - .and_then(std::char::from_u32) { + match bigint.as_bigint().to_u32().and_then(std::char::from_u32) { Some(ch) => result.push(ch as char), - None => return Err(vm.new_value_error(format!("character mapping must be in range(0x110000)"))), + None => { + return Err(vm.new_value_error(format!( + "character mapping must be in range(0x110000)" + ))); + } } } else { - return Err(vm.new_type_error("character mapping must return integer, None or str".to_owned())); + return Err(vm.new_type_error( + "character mapping must return integer, None or str".to_owned(), + )); } - }, + } _ => result.push(c), } } @@ -1139,15 +1143,30 @@ mod tests { #[test] fn str_translate() { let vm = VirtualMachine::new(); - + let table = vm.context().new_dict(); - vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(97), vm.new_str("🎅".to_owned())]).unwrap(); - vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(98), vm.get_none()]).unwrap(); - vm.call_method(table.as_object(), "__setitem__", vec![vm.new_int(99), vm.new_str("xda".to_owned())]).unwrap(); + vm.call_method( + table.as_object(), + "__setitem__", + vec![vm.new_int(97), vm.new_str("🎅".to_owned())], + ) + .unwrap(); + vm.call_method( + table.as_object(), + "__setitem__", + vec![vm.new_int(98), vm.get_none()], + ) + .unwrap(); + vm.call_method( + table.as_object(), + "__setitem__", + vec![vm.new_int(99), vm.new_str("xda".to_owned())], + ) + .unwrap(); let text = PyString::from("abc"); let translated = text.translate(table.into_object(), &vm).unwrap(); assert_eq!(translated, "🎅xda".to_owned()); let translated = text.translate(vm.new_int(3), &vm); println!("{:?}", translated); } -} \ No newline at end of file +} diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index 194212a492..94fe0fc7b7 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -127,10 +127,8 @@ fn super_new( match vm.get_locals().get_item_option(first_arg, vm)? { Some(obj) => obj.clone(), _ => { - return Err(vm.new_type_error(format!( - "super arguement {} was not supplied", - first_arg - ))); + return Err(vm + .new_type_error(format!("super arguement {} was not supplied", first_arg))); } } } else { diff --git a/whats_left.sh b/whats_left.sh index e05051d283..aa79d8d653 100755 --- a/whats_left.sh +++ b/whats_left.sh @@ -8,4 +8,4 @@ python3 not_impl_gen.py cd .. -cargo run -- tests/snippets/whats_left_to_implement.py +cargo +nightly run -- tests/snippets/whats_left_to_implement.py From 2f253ca0545bb71ef480df0c25461de6a118e81d Mon Sep 17 00:00:00 2001 From: zer0 Date: Fri, 10 May 2019 23:31:11 +0300 Subject: [PATCH 3/9] cargo fmt --- vm/src/obj/objstr.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 6bbb9903d2..4f65895989 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -11,8 +11,8 @@ use unicode_segmentation::UnicodeSegmentation; use crate::format::{FormatParseError, FormatPart, FormatString}; use crate::function::{OptionalArg, PyFuncArgs}; use crate::pyobject::{ - IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, - PyValue, TryFromObject, TryIntoRef, TypeProtocol, + IdProtocol, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, + PyResult, PyValue, TryFromObject, TryIntoRef, TypeProtocol, }; use crate::vm::VirtualMachine; @@ -832,13 +832,13 @@ impl PyString { } // https://docs.python.org/3/library/stdtypes.html#str.translate - // Make it work for only subscribtable types #[pymethod] fn translate(&self, table: PyObjectRef, vm: &VirtualMachine) -> PyResult { let mut result = String::new(); + // It throws a type error if it is not subscribtable + vm.get_method(table.clone(), "__getitem__")?; for c in self.value.chars() { - let args = PyFuncArgs::new(vec![vm.new_int(c as i32)], vec![]); - match vm.call_method(&table, "__getitem__", args) { + match table.get_item(c as i32, vm) { Ok(value) => { if let Some(text) = value.payload::() { result.extend(text.value.chars()); @@ -1145,6 +1145,7 @@ mod tests { let vm = VirtualMachine::new(); let table = vm.context().new_dict(); + // TODO: use table.set_item vm.call_method( table.as_object(), "__setitem__", From b15a58416856f080e86c78c3e2603410016646b3 Mon Sep 17 00:00:00 2001 From: zer0 Date: Fri, 10 May 2019 23:47:11 +0300 Subject: [PATCH 4/9] added small test to snippets --- tests/snippets/strings.py | 3 +++ vm/src/obj/objstr.rs | 26 +++++++------------------- vm/src/obj/objsuper.rs | 6 ++++-- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/tests/snippets/strings.py b/tests/snippets/strings.py index 3364a293c5..7e2cd2ef53 100644 --- a/tests/snippets/strings.py +++ b/tests/snippets/strings.py @@ -157,6 +157,9 @@ assert 'z' >= 'b' assert 'a' >= 'a' +# str.translate +assert "abc".translate({97: '🎅', 98: None, 99: "xd"}) == "🎅xd" + def try_mutate_str(): word = "word" word[0] = 'x' diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 4f65895989..683af3484c 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1145,25 +1145,13 @@ mod tests { let vm = VirtualMachine::new(); let table = vm.context().new_dict(); - // TODO: use table.set_item - vm.call_method( - table.as_object(), - "__setitem__", - vec![vm.new_int(97), vm.new_str("🎅".to_owned())], - ) - .unwrap(); - vm.call_method( - table.as_object(), - "__setitem__", - vec![vm.new_int(98), vm.get_none()], - ) - .unwrap(); - vm.call_method( - table.as_object(), - "__setitem__", - vec![vm.new_int(99), vm.new_str("xda".to_owned())], - ) - .unwrap(); + table + .set_item(97, vm.new_str("🎅".to_owned()), &vm) + .unwrap(); + table.set_item(98, vm.get_none(), &vm).unwrap(); + table + .set_item(99, vm.new_str("xda".to_owned()), &vm) + .unwrap(); let text = PyString::from("abc"); let translated = text.translate(table.into_object(), &vm).unwrap(); assert_eq!(translated, "🎅xda".to_owned()); diff --git a/vm/src/obj/objsuper.rs b/vm/src/obj/objsuper.rs index 94fe0fc7b7..194212a492 100644 --- a/vm/src/obj/objsuper.rs +++ b/vm/src/obj/objsuper.rs @@ -127,8 +127,10 @@ fn super_new( match vm.get_locals().get_item_option(first_arg, vm)? { Some(obj) => obj.clone(), _ => { - return Err(vm - .new_type_error(format!("super arguement {} was not supplied", first_arg))); + return Err(vm.new_type_error(format!( + "super arguement {} was not supplied", + first_arg + ))); } } } else { From 6e057955213fd01559bb4fb0301d692745c6c6de Mon Sep 17 00:00:00 2001 From: zer0 Date: Sat, 11 May 2019 01:03:22 +0300 Subject: [PATCH 5/9] added str.maketrans --- parser/src/lexer.rs | 6 +++- tests/snippets/strings.py | 4 +++ vm/src/obj/objstr.rs | 61 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index d23198ca89..11d30cbee7 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -826,7 +826,11 @@ where } _ => { let tok_end = self.get_pos(); - return Some(Ok((tok_start, Tok::DoubleSlash, tok_end))); + return Some(Ok(( + tok_start, + Tok::DoubleSlash, + tok_end, + ))); } } } diff --git a/tests/snippets/strings.py b/tests/snippets/strings.py index 7e2cd2ef53..480500e9f8 100644 --- a/tests/snippets/strings.py +++ b/tests/snippets/strings.py @@ -160,6 +160,10 @@ # str.translate assert "abc".translate({97: '🎅', 98: None, 99: "xd"}) == "🎅xd" +# str.maketrans +assert str.maketrans({"a": "abc", "b": None, "c": 33}) == {97: "abc", 98: None, 99: 33} +assert str.maketrans("hello", "world", "rust") == {103: "w", 101: "o", 108: "l", 111: "d", "r": None, "u": None, "s": None, "t": None} + def try_mutate_str(): word = "word" word[0] = 'x' diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 683af3484c..a4e6da8c50 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -16,6 +16,7 @@ use crate::pyobject::{ }; use crate::vm::VirtualMachine; +use super::objdict::{PyDict, PyDictRef}; use super::objint::{self, PyInt}; use super::objnone::PyNone; use super::objsequence::PySliceableSequence; @@ -838,7 +839,7 @@ impl PyString { // It throws a type error if it is not subscribtable vm.get_method(table.clone(), "__getitem__")?; for c in self.value.chars() { - match table.get_item(c as i32, vm) { + match table.get_item(c as u32, vm) { Ok(value) => { if let Some(text) = value.payload::() { result.extend(text.value.chars()); @@ -864,6 +865,64 @@ impl PyString { } Ok(result) } + + #[pymethod] + fn maketrans( + dict_or_str: PyObjectRef, + to_str: OptionalArg, + none_str: OptionalArg, + vm: &VirtualMachine, + ) -> PyResult { + if let OptionalArg::Present(to_str) = to_str { + // dict_or_str is str + let from_str = dict_or_str.payload::().ok_or( + vm.new_type_error( + "first maketrans argument must be a string if there is a second argument" + .to_owned(), + ), + )?; + let new_dict = vm.context().new_dict(); + if to_str.len(vm) == from_str.len(vm) { + for (c1, c2) in from_str.value.chars().zip(to_str.value.chars()) { + new_dict.set_item(c1.to_string(), vm.new_str(c2.to_string()), vm)?; + } + } else { + return Err(vm.new_value_error( + "the first two maketrans arguments must have equal length".to_owned(), + )); + } + if let OptionalArg::Present(none_str) = none_str { + for c in none_str.value.chars() { + new_dict.set_item(c.to_string(), vm.get_none(), vm)?; + } + } + new_dict.into_pyobject(vm) + } else { + // dict_str must be a dict + if let Ok(dict) = dict_or_str.downcast::() { + let new_dict = vm.context().new_dict(); + for (key, val) in dict { + if let Some(num) = key.payload::() { + new_dict.set_item(num.as_bigint().to_i32(), val, vm)?; + } else if let Some(string) = key.payload::() { + if string.len(vm) == 1 { + let num_value = string.value.chars().next().unwrap() as u32; + new_dict.set_item(num_value, val, vm)?; + } else { + return Err(vm.new_value_error( + "string keys in translate table must be of length 1".to_owned(), + )); + } + } + } + new_dict.into_pyobject(vm) + } else { + Err(vm.new_value_error( + "if you give only one argument to maketrans it must be a dict".to_owned(), + )) + } + } + } } impl PyValue for PyString { From 268cb8d21776e110f1b9ef288592dc465e78ec57 Mon Sep 17 00:00:00 2001 From: zer0 Date: Sat, 11 May 2019 23:58:42 +0300 Subject: [PATCH 6/9] fix str.maketrans 2 and 3 arguments cases --- tests/snippets/strings.py | 2 +- vm/src/obj/objstr.rs | 4 ++-- whats_left.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/snippets/strings.py b/tests/snippets/strings.py index 480500e9f8..531e8f83c1 100644 --- a/tests/snippets/strings.py +++ b/tests/snippets/strings.py @@ -162,7 +162,7 @@ # str.maketrans assert str.maketrans({"a": "abc", "b": None, "c": 33}) == {97: "abc", 98: None, 99: 33} -assert str.maketrans("hello", "world", "rust") == {103: "w", 101: "o", 108: "l", 111: "d", "r": None, "u": None, "s": None, "t": None} +assert str.maketrans("hello", "world", "rust") == {104: 119, 101: 111, 108: 108, 111: 100, 114: None, 117: None, 115: None, 116: None} def try_mutate_str(): word = "word" diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index a4e6da8c50..6062d1d178 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -884,7 +884,7 @@ impl PyString { let new_dict = vm.context().new_dict(); if to_str.len(vm) == from_str.len(vm) { for (c1, c2) in from_str.value.chars().zip(to_str.value.chars()) { - new_dict.set_item(c1.to_string(), vm.new_str(c2.to_string()), vm)?; + new_dict.set_item(c1 as u32, vm.new_int(c2 as u32), vm)?; } } else { return Err(vm.new_value_error( @@ -893,7 +893,7 @@ impl PyString { } if let OptionalArg::Present(none_str) = none_str { for c in none_str.value.chars() { - new_dict.set_item(c.to_string(), vm.get_none(), vm)?; + new_dict.set_item(c as u32, vm.get_none(), vm)?; } } new_dict.into_pyobject(vm) diff --git a/whats_left.sh b/whats_left.sh index aa79d8d653..66e64f1a37 100755 --- a/whats_left.sh +++ b/whats_left.sh @@ -8,4 +8,4 @@ python3 not_impl_gen.py cd .. -cargo +nightly run -- tests/snippets/whats_left_to_implement.py +cargo run -- tests/snippets/whats_left_to_implement.py \ No newline at end of file From b94923314db7990bf11f21bff8de261cde6152ae Mon Sep 17 00:00:00 2001 From: zer0 Date: Sun, 12 May 2019 00:00:21 +0300 Subject: [PATCH 7/9] removed import warning --- vm/src/obj/objstr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 6062d1d178..a87aad20e2 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -16,7 +16,7 @@ use crate::pyobject::{ }; use crate::vm::VirtualMachine; -use super::objdict::{PyDict, PyDictRef}; +use super::objdict::PyDict; use super::objint::{self, PyInt}; use super::objnone::PyNone; use super::objsequence::PySliceableSequence; From 764215151d1aabfeff608c9503209a8c57ae6eda Mon Sep 17 00:00:00 2001 From: zer0 Date: Sun, 12 May 2019 00:40:43 +0300 Subject: [PATCH 8/9] more idiomatic code --- vm/src/obj/objstr.rs | 90 +++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index a87aad20e2..c084ca0ce6 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -835,19 +835,19 @@ impl PyString { // https://docs.python.org/3/library/stdtypes.html#str.translate #[pymethod] fn translate(&self, table: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let mut result = String::new(); + let mut translated = String::new(); // It throws a type error if it is not subscribtable vm.get_method(table.clone(), "__getitem__")?; for c in self.value.chars() { match table.get_item(c as u32, vm) { Ok(value) => { if let Some(text) = value.payload::() { - result.extend(text.value.chars()); + translated.extend(text.value.chars()); } else if let Some(_) = value.payload::() { // Do Nothing } else if let Some(bigint) = value.payload::() { match bigint.as_bigint().to_u32().and_then(std::char::from_u32) { - Some(ch) => result.push(ch as char), + Some(ch) => translated.push(ch as char), None => { return Err(vm.new_value_error(format!( "character mapping must be in range(0x110000)" @@ -860,10 +860,10 @@ impl PyString { )); } } - _ => result.push(c), + _ => translated.push(c), } } - Ok(result) + Ok(translated) } #[pymethod] @@ -873,53 +873,54 @@ impl PyString { none_str: OptionalArg, vm: &VirtualMachine, ) -> PyResult { + let new_dict = vm.context().new_dict(); if let OptionalArg::Present(to_str) = to_str { - // dict_or_str is str - let from_str = dict_or_str.payload::().ok_or( - vm.new_type_error( + match dict_or_str.downcast::() { + Ok(from_str) => { + if to_str.len(vm) == from_str.len(vm) { + for (c1, c2) in from_str.value.chars().zip(to_str.value.chars()) { + new_dict.set_item(c1 as u32, vm.new_int(c2 as u32), vm)?; + } + if let OptionalArg::Present(none_str) = none_str { + for c in none_str.value.chars() { + new_dict.set_item(c as u32, vm.get_none(), vm)?; + } + } + new_dict.into_pyobject(vm) + } else { + Err(vm.new_value_error( + "the first two maketrans arguments must have equal length".to_owned(), + )) + } + } + _ => Err(vm.new_type_error( "first maketrans argument must be a string if there is a second argument" .to_owned(), - ), - )?; - let new_dict = vm.context().new_dict(); - if to_str.len(vm) == from_str.len(vm) { - for (c1, c2) in from_str.value.chars().zip(to_str.value.chars()) { - new_dict.set_item(c1 as u32, vm.new_int(c2 as u32), vm)?; - } - } else { - return Err(vm.new_value_error( - "the first two maketrans arguments must have equal length".to_owned(), - )); + )), } - if let OptionalArg::Present(none_str) = none_str { - for c in none_str.value.chars() { - new_dict.set_item(c as u32, vm.get_none(), vm)?; - } - } - new_dict.into_pyobject(vm) } else { // dict_str must be a dict - if let Ok(dict) = dict_or_str.downcast::() { - let new_dict = vm.context().new_dict(); - for (key, val) in dict { - if let Some(num) = key.payload::() { - new_dict.set_item(num.as_bigint().to_i32(), val, vm)?; - } else if let Some(string) = key.payload::() { - if string.len(vm) == 1 { - let num_value = string.value.chars().next().unwrap() as u32; - new_dict.set_item(num_value, val, vm)?; - } else { - return Err(vm.new_value_error( - "string keys in translate table must be of length 1".to_owned(), - )); + match dict_or_str.downcast::() { + Ok(dict) => { + for (key, val) in dict { + if let Some(num) = key.payload::() { + new_dict.set_item(num.as_bigint().to_i32(), val, vm)?; + } else if let Some(string) = key.payload::() { + if string.len(vm) == 1 { + let num_value = string.value.chars().next().unwrap() as u32; + new_dict.set_item(num_value, val, vm)?; + } else { + return Err(vm.new_value_error( + "string keys in translate table must be of length 1".to_owned(), + )); + } } } + new_dict.into_pyobject(vm) } - new_dict.into_pyobject(vm) - } else { - Err(vm.new_value_error( + _ => Err(vm.new_value_error( "if you give only one argument to maketrans it must be a dict".to_owned(), - )) + )), } } } @@ -1217,4 +1218,9 @@ mod tests { let translated = text.translate(vm.new_int(3), &vm); println!("{:?}", translated); } + + #[test] + fn str_maketrans() { + let vm = VirtualMachine::new(); + } } From 04c017d2682cf6c8975a6b5fbd3f4c22e0e44cd3 Mon Sep 17 00:00:00 2001 From: zer0 Date: Sun, 12 May 2019 12:47:23 +0300 Subject: [PATCH 9/9] unit testing for str.maketrans --- vm/src/obj/objstr.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index c084ca0ce6..d81b69f93e 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1201,26 +1201,28 @@ mod tests { } #[test] - fn str_translate() { + fn str_maketrans_and_translate() { let vm = VirtualMachine::new(); let table = vm.context().new_dict(); table - .set_item(97, vm.new_str("🎅".to_owned()), &vm) + .set_item("a", vm.new_str("🎅".to_owned()), &vm) .unwrap(); - table.set_item(98, vm.get_none(), &vm).unwrap(); + table.set_item("b", vm.get_none(), &vm).unwrap(); table - .set_item(99, vm.new_str("xda".to_owned()), &vm) + .set_item("c", vm.new_str("xda".to_owned()), &vm) .unwrap(); + let translated = PyString::maketrans( + table.into_object(), + OptionalArg::Missing, + OptionalArg::Missing, + &vm, + ) + .unwrap(); let text = PyString::from("abc"); - let translated = text.translate(table.into_object(), &vm).unwrap(); + let translated = text.translate(translated, &vm).unwrap(); assert_eq!(translated, "🎅xda".to_owned()); let translated = text.translate(vm.new_int(3), &vm); - println!("{:?}", translated); - } - - #[test] - fn str_maketrans() { - let vm = VirtualMachine::new(); + assert_eq!(translated.unwrap_err().class().name, "TypeError".to_owned()); } }