From 1114d27e281392dbccb7c7382137840558ca74a1 Mon Sep 17 00:00:00 2001 From: MinGyo Jung Date: Thu, 15 Aug 2019 17:39:03 +0900 Subject: [PATCH] #1224 Add formating for floating point and test Just supports "%f" types --- vm/src/cformat.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++ vm/src/obj/objstr.rs | 13 ++++++++ 2 files changed, 83 insertions(+) diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index 2b17b992a..0d86609bf 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -209,6 +209,41 @@ impl CFormatSpec { self.fill_string(format!("{}{}", prefix, magnitude_string), ' ', None) } } + + pub fn format_float(&self, num: f64) -> String { + let magnitude = num.abs(); + + let sign_string = match num.is_sign_positive() { + false => "-", + true => { + if self.flags.contains(CConversionFlags::SIGN_CHAR) { + "+" + } else if self.flags.contains(CConversionFlags::BLANK_SIGN) { + " " + } else { + "" + } + } + }; + + // TODO: Support precision + let magnitude_string = format!("{:.6}", magnitude); + + if self.flags.contains(CConversionFlags::ZERO_PAD) { + let fill_char = if !self.flags.contains(CConversionFlags::LEFT_ADJUST) { + '0' + } else { + ' ' + }; + format!( + "{}{}", + sign_string, + self.fill_string(magnitude_string, fill_char, Some(sign_string.chars().count())) + ) + } else { + self.fill_string(format!("{}{}", sign_string, magnitude_string), ' ', None) + } + } } #[derive(Debug, PartialEq)] @@ -761,6 +796,41 @@ mod tests { .format_number(&BigInt::from(0x1337)), "0x1337 ".to_string() ); + assert_eq!( + "%f" + .parse::() + .unwrap() + .format_float(f64::from(1.2345)), + "1.234500".to_string() + ); + assert_eq!( + "%+f" + .parse::() + .unwrap() + .format_float(f64::from(1.2345)), + "+1.234500".to_string() + ); + assert_eq!( + "% f" + .parse::() + .unwrap() + .format_float(f64::from(1.2345)), + " 1.234500".to_string() + ); + assert_eq!( + "%f" + .parse::() + .unwrap() + .format_float(f64::from(-1.2345)), + "-1.234500".to_string() + ); + assert_eq!( + "%f" + .parse::() + .unwrap() + .format_float(f64::from(1.2345678901)), + "1.234568".to_string() + ); } #[test] diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index ff609eaad..95b4d0f05 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -29,6 +29,7 @@ use crate::vm::VirtualMachine; use super::objbytes::PyBytes; use super::objdict::PyDict; use super::objint::{self, PyInt}; +use super::objfloat; use super::objiter; use super::objnone::PyNone; use super::objsequence::PySliceableSequence; @@ -1220,6 +1221,18 @@ fn do_cformat_specifier( } Ok(format_spec.format_number(objint::get_value(&obj))) } + CFormatType::Float(_) => { + if !objtype::isinstance(&obj, &vm.ctx.float_type()) { + let required_type_string = "an floating point"; + return Err(vm.new_type_error(format!( + "%{} format: {} is required, not {}", + format_spec.format_char, + required_type_string, + obj.class() + ))); + } + Ok(format_spec.format_float(objfloat::get_value(&obj))) + } CFormatType::Character => { let char_string = { if objtype::isinstance(&obj, &vm.ctx.int_type()) {