|
1 | 1 | extern crate unicode_categories;
|
2 | 2 | extern crate unicode_xid;
|
3 | 3 |
|
| 4 | +use std::char; |
4 | 5 | use std::fmt;
|
5 | 6 | use std::ops::Range;
|
6 | 7 | use std::str::FromStr;
|
@@ -442,7 +443,7 @@ impl PyString {
|
442 | 443 | Err(err) => match err.typ {
|
443 | 444 | CFormatErrorType::UnsupportedFormatChar(c) => Err(vm.new_value_error(format!(
|
444 | 445 | "unsupported format character '{}' ({:#x}) at index {}",
|
445 |
| - c, c as u8, err.index |
| 446 | + c, c as u32, err.index |
446 | 447 | ))),
|
447 | 448 | CFormatErrorType::UnmatchedKeyParentheses => {
|
448 | 449 | // 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: &
|
1105 | 1106 |
|
1106 | 1107 | fn do_cformat_specifier(
|
1107 | 1108 | vm: &VirtualMachine,
|
1108 |
| - format_spec: &CFormatSpec, |
| 1109 | + format_spec: &mut CFormatSpec, |
1109 | 1110 | obj: PyObjectRef,
|
1110 | 1111 | ) -> Result<String, PyObjectRef> {
|
1111 | 1112 | use CNumberType::*;
|
@@ -1137,6 +1138,33 @@ fn do_cformat_specifier(
|
1137 | 1138 | }
|
1138 | 1139 | Ok(format_spec.format_number(objint::get_value(&obj)))
|
1139 | 1140 | }
|
| 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 | + } |
1140 | 1168 | _ => Err(vm.new_not_implemented_error(format!(
|
1141 | 1169 | "Not yet implemented for %{}",
|
1142 | 1170 | format_spec.format_char
|
@@ -1246,8 +1274,7 @@ fn do_cformat(
|
1246 | 1274 | obj
|
1247 | 1275 | }
|
1248 | 1276 | };
|
1249 |
| - |
1250 |
| - do_cformat_specifier(vm, &format_spec, obj) |
| 1277 | + do_cformat_specifier(vm, format_spec, obj) |
1251 | 1278 | }
|
1252 | 1279 | CFormatPart::Literal(literal) => Ok(literal.clone()),
|
1253 | 1280 | }?;
|
|
0 commit comments