diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-09-11 19:37:29 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-09-11 19:41:07 -0700 |
| commit | 2c6c963f61d84d2a959df0d5c82f519c157ef552 (patch) | |
| tree | 39e1e9cd24b8db28302db9a0018192b097b77b75 /src/libcore/extfmt.rs | |
| parent | ec225166cd73398052dcf4a2135cd1110856f4d1 (diff) | |
Convert core::extfmt to camel case
Diffstat (limited to 'src/libcore/extfmt.rs')
| -rw-r--r-- | src/libcore/extfmt.rs | 339 |
1 files changed, 266 insertions, 73 deletions
diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs index cd22b2c5c04..e7b1ec517ec 100644 --- a/src/libcore/extfmt.rs +++ b/src/libcore/extfmt.rs @@ -1,5 +1,4 @@ #[doc(hidden)]; -#[allow(non_camel_case_types)]; /* Syntax Extension: fmt @@ -43,53 +42,53 @@ use option::{Some, None}; // Functions used by the fmt extension at compile time mod ct { - enum signedness { signed, unsigned, } - enum caseness { case_upper, case_lower, } - enum ty { - ty_bool, - ty_str, - ty_char, - ty_int(signedness), - ty_bits, - ty_hex(caseness), - ty_octal, - ty_float, - ty_poly, - } - enum flag { - flag_left_justify, - flag_left_zero_pad, - flag_space_for_sign, - flag_sign_always, - flag_alternate, - } - enum count { - count_is(int), - count_is_param(int), - count_is_next_param, - count_implied, + enum Signedness { Signed, Unsigned, } + enum Caseness { CaseUpper, CaseLower, } + enum Ty { + TyBool, + TyStr, + TyChar, + TyInt(Signedness), + TyBits, + TyHex(Caseness), + TyOctal, + TyFloat, + TyPoly, + } + enum Flag { + FlagLeftJustify, + FlagLeftZeroPad, + FlagSpaceForSign, + FlagSignAlways, + FlagAlternate, + } + enum Count { + CountIs(int), + CountIsParam(int), + CountIsNextParam, + CountImplied, } // A formatted conversion from an expression to a string - type conv = + type Conv = {param: Option<int>, - flags: ~[flag], - width: count, - precision: count, - ty: ty}; + flags: ~[Flag], + width: Count, + precision: Count, + ty: Ty}; // A fragment of the output sequence - enum piece { piece_string(~str), piece_conv(conv), } - type error_fn = fn@(~str) -> ! ; + enum Piece { PieceString(~str), PieceConv(Conv), } + type ErrorFn = fn@(~str) -> ! ; - fn parse_fmt_string(s: ~str, error: error_fn) -> ~[piece] { - let mut pieces: ~[piece] = ~[]; + fn parse_fmt_string(s: ~str, error: ErrorFn) -> ~[Piece] { + let mut pieces: ~[Piece] = ~[]; let lim = str::len(s); let mut buf = ~""; - fn flush_buf(+buf: ~str, &pieces: ~[piece]) -> ~str { + fn flush_buf(+buf: ~str, &pieces: ~[Piece]) -> ~str { if str::len(buf) > 0 { - let piece = piece_string(move buf); + let piece = PieceString(move buf); vec::push(pieces, move piece); } return ~""; @@ -140,15 +139,15 @@ mod ct { None } } - fn parse_conversion(s: ~str, i: uint, lim: uint, error: error_fn) -> - {piece: piece, next: uint} { + fn parse_conversion(s: ~str, i: uint, lim: uint, error: ErrorFn) -> + {piece: Piece, next: uint} { let parm = parse_parameter(s, i, lim); let flags = parse_flags(s, parm.next, lim); let width = parse_count(s, flags.next, lim); let prec = parse_precision(s, width.next, lim); let ty = parse_type(s, prec.next, lim, error); return {piece: - piece_conv({param: parm.param, + PieceConv({param: parm.param, flags: copy flags.flags, width: width.count, precision: prec.count, @@ -171,58 +170,58 @@ mod ct { }; } fn parse_flags(s: ~str, i: uint, lim: uint) -> - {flags: ~[flag], next: uint} { - let noflags: ~[flag] = ~[]; + {flags: ~[Flag], next: uint} { + let noflags: ~[Flag] = ~[]; if i >= lim { return {flags: move noflags, next: i}; } - fn more_(f: flag, s: ~str, i: uint, lim: uint) -> - {flags: ~[flag], next: uint} { + fn more_(f: Flag, s: ~str, i: uint, lim: uint) -> + {flags: ~[Flag], next: uint} { let next = parse_flags(s, i + 1u, lim); let rest = copy next.flags; let j = next.next; - let curr: ~[flag] = ~[f]; + let curr: ~[Flag] = ~[f]; return {flags: vec::append(move curr, rest), next: j}; } let more = |x, copy s| more_(x, copy s, i, lim); let f = s[i]; return if f == '-' as u8 { - more(flag_left_justify) + more(FlagLeftJustify) } else if f == '0' as u8 { - more(flag_left_zero_pad) + more(FlagLeftZeroPad) } else if f == ' ' as u8 { - more(flag_space_for_sign) + more(FlagSpaceForSign) } else if f == '+' as u8 { - more(flag_sign_always) + more(FlagSignAlways) } else if f == '#' as u8 { - more(flag_alternate) + more(FlagAlternate) } else { {flags: move noflags, next: i} }; } fn parse_count(s: ~str, i: uint, lim: uint) - -> {count: count, next: uint} { + -> {count: Count, next: uint} { return if i >= lim { - {count: count_implied, next: i} + {count: CountImplied, next: i} } else if s[i] == '*' as u8 { let param = parse_parameter(s, i + 1u, lim); let j = param.next; match param.param { - None => {count: count_is_next_param, next: j}, - Some(n) => {count: count_is_param(n), next: j} + None => {count: CountIsNextParam, next: j}, + Some(n) => {count: CountIsParam(n), next: j} } } else { let num = peek_num(s, i, lim); match num { - None => {count: count_implied, next: i}, + None => {count: CountImplied, next: i}, Some(num) => { - count: count_is(num.num as int), + count: CountIs(num.num as int), next: num.next } } }; } fn parse_precision(s: ~str, i: uint, lim: uint) -> - {count: count, next: uint} { + {count: Count, next: uint} { return if i >= lim { - {count: count_implied, next: i} + {count: CountImplied, next: i} } else if s[i] == '.' as u8 { let count = parse_count(s, i + 1u, lim); @@ -230,40 +229,40 @@ mod ct { // If there were no digits specified, i.e. the precision // was ".", then the precision is 0 match count.count { - count_implied => {count: count_is(0), next: count.next}, + CountImplied => {count: CountIs(0), next: count.next}, _ => count } - } else { {count: count_implied, next: i} }; + } else { {count: CountImplied, next: i} }; } - fn parse_type(s: ~str, i: uint, lim: uint, error: error_fn) -> - {ty: ty, next: uint} { + fn parse_type(s: ~str, i: uint, lim: uint, error: ErrorFn) -> + {ty: Ty, next: uint} { if i >= lim { error(~"missing type in conversion"); } let tstr = str::slice(s, i, i+1u); // FIXME (#2249): Do we really want two signed types here? // How important is it to be printf compatible? let t = if tstr == ~"b" { - ty_bool + TyBool } else if tstr == ~"s" { - ty_str + TyStr } else if tstr == ~"c" { - ty_char + TyChar } else if tstr == ~"d" || tstr == ~"i" { - ty_int(signed) + TyInt(Signed) } else if tstr == ~"u" { - ty_int(unsigned) + TyInt(Unsigned) } else if tstr == ~"x" { - ty_hex(case_lower) + TyHex(CaseLower) } else if tstr == ~"X" { - ty_hex(case_upper) + TyHex(CaseUpper) } else if tstr == ~"t" { - ty_bits + TyBits } else if tstr == ~"o" { - ty_octal + TyOctal } else if tstr == ~"f" { - ty_float + TyFloat } else if tstr == ~"?" { - ty_poly + TyPoly } else { error(~"unknown type in conversion: " + tstr) }; return {ty: t, next: i + 1u}; } @@ -274,6 +273,199 @@ mod ct { // decisions made a runtime. If it proves worthwhile then some of these // conditions can be evaluated at compile-time. For now though it's cleaner to // implement it 0this way, I think. +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +mod rt { + const flag_none : u32 = 0u32; + const flag_left_justify : u32 = 0b00000000000000000000000000000001u32; + const flag_left_zero_pad : u32 = 0b00000000000000000000000000000010u32; + const flag_space_for_sign : u32 = 0b00000000000000000000000000000100u32; + const flag_sign_always : u32 = 0b00000000000000000000000000001000u32; + const flag_alternate : u32 = 0b00000000000000000000000000010000u32; + + enum Count { CountIs(int), CountImplied, } + enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, } + + type Conv = {flags: u32, width: Count, precision: Count, ty: Ty}; + + pure fn conv_int(cv: Conv, i: int) -> ~str { + let radix = 10u; + let prec = get_int_precision(cv); + let mut s : ~str = int_to_str_prec(i, radix, prec); + if 0 <= i { + if have_flag(cv.flags, flag_sign_always) { + unchecked { str::unshift_char(s, '+') }; + } else if have_flag(cv.flags, flag_space_for_sign) { + unchecked { str::unshift_char(s, ' ') }; + } + } + return unchecked { pad(cv, s, PadSigned) }; + } + pure fn conv_uint(cv: Conv, u: uint) -> ~str { + let prec = get_int_precision(cv); + let mut rs = + match cv.ty { + TyDefault => uint_to_str_prec(u, 10u, prec), + TyHexLower => uint_to_str_prec(u, 16u, prec), + TyHexUpper => str::to_upper(uint_to_str_prec(u, 16u, prec)), + TyBits => uint_to_str_prec(u, 2u, prec), + TyOctal => uint_to_str_prec(u, 8u, prec) + }; + return unchecked { pad(cv, rs, PadUnsigned) }; + } + pure fn conv_bool(cv: Conv, b: bool) -> ~str { + let s = if b { ~"true" } else { ~"false" }; + // run the boolean conversion through the string conversion logic, + // giving it the same rules for precision, etc. + return conv_str(cv, s); + } + pure fn conv_char(cv: Conv, c: char) -> ~str { + let mut s = str::from_char(c); + return unchecked { pad(cv, s, PadNozero) }; + } + pure fn conv_str(cv: Conv, s: &str) -> ~str { + // For strings, precision is the maximum characters + // displayed + let mut unpadded = match cv.precision { + CountImplied => s.to_unique(), + CountIs(max) => if max as uint < str::char_len(s) { + str::substr(s, 0u, max as uint) + } else { + s.to_unique() + } + }; + return unchecked { pad(cv, unpadded, PadNozero) }; + } + pure fn conv_float(cv: Conv, f: float) -> ~str { + let (to_str, digits) = match cv.precision { + CountIs(c) => (float::to_str_exact, c as uint), + CountImplied => (float::to_str, 6u) + }; + let mut s = unchecked { to_str(f, digits) }; + if 0.0 <= f { + if have_flag(cv.flags, flag_sign_always) { + s = ~"+" + s; + } else if have_flag(cv.flags, flag_space_for_sign) { + s = ~" " + s; + } + } + return unchecked { pad(cv, s, PadFloat) }; + } + pure fn conv_poly<T>(cv: Conv, v: T) -> ~str { + let s = sys::log_str(v); + return conv_str(cv, s); + } + + // Convert an int to string with minimum number of digits. If precision is + // 0 and num is 0 then the result is the empty string. + pure fn int_to_str_prec(num: int, radix: uint, prec: uint) -> ~str { + return if num < 0 { + ~"-" + uint_to_str_prec(-num as uint, radix, prec) + } else { uint_to_str_prec(num as uint, radix, prec) }; + } + + // Convert a uint to string with a minimum number of digits. If precision + // is 0 and num is 0 then the result is the empty string. Could move this + // to uint: but it doesn't seem all that useful. + pure fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str { + return if prec == 0u && num == 0u { + ~"" + } else { + let s = uint::to_str(num, radix); + let len = str::char_len(s); + if len < prec { + let diff = prec - len; + let pad = str::from_chars(vec::from_elem(diff, '0')); + pad + s + } else { move s } + }; + } + pure fn get_int_precision(cv: Conv) -> uint { + return match cv.precision { + CountIs(c) => c as uint, + CountImplied => 1u + }; + } + + enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat } + + impl PadMode: Eq { + pure fn eq(&&other: PadMode) -> bool { + match (self, other) { + (PadSigned, PadSigned) => true, + (PadUnsigned, PadUnsigned) => true, + (PadNozero, PadNozero) => true, + (PadFloat, PadFloat) => true, + (PadSigned, _) => false, + (PadUnsigned, _) => false, + (PadNozero, _) => false, + (PadFloat, _) => false + } + } + pure fn ne(&&other: PadMode) -> bool { !self.eq(other) } + } + + fn pad(cv: Conv, &s: ~str, mode: PadMode) -> ~str { + let uwidth : uint = match cv.width { + CountImplied => return copy s, + CountIs(width) => { + // FIXME: width should probably be uint (see Issue #1996) + width as uint + } + }; + let strlen = str::char_len(s); + if uwidth <= strlen { return copy s; } + let mut padchar = ' '; + let diff = uwidth - strlen; + if have_flag(cv.flags, flag_left_justify) { + let padstr = str::from_chars(vec::from_elem(diff, padchar)); + return s + padstr; + } + let {might_zero_pad, signed} = match mode { + PadNozero => {might_zero_pad:false, signed:false}, + PadSigned => {might_zero_pad:true, signed:true }, + PadFloat => {might_zero_pad:true, signed:true}, + PadUnsigned => {might_zero_pad:true, signed:false} + }; + pure fn have_precision(cv: Conv) -> bool { + return match cv.precision { CountImplied => false, _ => true }; + } + let zero_padding = { + if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) && + (!have_precision(cv) || mode == PadFloat) { + padchar = '0'; + true + } else { + false + } + }; + let padstr = str::from_chars(vec::from_elem(diff, padchar)); + // This is completely heinous. If we have a signed value then + // potentially rip apart the intermediate result and insert some + // zeros. It may make sense to convert zero padding to a precision + // instead. + + if signed && zero_padding && str::len(s) > 0u { + let head = str::shift_char(s); + if head == '+' || head == '-' || head == ' ' { + let headstr = str::from_chars(vec::from_elem(1u, head)); + return headstr + padstr + s; + } + else { + str::unshift_char(s, head); + } + } + return padstr + s; + } + pure fn have_flag(flags: u32, f: u32) -> bool { + flags & f != 0 + } +} + +// XXX remove after snappies +#[cfg(stage0)] +#[allow(non_camel_case_types)] mod rt { const flag_none : u32 = 0u32; const flag_left_justify : u32 = 0b00000000000000000000000000000001u32; @@ -461,6 +653,7 @@ mod rt { } } + #[cfg(test)] mod test { #[test] |
