Skip to content

Commit 8d612f3

Browse files
committed
Add %c formatting
1 parent 8e880b9 commit 8d612f3

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

vm/src/obj/objstr.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
extern crate unicode_categories;
22
extern crate unicode_xid;
33

4+
use std::char;
45
use std::fmt;
56
use std::ops::Range;
67
use std::str::FromStr;
@@ -442,7 +443,7 @@ impl PyString {
442443
Err(err) => match err.typ {
443444
CFormatErrorType::UnsupportedFormatChar(c) => Err(vm.new_value_error(format!(
444445
"unsupported format character '{}' ({:#x}) at index {}",
445-
c, c as u8, err.index
446+
c, c as u32, err.index
446447
))),
447448
CFormatErrorType::UnmatchedKeyParentheses => {
448449
// TODO in cpython, this error comes after verifying that `values` is a mapping type.
@@ -1105,7 +1106,7 @@ fn call_object_format(vm: &VirtualMachine, argument: PyObjectRef, format_spec: &
11051106

11061107
fn do_cformat_specifier(
11071108
vm: &VirtualMachine,
1108-
format_spec: &CFormatSpec,
1109+
format_spec: &mut CFormatSpec,
11091110
obj: PyObjectRef,
11101111
) -> Result<String, PyObjectRef> {
11111112
use CNumberType::*;
@@ -1137,6 +1138,33 @@ fn do_cformat_specifier(
11371138
}
11381139
Ok(format_spec.format_number(objint::get_value(&obj)))
11391140
}
1141+
CFormatType::Character => {
1142+
let char_string = {
1143+
if objtype::isinstance(&obj, &vm.ctx.int_type()) {
1144+
// BigInt truncation is fine in this case because only the unicode range is relevant
1145+
match objint::get_value(&obj).to_u32().and_then(char::from_u32) {
1146+
Some(value) => Ok(value.to_string()),
1147+
None => {
1148+
Err(vm.new_overflow_error("%c arg not in range(0x110000)".to_string()))
1149+
}
1150+
}
1151+
} else if objtype::isinstance(&obj, &vm.ctx.str_type()) {
1152+
let s: String = get_value(&obj);
1153+
let num_chars = s.chars().count();
1154+
if num_chars != 1 {
1155+
Err(vm.new_type_error("%c requires int or char".to_string()))
1156+
} else {
1157+
println!("Hurray!");
1158+
Ok(s.chars().next().unwrap().to_string())
1159+
}
1160+
} else {
1161+
// TODO re-arrange this block so this error is only created once
1162+
Err(vm.new_type_error("%c requires int or char".to_string()))
1163+
}
1164+
}?;
1165+
format_spec.precision = Some(CFormatQuantity::Amount(1));
1166+
Ok(format_spec.format_string(char_string))
1167+
}
11401168
_ => Err(vm.new_not_implemented_error(format!(
11411169
"Not yet implemented for %{}",
11421170
format_spec.format_char
@@ -1246,8 +1274,7 @@ fn do_cformat(
12461274
obj
12471275
}
12481276
};
1249-
1250-
do_cformat_specifier(vm, &format_spec, obj)
1277+
do_cformat_specifier(vm, format_spec, obj)
12511278
}
12521279
CFormatPart::Literal(literal) => Ok(literal.clone()),
12531280
}?;

0 commit comments

Comments
 (0)