Skip to content

Commit ab6c517

Browse files
Merge pull request RustPython#123 from RustPython/repr
Implement Repr
2 parents f8016dc + a7af78b commit ab6c517

File tree

13 files changed

+79
-22
lines changed

13 files changed

+79
-22
lines changed

tests/snippets/strings.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@
1515
assert str(2.1) == "2.1"
1616
assert str() == ""
1717
assert str("abc") == "abc"
18+
19+
assert repr("a") == "'a'"
20+
assert repr("can't") == '"can\'t"'
21+
assert repr('"won\'t"') == "'\"won\\'t\"'"
22+
assert repr('\n\t') == "'\\n\\t'"
23+
24+
assert str(["a", "b", "can't"]) == "['a', 'b', \"can't\"]"

vm/src/builtins.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
288288
}
289289

290290
// builtin_repr
291+
fn builtin_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
292+
arg_check!(vm, args, required = [(obj, None)]);
293+
vm.to_repr(obj.clone())
294+
}
291295
// builtin_reversed
292296
// builtin_round
293297
// builtin_set
@@ -346,6 +350,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
346350
dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals));
347351
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
348352
dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range));
353+
dict.insert(String::from("repr"), ctx.new_rustfunc(builtin_repr));
349354
dict.insert(String::from("setattr"), ctx.new_rustfunc(builtin_setattr));
350355
dict.insert(String::from("str"), ctx.str_type()); // new_rustfunc(builtin_str));
351356
dict.insert(String::from("tuple"), ctx.tuple_type());

vm/src/obj/objbytes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::objtype;
1111
pub fn init(context: &PyContext) {
1212
let ref bytes_type = context.bytes_type;
1313
bytes_type.set_attr("__init__", context.new_rustfunc(bytes_init));
14-
bytes_type.set_attr("__str__", context.new_rustfunc(bytes_str));
14+
bytes_type.set_attr("__repr__", context.new_rustfunc(bytes_repr));
1515
}
1616

1717
// __init__ (store value into objectkind)
@@ -50,7 +50,7 @@ fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
5050
obj.borrow_mut().kind = PyObjectKind::Bytes { value };
5151
}
5252

53-
fn bytes_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
53+
fn bytes_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5454
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytes_type()))]);
5555
let data = get_value(obj);
5656
let data: Vec<String> = data.into_iter().map(|b| format!("\\x{:02x}", b)).collect();

vm/src/obj/objdict.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ fn dict_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4444
Ok(vm.ctx.new_int(elements.len() as i32))
4545
}
4646

47-
fn dict_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
47+
fn dict_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4848
arg_check!(vm, args, required = [(o, Some(vm.ctx.dict_type()))]);
4949

5050
let elements = get_elements(o);
5151
let mut str_parts = vec![];
5252
for elem in elements {
53-
match vm.to_str(elem.1) {
53+
match vm.to_repr(elem.1) {
5454
Ok(s) => {
5555
let value_str = objstr::get_value(&s);
5656
str_parts.push(format!("{}: {}", elem.0, value_str));
@@ -76,5 +76,5 @@ pub fn init(context: &PyContext) {
7676
let ref dict_type = context.dict_type;
7777
dict_type.set_attr("__len__", context.new_rustfunc(dict_len));
7878
dict_type.set_attr("__new__", context.new_rustfunc(dict_new));
79-
dict_type.set_attr("__str__", context.new_rustfunc(dict_str));
79+
dict_type.set_attr("__repr__", context.new_rustfunc(dict_repr));
8080
}

vm/src/obj/objfloat.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::super::vm::VirtualMachine;
55
use super::objint;
66
use super::objtype;
77

8-
fn str(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
8+
fn float_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
99
arg_check!(vm, args, required = [(float, Some(vm.ctx.float_type()))]);
1010
let v = get_value(float);
1111
Ok(vm.new_str(v.to_string()))
@@ -120,7 +120,6 @@ pub fn init(context: &PyContext) {
120120
float_type.set_attr("__add__", context.new_rustfunc(float_add));
121121
float_type.set_attr("__init__", context.new_rustfunc(float_init));
122122
float_type.set_attr("__pow__", context.new_rustfunc(float_pow));
123-
float_type.set_attr("__str__", context.new_rustfunc(str));
124123
float_type.set_attr("__sub__", context.new_rustfunc(float_sub));
125-
float_type.set_attr("__repr__", context.new_rustfunc(str));
124+
float_type.set_attr("__repr__", context.new_rustfunc(float_repr));
126125
}

vm/src/obj/objint.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::super::vm::VirtualMachine;
66
use super::objfloat;
77
use super::objtype;
88

9-
fn str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9+
fn int_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
1010
arg_check!(vm, args, required = [(int, Some(vm.ctx.int_type()))]);
1111
let v = get_value(int);
1212
Ok(vm.new_str(v.to_string()))
@@ -219,8 +219,7 @@ pub fn init(context: &PyContext) {
219219
int_type.set_attr("__mul__", context.new_rustfunc(int_mul));
220220
int_type.set_attr("__or__", context.new_rustfunc(int_or));
221221
int_type.set_attr("__pow__", context.new_rustfunc(int_pow));
222-
int_type.set_attr("__repr__", context.new_rustfunc(str));
223-
int_type.set_attr("__str__", context.new_rustfunc(str));
222+
int_type.set_attr("__repr__", context.new_rustfunc(int_repr));
224223
int_type.set_attr("__sub__", context.new_rustfunc(int_sub));
225224
int_type.set_attr("__truediv__", context.new_rustfunc(int_truediv));
226225
int_type.set_attr("__xor__", context.new_rustfunc(int_xor));

vm/src/obj/objlist.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6868
}
6969
}
7070

71-
fn list_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
71+
fn list_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7272
arg_check!(vm, args, required = [(o, Some(vm.ctx.list_type()))]);
7373

7474
let elements = get_elements(o);
7575
let mut str_parts = vec![];
7676
for elem in elements {
77-
match vm.to_str(elem) {
77+
match vm.to_repr(elem) {
7878
Ok(s) => str_parts.push(objstr::get_value(&s)),
7979
Err(err) => return Err(err),
8080
}
@@ -136,7 +136,7 @@ pub fn init(context: &PyContext) {
136136
list_type.set_attr("__eq__", context.new_rustfunc(list_eq));
137137
list_type.set_attr("__add__", context.new_rustfunc(list_add));
138138
list_type.set_attr("__len__", context.new_rustfunc(list_len));
139-
list_type.set_attr("__str__", context.new_rustfunc(list_str));
139+
list_type.set_attr("__repr__", context.new_rustfunc(list_repr));
140140
list_type.set_attr("append", context.new_rustfunc(append));
141141
list_type.set_attr("clear", context.new_rustfunc(clear));
142142
list_type.set_attr("reverse", context.new_rustfunc(reverse));

vm/src/obj/objobject.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ fn object_ne(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5050
}
5151

5252
fn object_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
53+
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.object()))]);
54+
vm.call_method(zelf.clone(), "__repr__", vec![])
55+
}
56+
57+
fn object_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5358
arg_check!(vm, args, required = [(obj, Some(vm.ctx.object()))]);
5459
let type_name = objtype::get_type_name(&obj.typ());
5560
let address = obj.get_id();
@@ -64,6 +69,7 @@ pub fn init(context: &PyContext) {
6469
object.set_attr("__ne__", context.new_rustfunc(object_ne));
6570
object.set_attr("__dict__", context.new_member_descriptor(object_dict));
6671
object.set_attr("__str__", context.new_rustfunc(object_str));
72+
object.set_attr("__repr__", context.new_rustfunc(object_repr));
6773
}
6874

6975
fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {

vm/src/obj/objstr.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub fn init(context: &PyContext) {
1414
str_type.set_attr("__mul__", context.new_rustfunc(str_mul));
1515
str_type.set_attr("__new__", context.new_rustfunc(str_new));
1616
str_type.set_attr("__str__", context.new_rustfunc(str_str));
17+
str_type.set_attr("__repr__", context.new_rustfunc(str_repr));
1718
}
1819

1920
pub fn get_value(obj: &PyObjectRef) -> String {
@@ -44,6 +45,41 @@ fn str_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4445
Ok(s.clone())
4546
}
4647

48+
fn count_char(s: &str, c: char) -> usize {
49+
s.chars().filter(|x| *x == c).count()
50+
}
51+
52+
fn str_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
53+
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
54+
let value = get_value(s);
55+
let quote_char = if count_char(&value, '\'') > count_char(&value, '"') {
56+
'"'
57+
} else {
58+
'\''
59+
};
60+
let mut formatted = String::new();
61+
formatted.push(quote_char);
62+
for c in value.chars() {
63+
if c == quote_char || c == '\\' {
64+
formatted.push('\\');
65+
formatted.push(c);
66+
} else if c == '\n' {
67+
formatted.push('\\');
68+
formatted.push('n');
69+
} else if c == '\t' {
70+
formatted.push('\\');
71+
formatted.push('t');
72+
} else if c == '\r' {
73+
formatted.push('\\');
74+
formatted.push('r');
75+
} else {
76+
formatted.push(c);
77+
}
78+
}
79+
formatted.push(quote_char);
80+
Ok(vm.ctx.new_str(formatted))
81+
}
82+
4783
fn str_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4884
arg_check!(
4985
vm,

vm/src/obj/objtuple.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2929
Ok(vm.context().new_int(elements.len() as i32))
3030
}
3131

32-
fn tuple_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
32+
fn tuple_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
3333
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]);
3434

3535
let elements = get_elements(zelf);
3636

3737
let mut str_parts = vec![];
3838
for elem in elements {
39-
match vm.to_str(elem) {
39+
match vm.to_repr(elem) {
4040
Ok(s) => str_parts.push(objstr::get_value(&s)),
4141
Err(err) => return Err(err),
4242
}
@@ -62,5 +62,5 @@ pub fn init(context: &PyContext) {
6262
let ref tuple_type = context.tuple_type;
6363
tuple_type.set_attr("__eq__", context.new_rustfunc(tuple_eq));
6464
tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len));
65-
tuple_type.set_attr("__str__", context.new_rustfunc(tuple_str));
65+
tuple_type.set_attr("__repr__", context.new_rustfunc(tuple_repr));
6666
}

vm/src/obj/objtype.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn init(context: &PyContext) {
2525
type_type.set_attr("__new__", context.new_rustfunc(type_new));
2626
type_type.set_attr("__mro__", context.new_member_descriptor(type_mro));
2727
type_type.set_attr("__class__", context.new_member_descriptor(type_new));
28-
type_type.set_attr("__str__", context.new_rustfunc(type_str));
28+
type_type.set_attr("__repr__", context.new_rustfunc(type_repr));
2929
}
3030

3131
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -221,7 +221,7 @@ pub fn new(typ: PyObjectRef, name: &str, bases: Vec<PyObjectRef>, dict: PyObject
221221
))
222222
}
223223

224-
fn type_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
224+
fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
225225
arg_check!(vm, args, required = [(obj, Some(vm.ctx.type_type()))]);
226226
let type_name = get_type_name(&obj);
227227
Ok(vm.new_str(format!("<class '{}'>", type_name)))

vm/src/objbool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
3333
pub fn init(context: &PyContext) {
3434
let ref bool_type = context.bool_type;
3535
bool_type.set_attr("__new__", context.new_rustfunc(bool_new));
36-
bool_type.set_attr("__str__", context.new_rustfunc(bool_str));
36+
bool_type.set_attr("__repr__", context.new_rustfunc(bool_repr));
3737
}
3838

3939
pub fn not(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyResult {
@@ -54,7 +54,7 @@ pub fn get_value(obj: &PyObjectRef) -> bool {
5454
}
5555
}
5656

57-
fn bool_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
57+
fn bool_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> Result<PyObjectRef, PyObjectRef> {
5858
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bool_type()))]);
5959
let v = get_value(obj);
6060
let s = if v {

vm/src/vm.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ impl VirtualMachine {
142142
self.call_method(obj, "__str__", vec![])
143143
}
144144

145+
pub fn to_repr(&mut self, obj: PyObjectRef) -> PyResult {
146+
self.call_method(obj, "__repr__", vec![])
147+
}
148+
145149
pub fn current_frame(&self) -> &Frame {
146150
self.frames.last().unwrap()
147151
}
@@ -1003,10 +1007,11 @@ impl VirtualMachine {
10031007
match expr.borrow().kind {
10041008
PyObjectKind::None => (),
10051009
_ => {
1010+
let repr = self.to_repr(expr.clone()).unwrap();
10061011
builtins::builtin_print(
10071012
self,
10081013
PyFuncArgs {
1009-
args: vec![expr.clone()],
1014+
args: vec![repr],
10101015
kwargs: vec![],
10111016
},
10121017
).unwrap();

0 commit comments

Comments
 (0)