From 29c58c473f086af1c55f4a33ef9e6cbaa19ffdb1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Oct 2013 16:01:40 -0700 Subject: [PATCH] Remove the fmt! syntax extension It lived a good life, but its time has come. The groundwork is set for the official transition after the next snapshot (removal of XXX2 macros) --- Makefile.in | 2 +- src/libstd/unstable/extfmt.rs | 703 ------------------ src/libstd/unstable/mod.rs | 1 - src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/expand.rs | 68 +- src/libsyntax/ext/fmt.rs | 317 +------- src/test/compile-fail/extfmt-missing-type.rs | 13 - src/test/compile-fail/extfmt-no-args.rs | 13 - src/test/compile-fail/extfmt-non-literal.rs | 18 - src/test/compile-fail/extfmt-non-literal2.rs | 18 - .../compile-fail/extfmt-not-enough-args.rs | 15 - src/test/compile-fail/extfmt-too-many-args.rs | 15 - src/test/compile-fail/extfmt-unknown-type.rs | 13 - src/test/compile-fail/extfmt-unsigned-plus.rs | 16 - .../compile-fail/extfmt-unsigned-space.rs | 16 - .../compile-fail/extfmt-unterminated-conv.rs | 13 - src/test/run-pass/pure-fmt.rs | 34 - src/test/run-pass/syntax-extension-fmt.rs | 282 ------- 18 files changed, 26 insertions(+), 1533 deletions(-) delete mode 100644 src/libstd/unstable/extfmt.rs delete mode 100644 src/test/compile-fail/extfmt-missing-type.rs delete mode 100644 src/test/compile-fail/extfmt-no-args.rs delete mode 100644 src/test/compile-fail/extfmt-non-literal.rs delete mode 100644 src/test/compile-fail/extfmt-non-literal2.rs delete mode 100644 src/test/compile-fail/extfmt-not-enough-args.rs delete mode 100644 src/test/compile-fail/extfmt-too-many-args.rs delete mode 100644 src/test/compile-fail/extfmt-unknown-type.rs delete mode 100644 src/test/compile-fail/extfmt-unsigned-plus.rs delete mode 100644 src/test/compile-fail/extfmt-unsigned-space.rs delete mode 100644 src/test/compile-fail/extfmt-unterminated-conv.rs delete mode 100644 src/test/run-pass/pure-fmt.rs delete mode 100644 src/test/run-pass/syntax-extension-fmt.rs diff --git a/Makefile.in b/Makefile.in index 7e77f6fd678..8d35e01e4d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,7 +88,7 @@ ifneq ($(wildcard $(NON_BUILD_TARGET_TRIPLES)),) CFG_INFO := $(info cfg: non-build target triples $(NON_BUILD_TARGET_TRIPLES)) endif -CFG_RUSTC_FLAGS := $(RUSTFLAGS) --cfg nofmt +CFG_RUSTC_FLAGS := $(RUSTFLAGS) CFG_GCCISH_CFLAGS := CFG_GCCISH_LINK_FLAGS := diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs deleted file mode 100644 index 0131f2c603c..00000000000 --- a/src/libstd/unstable/extfmt.rs +++ /dev/null @@ -1,703 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support for fmt! expressions. -//! -//! The syntax is close to that of Posix format strings: -//! -//! ~~~~~~ -//! Format := '%' Parameter? Flag* Width? Precision? Type -//! Parameter := [0-9]+ '$' -//! Flag := [ 0#+-] -//! Width := Parameter | [0-9]+ -//! Precision := '.' [0-9]+ -//! Type := [bcdfiostuxX?] -//! ~~~~~~ -//! -//! * Parameter is the 1-based argument to apply the format to. Currently not -//! implemented. -//! * Flag 0 causes leading zeros to be used for padding when converting -//! numbers. -//! * Flag # causes the conversion to be done in an *alternative* manner. -//! Currently not implemented. -//! * Flag + causes signed numbers to always be prepended with a sign -//! character. -//! * Flag - left justifies the result -//! * Width specifies the minimum field width of the result. By default -//! leading spaces are added. -//! * Precision specifies the minimum number of digits for integral types -//! and the minimum number -//! of decimal places for float. -//! -//! The types currently supported are: -//! -//! * b - bool -//! * c - char -//! * d - int -//! * f - float -//! * i - int (same as d) -//! * o - uint as octal -//! * t - uint as binary -//! * u - uint -//! * x - uint as lower-case hexadecimal -//! * X - uint as upper-case hexadecimal -//! * s - str (any flavor) -//! * ? - arbitrary type (does not use the to_str trait) - -/* -Syntax Extension: fmt - -Format a string - -The 'fmt' extension is modeled on the posix printf system. - -A posix conversion ostensibly looks like this - -> %~[parameter]~[flags]~[width]~[.precision]~[length]type - -Given the different numeric type bestiary we have, we omit the 'length' -parameter and support slightly different conversions for 'type' - -> %~[parameter]~[flags]~[width]~[.precision]type - -we also only support translating-to-rust a tiny subset of the possible -combinations at the moment. - -Example: - -debug!("hello, %s!", "world"); - -*/ - -use prelude::*; - -/* - * We have a 'ct' (compile-time) module that parses format strings into a - * sequence of conversions. From those conversions AST fragments are built - * that call into properly-typed functions in the 'rt' (run-time) module. - * Each of those run-time conversion functions accepts another conversion - * description that specifies how to format its output. - * - * The building of the AST is currently done in a module inside the compiler, - * but should migrate over here as the plugin interface is defined. - */ - -// Functions used by the fmt extension at compile time -#[doc(hidden)] -pub mod ct { - use char; - use container::Container; - use prelude::*; - use str; - - #[deriving(Eq)] - pub enum Signedness { Signed, Unsigned, } - - #[deriving(Eq)] - pub enum Caseness { CaseUpper, CaseLower, } - - #[deriving(Eq)] - pub enum Ty { - TyBool, - TyStr, - TyChar, - TyInt(Signedness), - TyBits, - TyHex(Caseness), - TyOctal, - TyFloat, - TyPointer, - TyPoly, - } - - #[deriving(Eq)] - pub enum Flag { - FlagLeftJustify, - FlagLeftZeroPad, - FlagSpaceForSign, - FlagSignAlways, - FlagAlternate, - } - - #[deriving(Eq)] - pub enum Count { - CountIs(uint), - CountIsParam(uint), - CountIsNextParam, - CountImplied, - } - - #[deriving(Eq)] - struct Parsed { - val: T, - next: uint - } - - impl Parsed { - pub fn new(val: T, next: uint) -> Parsed { - Parsed {val: val, next: next} - } - } - - // A formatted conversion from an expression to a string - #[deriving(Eq)] - pub struct Conv { - param: Option, - flags: ~[Flag], - width: Count, - precision: Count, - ty: Ty - } - - // A fragment of the output sequence - #[deriving(Eq)] - pub enum Piece { - PieceString(~str), - PieceConv(Conv), - } - - pub type ErrorFn<'self> = &'self fn(&str) -> !; - - pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] { - fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) { - if to > from { - ps.push(PieceString(s.slice(from, to).to_owned())); - } - } - - let lim = s.len(); - let mut h = 0; - let mut i = 0; - let mut pieces = ~[]; - - while i < lim { - if s[i] == '%' as u8 { - i += 1; - - if i >= lim { - err("unterminated conversion at end of string"); - } else if s[i] == '%' as u8 { - push_slice(&mut pieces, s, h, i); - i += 1; - } else { - push_slice(&mut pieces, s, h, i - 1); - let Parsed { - val, - next - } = parse_conversion(s, i, lim, |s| err(s)); - pieces.push(val); - i = next; - } - - h = i; - } else { - i += str::utf8_char_width(s[i]); - } - } - - push_slice(&mut pieces, s, h, i); - pieces - } - - pub fn peek_num(s: &str, i: uint, lim: uint) -> Option> { - let mut i = i; - let mut accum = 0; - let mut found = false; - - while i < lim { - match char::to_digit(s[i] as char, 10) { - Some(x) => { - found = true; - accum *= 10; - accum += x; - i += 1; - } - None => break - } - } - - if found { - Some(Parsed::new(accum, i)) - } else { - None - } - } - - pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>) - -> Parsed { - let param = parse_parameter(s, i, lim); - // avoid copying ~[Flag] by destructuring - let Parsed {val: flags_val, next: flags_next} = parse_flags(s, - param.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, err); - - Parsed::new(PieceConv(Conv { - param: param.val, - flags: flags_val, - width: width.val, - precision: prec.val, - ty: ty.val}), ty.next) - } - - pub fn parse_parameter(s: &str, i: uint, lim: uint) -> - Parsed> { - if i >= lim { return Parsed::new(None, i); } - - match peek_num(s, i, lim) { - Some(num) if num.next < lim && s[num.next] == '$' as u8 => - Parsed::new(Some(num.val), num.next + 1), - _ => Parsed::new(None, i) - } - } - - pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> { - let mut i = i; - let mut flags = ~[]; - - while i < lim { - let f = match s[i] as char { - '-' => FlagLeftJustify, - '0' => FlagLeftZeroPad, - ' ' => FlagSpaceForSign, - '+' => FlagSignAlways, - '#' => FlagAlternate, - _ => break - }; - - flags.push(f); - i += 1; - } - - Parsed::new(flags, i) - } - - pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed { - if i >= lim { - Parsed::new(CountImplied, i) - } else if s[i] == '*' as u8 { - let param = parse_parameter(s, i + 1, lim); - let j = param.next; - - match param.val { - None => Parsed::new(CountIsNextParam, j), - Some(n) => Parsed::new(CountIsParam(n), j) - } - } else { - match peek_num(s, i, lim) { - None => Parsed::new(CountImplied, i), - Some(num) => Parsed::new(CountIs(num.val), num.next) - } - } - } - - pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed { - if i < lim && s[i] == '.' as u8 { - let count = parse_count(s, i + 1, lim); - - // If there were no digits specified, i.e. the precision - // was ".", then the precision is 0 - match count.val { - CountImplied => Parsed::new(CountIs(0), count.next), - _ => count - } - } else { - Parsed::new(CountImplied, i) - } - } - - pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>) - -> Parsed { - if i >= lim { err("missing type in conversion"); } - - // FIXME (#2249): Do we really want two signed types here? - // How important is it to be printf compatible? - let t = match s[i] as char { - 'b' => TyBool, - 's' => TyStr, - 'c' => TyChar, - 'd' | 'i' => TyInt(Signed), - 'u' => TyInt(Unsigned), - 'x' => TyHex(CaseLower), - 'X' => TyHex(CaseUpper), - 't' => TyBits, - 'o' => TyOctal, - 'f' => TyFloat, - 'p' => TyPointer, - '?' => TyPoly, - _ => err(format!("unknown type in conversion: {}", s.char_at(i))) - }; - - Parsed::new(t, i + 1) - } - - #[cfg(test)] - fn die(s: &str) -> ! { fail2!(s.to_owned()) } - - #[test] - fn test_parse_count() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_count(s, 0, s.len()) == Parsed::new(count, next) - } - - assert!(test("", CountImplied, 0)); - assert!(test("*", CountIsNextParam, 1)); - assert!(test("*1", CountIsNextParam, 1)); - assert!(test("*1$", CountIsParam(1), 3)); - assert!(test("123", CountIs(123), 3)); - } - - #[test] - fn test_parse_flags() { - fn pack(fs: &[Flag]) -> uint { - fs.iter().fold(0, |p, &f| p | (1 << f as uint)) - } - - fn test(s: &str, flags: &[Flag], next: uint) { - let f = parse_flags(s, 0, s.len()); - assert_eq!(pack(f.val), pack(flags)); - assert_eq!(f.next, next); - } - - test("", [], 0); - test("!#-+ 0", [], 0); - test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3); - test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2); - } - - #[test] - fn test_parse_fmt_string() { - assert!(parse_fmt_string("foo %s bar", die) == ~[ - PieceString(~"foo "), - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - }), - PieceString(~" bar")]); - - assert!(parse_fmt_string("%s", die) == ~[ - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - })]); - - assert!(parse_fmt_string("%%%%", die) == ~[ - PieceString(~"%"), PieceString(~"%")]); - } - - #[test] - fn test_parse_parameter() { - fn test(s: &str, param: Option, next: uint) -> bool { - parse_parameter(s, 0, s.len()) == Parsed::new(param, next) - } - - assert!(test("", None, 0)); - assert!(test("foo", None, 0)); - assert!(test("123", None, 0)); - assert!(test("123$", Some(123), 4)); - } - - #[test] - fn test_parse_precision() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_precision(s, 0, s.len()) == Parsed::new(count, next) - } - - assert!(test("", CountImplied, 0)); - assert!(test(".", CountIs(0), 1)); - assert!(test(".*", CountIsNextParam, 2)); - assert!(test(".*1", CountIsNextParam, 2)); - assert!(test(".*1$", CountIsParam(1), 4)); - assert!(test(".123", CountIs(123), 4)); - } - - #[test] - fn test_parse_type() { - fn test(s: &str, ty: Ty) -> bool { - parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1) - } - - assert!(test("b", TyBool)); - assert!(test("c", TyChar)); - assert!(test("d", TyInt(Signed))); - assert!(test("f", TyFloat)); - assert!(test("i", TyInt(Signed))); - assert!(test("o", TyOctal)); - assert!(test("s", TyStr)); - assert!(test("t", TyBits)); - assert!(test("x", TyHex(CaseLower))); - assert!(test("X", TyHex(CaseUpper))); - assert!(test("p", TyPointer)); - assert!(test("?", TyPoly)); - } - - #[test] - #[should_fail] - fn test_parse_type_missing() { - parse_type("", 0, 0, die); - } - - #[test] - #[should_fail] - fn test_parse_type_unknown() { - parse_type("!", 0, 1, die); - } - - #[test] - fn test_peek_num() { - let s1 = ""; - assert!(peek_num(s1, 0, s1.len()).is_none()); - - let s2 = "foo"; - assert!(peek_num(s2, 0, s2.len()).is_none()); - - let s3 = "123"; - assert_eq!(peek_num(s3, 0, s3.len()), Some(Parsed::new(123, 3))); - - let s4 = "123foo"; - assert_eq!(peek_num(s4, 0, s4.len()), Some(Parsed::new(123, 3))); - } -} - -// Functions used by the fmt extension at runtime. For now there are a lot of -// 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 this way, I think. -#[doc(hidden)] -#[allow(non_uppercase_statics)] -pub mod rt { - use f64; - use str; - use sys; - use num; - use vec; - use option::{Some, None, Option}; - - pub static flag_none : u32 = 0u32; - pub static flag_left_justify : u32 = 0b00000000000001u32; - pub static flag_left_zero_pad : u32 = 0b00000000000010u32; - pub static flag_space_for_sign : u32 = 0b00000000000100u32; - pub static flag_sign_always : u32 = 0b00000000001000u32; - pub static flag_alternate : u32 = 0b00000000010000u32; - - pub enum Count { CountIs(uint), CountImplied, } - - pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, } - - pub struct Conv { - flags: u32, - width: Count, - precision: Count, - ty: Ty, - } - - pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) { - let radix = 10; - let prec = get_int_precision(cv); - let s : ~str = uint_to_str_prec(num::abs(i) as uint, radix, prec); - - let head = if i >= 0 { - if have_flag(cv.flags, flag_sign_always) { - Some('+') - } else if have_flag(cv.flags, flag_space_for_sign) { - Some(' ') - } else { - None - } - } else { Some('-') }; - pad(cv, s, head, PadSigned, buf); - } - pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) { - let prec = get_int_precision(cv); - let rs = - match cv.ty { - TyDefault => uint_to_str_prec(u, 10, prec), - TyHexLower => uint_to_str_prec(u, 16, prec), - - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_move and to_str_move to not do a unnecessary copy. - TyHexUpper => { - let s = uint_to_str_prec(u, 16, prec); - s.to_ascii().to_upper().to_str_ascii() - } - TyBits => uint_to_str_prec(u, 2, prec), - TyOctal => uint_to_str_prec(u, 8, prec) - }; - pad(cv, rs, None, PadUnsigned, buf); - } - pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~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. - conv_str(cv, s, buf); - } - pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) { - pad(cv, "", Some(c), PadNozero, buf); - } - pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) { - // For strings, precision is the maximum characters - // displayed - let unpadded = match cv.precision { - CountImplied => s, - CountIs(max) => { - if (max as uint) < s.char_len() { - s.slice(0, max as uint) - } else { - s - } - } - }; - pad(cv, unpadded, None, PadNozero, buf); - } - pub fn conv_float(cv: Conv, f: f64, buf: &mut ~str) { - let (to_str, digits) = match cv.precision { - CountIs(c) => (f64::to_str_exact, c as uint), - CountImplied => (f64::to_str_digits, 6u) - }; - let s = to_str(f, digits); - let head = if 0.0 <= f { - if have_flag(cv.flags, flag_sign_always) { - Some('+') - } else if have_flag(cv.flags, flag_space_for_sign) { - Some(' ') - } else { - None - } - } else { None }; - pad(cv, s, head, PadFloat, buf); - } - pub fn conv_pointer(cv: Conv, ptr: *T, buf: &mut ~str) { - let s = ~"0x" + uint_to_str_prec(ptr as uint, 16, 1u); - pad(cv, s, None, PadNozero, buf); - } - pub fn conv_poly(cv: Conv, v: &T, buf: &mut ~str) { - let s = sys::log_str(v); - conv_str(cv, s, buf); - } - - // 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. - pub fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str { - return if prec == 0u && num == 0u { - ~"" - } else { - let s = num.to_str_radix(radix); - let len = s.char_len(); - if len < prec { - let diff = prec - len; - let pad = str::from_chars(vec::from_elem(diff, '0')); - pad + s - } else { s } - }; - } - pub fn get_int_precision(cv: Conv) -> uint { - return match cv.precision { - CountIs(c) => c as uint, - CountImplied => 1u - }; - } - - #[deriving(Eq)] - pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat } - - pub fn pad(cv: Conv, s: &str, head: Option, mode: PadMode, - buf: &mut ~str) { - let headsize = match head { Some(_) => 1, _ => 0 }; - let uwidth : uint = match cv.width { - CountImplied => { - for &c in head.iter() { - buf.push_char(c); - } - return buf.push_str(s); - } - CountIs(width) => { width as uint } - }; - let strlen = s.char_len() + headsize; - if uwidth <= strlen { - for &c in head.iter() { - buf.push_char(c); - } - return buf.push_str(s); - } - let mut padchar = ' '; - let diff = uwidth - strlen; - if have_flag(cv.flags, flag_left_justify) { - for &c in head.iter() { - buf.push_char(c); - } - buf.push_str(s); - do diff.times { - buf.push_char(padchar); - } - return; - } - let (might_zero_pad, signed) = match mode { - PadNozero => (false, true), - PadSigned => (true, true), - PadFloat => (true, true), - PadUnsigned => (true, false) - }; - 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 { - for &head in head.iter() { - if head == '+' || head == '-' || head == ' ' { - buf.push_char(head); - buf.push_str(padstr); - buf.push_str(s); - return; - } - } - } - buf.push_str(padstr); - for &c in head.iter() { - buf.push_char(c); - } - buf.push_str(s); - } - #[inline] - pub fn have_flag(flags: u32, f: u32) -> bool { - flags & f != 0 - } -} - -// Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs -#[cfg(test)] -mod test { - #[test] - fn fmt_slice() { - let s = "abc"; - let _s = format!("{}", s); - } -} diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 0e281f33e2a..835b16996b5 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -21,7 +21,6 @@ pub mod dynamic_lib; pub mod finally; pub mod intrinsics; pub mod simd; -pub mod extfmt; #[cfg(not(test))] pub mod lang; pub mod sync; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a64e8ff825c..78c4d6b6f4b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -222,7 +222,7 @@ pub fn syntax_expander_table() -> SyntaxEnv { span: None, } as @SyntaxExpanderTTItemTrait, None))); - syntax_expanders.insert(intern(&"oldfmt"), + syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt_no_ctxt( ext::fmt::expand_syntax_ext)); syntax_expanders.insert(intern(&"format_args"), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1114e3a9893..bc91283b47b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -809,51 +809,7 @@ pub fn std_macros() -> @str { macro_rules! ignore (($($x:tt)*) => (())) - #[cfg(not(nofmt))] - mod fmt_extension { - #[macro_escape]; - - macro_rules! fmt(($($arg:tt)*) => (oldfmt!($($arg)*))) - - macro_rules! log( - ($lvl:expr, $arg:expr) => ({ - let lvl = $lvl; - if lvl <= __log_level() { - format_args!(|args| { - ::std::logging::log(lvl, args) - }, \"{}\", fmt!(\"%?\", $arg)) - } - }); - ($lvl:expr, $($arg:expr),+) => ({ - let lvl = $lvl; - if lvl <= __log_level() { - format_args!(|args| { - ::std::logging::log(lvl, args) - }, \"{}\", fmt!($($arg),+)) - } - }) - ) - macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) ) - macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) ) - macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) ) - macro_rules! debug( ($($arg:tt)*) => ( - if cfg!(not(ndebug)) { log!(4u32, $($arg)*) } - )) - - macro_rules! fail( - () => ( - fail2!(\"explicit failure\") - ); - ($msg:expr) => ( - ::std::sys::FailWithCause::fail_with($msg, file!(), line!()) - ); - ($( $arg:expr ),+) => ( - ::std::sys::FailWithCause::fail_with(fmt!( $($arg),+ ), file!(), line!()) - ) - ) - } - - macro_rules! log2( + macro_rules! log( ($lvl:expr, $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= __log_level() { @@ -863,16 +819,16 @@ pub fn std_macros() -> @str { } }) ) - macro_rules! error2( ($($arg:tt)*) => (log2!(1u32, $($arg)*)) ) - macro_rules! warn2 ( ($($arg:tt)*) => (log2!(2u32, $($arg)*)) ) - macro_rules! info2 ( ($($arg:tt)*) => (log2!(3u32, $($arg)*)) ) - macro_rules! debug2( ($($arg:tt)*) => ( - if cfg!(not(ndebug)) { log2!(4u32, $($arg)*) } + macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) ) + macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) ) + macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) ) + macro_rules! debug( ($($arg:tt)*) => ( + if cfg!(not(ndebug)) { log!(4u32, $($arg)*) } )) - macro_rules! fail2( + macro_rules! fail( () => ( - fail2!(\"explicit failure\") + fail!(\"explicit failure\") ); ($fmt:expr) => ( ::std::sys::FailWithCause::fail_with($fmt, file!(), line!()) @@ -882,6 +838,14 @@ pub fn std_macros() -> @str { ) ) + // NOTE (acrichto): remove these after the next snapshot + macro_rules! log2( ($($arg:tt)*) => (log!($($arg)*)) ) + macro_rules! error2( ($($arg:tt)*) => (error!($($arg)*)) ) + macro_rules! warn2 ( ($($arg:tt)*) => (warn!($($arg)*)) ) + macro_rules! info2 ( ($($arg:tt)*) => (info!($($arg)*)) ) + macro_rules! debug2( ($($arg:tt)*) => (debug!($($arg)*)) ) + macro_rules! fail2( ($($arg:tt)*) => (fail!($($arg)*)) ) + macro_rules! assert( ($cond:expr) => { if !$cond { diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 8258048a04d..5e3e4e15d8e 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -8,320 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/* - * The compiler code necessary to support the fmt! extension. Eventually this - * should all get sucked into either the standard library extfmt module or the - * compiler syntax extension plugin interface. - */ +/// Deprecated fmt! syntax extension use ast; use codemap::Span; -use ext::base::*; use ext::base; use ext::build::AstBuilder; -use std::option; -use std::unstable::extfmt::ct::*; -use parse::token::{str_to_ident}; +pub fn expand_syntax_ext(ecx: @base::ExtCtxt, sp: Span, + _tts: &[ast::token_tree]) -> base::MacResult { + ecx.span_err(sp, "`fmt!` is deprecated, use `format!` instead"); + ecx.parse_sess.span_diagnostic.span_note(sp, + "see http://static.rust-lang.org/doc/master/std/fmt/index.html \ + for documentation"); -pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) - -> base::MacResult { - let args = get_exprs_from_tts(cx, sp, tts); - if args.len() == 0 { - cx.span_fatal(sp, "fmt! takes at least 1 argument."); - } - let (fmt, _fmt_str_style) = - expr_to_str(cx, args[0], - "first argument to fmt! must be a string literal."); - let fmtspan = args[0].span; - debug2!("Format string: {}", fmt); - fn parse_fmt_err_(cx: @ExtCtxt, sp: Span, msg: &str) -> ! { - cx.span_fatal(sp, msg); - } - let parse_fmt_err: &fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s); - let pieces = parse_fmt_string(fmt, parse_fmt_err); - MRExpr(pieces_to_expr(cx, sp, pieces, args)) -} - -// FIXME (#2249): A lot of these functions for producing expressions can -// probably be factored out in common with other code that builds -// expressions. Also: Cleanup the naming of these functions. -// Note: Moved many of the common ones to build.rs --kevina -fn pieces_to_expr(cx: @ExtCtxt, sp: Span, - pieces: ~[Piece], args: ~[@ast::Expr]) - -> @ast::Expr { - fn make_path_vec(ident: &str) -> ~[ast::Ident] { - return ~[str_to_ident("std"), - str_to_ident("unstable"), - str_to_ident("extfmt"), - str_to_ident("rt"), - str_to_ident(ident)]; - } - fn make_rt_path_expr(cx: @ExtCtxt, sp: Span, nm: &str) -> @ast::Expr { - let path = make_path_vec(nm); - cx.expr_path(cx.path_global(sp, path)) - } - // Produces an AST expression that represents a RT::conv record, - // which tells the RT::conv* functions how to perform the conversion - - fn make_rt_conv_expr(cx: @ExtCtxt, sp: Span, cnv: &Conv) -> @ast::Expr { - fn make_flags(cx: @ExtCtxt, sp: Span, flags: &[Flag]) -> @ast::Expr { - let mut tmp_expr = make_rt_path_expr(cx, sp, "flag_none"); - for f in flags.iter() { - let fstr = match *f { - FlagLeftJustify => "flag_left_justify", - FlagLeftZeroPad => "flag_left_zero_pad", - FlagSpaceForSign => "flag_space_for_sign", - FlagSignAlways => "flag_sign_always", - FlagAlternate => "flag_alternate" - }; - tmp_expr = cx.expr_binary(sp, ast::BiBitOr, tmp_expr, - make_rt_path_expr(cx, sp, fstr)); - } - return tmp_expr; - } - fn make_count(cx: @ExtCtxt, sp: Span, cnt: Count) -> @ast::Expr { - match cnt { - CountImplied => { - return make_rt_path_expr(cx, sp, "CountImplied"); - } - CountIs(c) => { - let count_lit = cx.expr_uint(sp, c as uint); - let count_is_path = make_path_vec("CountIs"); - let count_is_args = ~[count_lit]; - return cx.expr_call_global(sp, count_is_path, count_is_args); - } - _ => cx.span_unimpl(sp, "unimplemented fmt! conversion") - } - } - fn make_ty(cx: @ExtCtxt, sp: Span, t: Ty) -> @ast::Expr { - let rt_type = match t { - TyHex(c) => match c { - CaseUpper => "TyHexUpper", - CaseLower => "TyHexLower" - }, - TyBits => "TyBits", - TyOctal => "TyOctal", - _ => "TyDefault" - }; - return make_rt_path_expr(cx, sp, rt_type); - } - fn make_conv_struct(cx: @ExtCtxt, sp: Span, flags_expr: @ast::Expr, - width_expr: @ast::Expr, precision_expr: @ast::Expr, - ty_expr: @ast::Expr) -> @ast::Expr { - cx.expr_struct( - sp, - cx.path_global(sp, make_path_vec("Conv")), - ~[ - cx.field_imm(sp, str_to_ident("flags"), flags_expr), - cx.field_imm(sp, str_to_ident("width"), width_expr), - cx.field_imm(sp, str_to_ident("precision"), precision_expr), - cx.field_imm(sp, str_to_ident("ty"), ty_expr) - ] - ) - } - let rt_conv_flags = make_flags(cx, sp, cnv.flags); - let rt_conv_width = make_count(cx, sp, cnv.width); - let rt_conv_precision = make_count(cx, sp, cnv.precision); - let rt_conv_ty = make_ty(cx, sp, cnv.ty); - make_conv_struct(cx, sp, rt_conv_flags, rt_conv_width, - rt_conv_precision, rt_conv_ty) - } - fn make_conv_call(cx: @ExtCtxt, sp: Span, conv_type: &str, cnv: &Conv, - arg: @ast::Expr, buf: @ast::Expr) -> @ast::Expr { - let fname = ~"conv_" + conv_type; - let path = make_path_vec(fname); - let cnv_expr = make_rt_conv_expr(cx, sp, cnv); - let args = ~[cnv_expr, arg, buf]; - cx.expr_call_global(arg.span, path, args) - } - - fn make_new_conv(cx: @ExtCtxt, sp: Span, cnv: &Conv, - arg: @ast::Expr, buf: @ast::Expr) -> @ast::Expr { - fn is_signed_type(cnv: &Conv) -> bool { - match cnv.ty { - TyInt(s) => match s { - Signed => return true, - Unsigned => return false - }, - TyFloat => return true, - _ => return false - } - } - let unsupported = ~"conversion not supported in fmt! string"; - match cnv.param { - option::None => (), - _ => cx.span_unimpl(sp, unsupported) - } - for f in cnv.flags.iter() { - match *f { - FlagLeftJustify => (), - FlagSignAlways => { - if !is_signed_type(cnv) { - cx.span_fatal(sp, - "+ flag only valid in \ - signed fmt! conversion"); - } - } - FlagSpaceForSign => { - if !is_signed_type(cnv) { - cx.span_fatal(sp, - "space flag only valid in \ - signed fmt! conversions"); - } - } - FlagLeftZeroPad => (), - _ => cx.span_unimpl(sp, unsupported) - } - } - match cnv.width { - CountImplied => (), - CountIs(_) => (), - _ => cx.span_unimpl(sp, unsupported) - } - match cnv.precision { - CountImplied => (), - CountIs(_) => (), - _ => cx.span_unimpl(sp, unsupported) - } - let (name, actual_arg) = match cnv.ty { - TyStr => ("str", arg), - TyInt(Signed) => ("int", arg), - TyBool => ("bool", arg), - TyChar => ("char", arg), - TyBits | TyOctal | TyHex(_) | TyInt(Unsigned) => ("uint", arg), - TyFloat => ("float", arg), - TyPointer => ("pointer", arg), - TyPoly => ("poly", cx.expr_addr_of(sp, arg)) - }; - return make_conv_call(cx, arg.span, name, cnv, actual_arg, - cx.expr_mut_addr_of(arg.span, buf)); - } - fn log_conv(c: &Conv) { - debug2!("Building conversion:"); - match c.param { - Some(p) => { debug2!("param: {}", p.to_str()); } - _ => debug2!("param: none") - } - for f in c.flags.iter() { - match *f { - FlagLeftJustify => debug2!("flag: left justify"), - FlagLeftZeroPad => debug2!("flag: left zero pad"), - FlagSpaceForSign => debug2!("flag: left space pad"), - FlagSignAlways => debug2!("flag: sign always"), - FlagAlternate => debug2!("flag: alternate") - } - } - match c.width { - CountIs(i) => - debug2!("width: count is {}", i.to_str()), - CountIsParam(i) => - debug2!("width: count is param {}", i.to_str()), - CountIsNextParam => debug2!("width: count is next param"), - CountImplied => debug2!("width: count is implied") - } - match c.precision { - CountIs(i) => - debug2!("prec: count is {}", i.to_str()), - CountIsParam(i) => - debug2!("prec: count is param {}", i.to_str()), - CountIsNextParam => debug2!("prec: count is next param"), - CountImplied => debug2!("prec: count is implied") - } - match c.ty { - TyBool => debug2!("type: bool"), - TyStr => debug2!("type: str"), - TyChar => debug2!("type: char"), - TyInt(s) => match s { - Signed => debug2!("type: signed"), - Unsigned => debug2!("type: unsigned") - }, - TyBits => debug2!("type: bits"), - TyHex(cs) => match cs { - CaseUpper => debug2!("type: uhex"), - CaseLower => debug2!("type: lhex"), - }, - TyOctal => debug2!("type: octal"), - TyFloat => debug2!("type: float"), - TyPointer => debug2!("type: pointer"), - TyPoly => debug2!("type: poly") - } - } - - /* Short circuit an easy case up front (won't work otherwise) */ - if pieces.len() == 0 { - return cx.expr_str_uniq(args[0].span, @""); - } - - let fmt_sp = args[0].span; - let mut n = 0u; - let nargs = args.len(); - - /* 'ident' is the local buffer building up the result of fmt! */ - let ident = str_to_ident("__fmtbuf"); - let buf = || cx.expr_ident(fmt_sp, ident); - let core_ident = str_to_ident("std"); - let str_ident = str_to_ident("str"); - let push_ident = str_to_ident("push_str"); - let mut stms = ~[]; - - /* Translate each piece (portion of the fmt expression) by invoking the - corresponding function in std::unstable::extfmt. Each function takes a - buffer to insert data into along with the data being formatted. */ - let npieces = pieces.len(); - for (i, pc) in pieces.move_iter().enumerate() { - match pc { - /* Raw strings get appended via str::push_str */ - PieceString(s) => { - /* If this is the first portion, then initialize the local - buffer with it directly. If it's actually the only piece, - then there's no need for it to be mutable */ - if i == 0 { - stms.push(cx.stmt_let(fmt_sp, npieces > 1, - ident, cx.expr_str_uniq(fmt_sp, s.to_managed()))); - } else { - // we call the push_str function because the - // bootstrap doesnt't seem to work if we call the - // method. - let args = ~[cx.expr_mut_addr_of(fmt_sp, buf()), - cx.expr_str(fmt_sp, s.to_managed())]; - let call = cx.expr_call_global(fmt_sp, - ~[core_ident, - str_ident, - push_ident], - args); - stms.push(cx.stmt_expr(call)); - } - } - - /* Invoke the correct conv function in extfmt */ - PieceConv(ref conv) => { - n += 1u; - if n >= nargs { - cx.span_fatal(sp, - "not enough arguments to fmt! \ - for the given format string"); - } - - log_conv(conv); - /* If the first portion is a conversion, then the local buffer - must be initialized as an empty string */ - if i == 0 { - stms.push(cx.stmt_let(fmt_sp, true, ident, - cx.expr_str_uniq(fmt_sp, @""))); - } - stms.push(cx.stmt_expr(make_new_conv(cx, fmt_sp, conv, - args[n], buf()))); - } - } - } - - let expected_nargs = n + 1u; // n conversions + the fmt string - if expected_nargs < nargs { - cx.span_fatal - (sp, format!("too many arguments to fmt!. found {}, expected {}", - nargs, expected_nargs)); - } - - cx.expr_block(cx.block(fmt_sp, stms, Some(buf()))) + base::MRExpr(ecx.expr_uint(sp, 2)) } diff --git a/src/test/compile-fail/extfmt-missing-type.rs b/src/test/compile-fail/extfmt-missing-type.rs deleted file mode 100644 index 7602656eabb..00000000000 --- a/src/test/compile-fail/extfmt-missing-type.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:missing type - -fn main() { oldfmt!("%+"); } diff --git a/src/test/compile-fail/extfmt-no-args.rs b/src/test/compile-fail/extfmt-no-args.rs deleted file mode 100644 index 2721c780ac6..00000000000 --- a/src/test/compile-fail/extfmt-no-args.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:fmt! takes at least 1 argument - -fn main() { oldfmt!(); } diff --git a/src/test/compile-fail/extfmt-non-literal.rs b/src/test/compile-fail/extfmt-non-literal.rs deleted file mode 100644 index 7aa744a11ca..00000000000 --- a/src/test/compile-fail/extfmt-non-literal.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: literal - -fn main() { - // fmt!'s first argument must be a literal. Hopefully this - // restriction can be eased eventually to just require a - // compile-time constant. - let x = oldfmt!("a" + "b"); -} diff --git a/src/test/compile-fail/extfmt-non-literal2.rs b/src/test/compile-fail/extfmt-non-literal2.rs deleted file mode 100644 index e25eae82127..00000000000 --- a/src/test/compile-fail/extfmt-non-literal2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: literal - -fn main() { - // fmt!'s first argument must be a literal. Hopefully this - // restriction can be eased eventually to just require a - // compile-time constant. - let x = oldfmt!(20); -} diff --git a/src/test/compile-fail/extfmt-not-enough-args.rs b/src/test/compile-fail/extfmt-not-enough-args.rs deleted file mode 100644 index 5fd17fe92c1..00000000000 --- a/src/test/compile-fail/extfmt-not-enough-args.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:not enough arguments - -extern mod extra; - -fn main() { let s = oldfmt!("%s%s%s", "test", "test"); } diff --git a/src/test/compile-fail/extfmt-too-many-args.rs b/src/test/compile-fail/extfmt-too-many-args.rs deleted file mode 100644 index 5e12543ce8f..00000000000 --- a/src/test/compile-fail/extfmt-too-many-args.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:too many arguments - -extern mod extra; - -fn main() { let s = oldfmt!("%s", "test", "test"); } diff --git a/src/test/compile-fail/extfmt-unknown-type.rs b/src/test/compile-fail/extfmt-unknown-type.rs deleted file mode 100644 index 94ded1c528f..00000000000 --- a/src/test/compile-fail/extfmt-unknown-type.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:unknown type - -fn main() { oldfmt!("%w"); } diff --git a/src/test/compile-fail/extfmt-unsigned-plus.rs b/src/test/compile-fail/extfmt-unsigned-plus.rs deleted file mode 100644 index 4e165153c0b..00000000000 --- a/src/test/compile-fail/extfmt-unsigned-plus.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:only valid in signed fmt! conversion - -fn main() { - // Can't use a sign on unsigned conversions - oldfmt!("%+u", 10u); -} diff --git a/src/test/compile-fail/extfmt-unsigned-space.rs b/src/test/compile-fail/extfmt-unsigned-space.rs deleted file mode 100644 index 8396ecc25c1..00000000000 --- a/src/test/compile-fail/extfmt-unsigned-space.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:only valid in signed fmt! conversion - -fn main() { - // Can't use a space on unsigned conversions - oldfmt!("% u", 10u); -} diff --git a/src/test/compile-fail/extfmt-unterminated-conv.rs b/src/test/compile-fail/extfmt-unterminated-conv.rs deleted file mode 100644 index 373a10e99cf..00000000000 --- a/src/test/compile-fail/extfmt-unterminated-conv.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:unterminated conversion - -fn main() { oldfmt!("%"); } diff --git a/src/test/run-pass/pure-fmt.rs b/src/test/run-pass/pure-fmt.rs deleted file mode 100644 index d7cf9f2cd2f..00000000000 --- a/src/test/run-pass/pure-fmt.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Testing that calling fmt! (via info2!) doesn't complain about impure borrows - -struct Big { b: @~str, c: uint, d: int, e: char, - f: f64, g: bool } - -fn foo() { - let a = Big { - b: @~"hi", - c: 0, - d: 1, - e: 'a', - f: 0.0, - g: true - }; - info2!("test {:?}", a.b); - info2!("test {:u}", a.c); - info2!("test {:i}", a.d); - info2!("test {:c}", a.e); - info2!("test {:f}", a.f); - info2!("test {:b}", a.g); -} - -pub fn main() { -} diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs deleted file mode 100644 index 15a343044e1..00000000000 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[feature(macro_rules)]; - -// compile-flags: --cfg nofmt - -extern mod extra; - -macro_rules! fmt(($($arg:tt)*) => (oldfmt!($($arg)*))) - -fn test(actual: ~str, expected: ~str) { - info2!("{}", actual.clone()); - info2!("{}", expected.clone()); - assert_eq!(actual, expected); -} - -pub fn main() { - test(fmt!("hello %d friends and %s things", 10, "formatted"), - ~"hello 10 friends and formatted things"); - - test(fmt!("test"), ~"test"); - - // a quadratic optimization in LLVM (jump-threading) makes this test a - // bit slow to compile unless we break it up - part1(); - part2(); - part3(); - part4(); - part5(); - part6(); - percent(); - more_floats(); - pointer(); -} - -fn part1() { - // Simple tests for types - - test(fmt!("%d", 1), ~"1"); - test(fmt!("%i", 2), ~"2"); - test(fmt!("%i", -1), ~"-1"); - test(fmt!("%u", 10u), ~"10"); - test(fmt!("%s", "test"), ~"test"); - test(fmt!("%b", true), ~"true"); - test(fmt!("%b", false), ~"false"); - test(fmt!("%c", 'A'), ~"A"); - test(fmt!("%x", 0xff_u), ~"ff"); - test(fmt!("%X", 0x12ab_u), ~"12AB"); - test(fmt!("%o", 10u), ~"12"); - test(fmt!("%t", 0b11010101_u), ~"11010101"); - test(fmt!("%f", 5.82), ~"5.82"); - // 32-bit limits - - test(fmt!("%i", -2147483648), ~"-2147483648"); - test(fmt!("%i", 2147483647), ~"2147483647"); - test(fmt!("%u", 4294967295u), ~"4294967295"); - test(fmt!("%x", 0xffffffff_u), ~"ffffffff"); - test(fmt!("%o", 0xffffffff_u), ~"37777777777"); - test(fmt!("%t", 0xffffffff_u), ~"11111111111111111111111111111111"); - - // Don't result in a compilation error - test(fmt!(""), ~""); -} -fn part2() { - // Widths - - test(fmt!("%1d", 500), ~"500"); - test(fmt!("%10d", 500), ~" 500"); - test(fmt!("%10d", -500), ~" -500"); - test(fmt!("%10u", 500u), ~" 500"); - test(fmt!("%10s", "test"), ~" test"); - test(fmt!("%10b", true), ~" true"); - test(fmt!("%10x", 0xff_u), ~" ff"); - test(fmt!("%10X", 0xff_u), ~" FF"); - test(fmt!("%10o", 10u), ~" 12"); - test(fmt!("%10t", 0xff_u), ~" 11111111"); - test(fmt!("%10c", 'A'), ~" A"); - test(fmt!("%10f", 5.82), ~" 5.82"); - // Left justify - - test(fmt!("%-10d", 500), ~"500 "); - test(fmt!("%-10d", -500), ~"-500 "); - test(fmt!("%-10u", 500u), ~"500 "); - test(fmt!("%-10s", "test"), ~"test "); - test(fmt!("%-10b", true), ~"true "); - test(fmt!("%-10x", 0xff_u), ~"ff "); - test(fmt!("%-10X", 0xff_u), ~"FF "); - test(fmt!("%-10o", 10u), ~"12 "); - test(fmt!("%-10t", 0xff_u), ~"11111111 "); - test(fmt!("%-10c", 'A'), ~"A "); - test(fmt!("%-10f", 5.82), ~"5.82 "); -} - -fn part3() { - // Precision - - test(fmt!("%.d", 0), ~""); - test(fmt!("%.u", 0u), ~""); - test(fmt!("%.x", 0u), ~""); - test(fmt!("%.t", 0u), ~""); - test(fmt!("%.d", 10), ~"10"); - test(fmt!("%.d", -10), ~"-10"); - test(fmt!("%.u", 10u), ~"10"); - test(fmt!("%.s", "test"), ~""); - test(fmt!("%.x", 127u), ~"7f"); - test(fmt!("%.o", 10u), ~"12"); - test(fmt!("%.t", 3u), ~"11"); - test(fmt!("%.c", 'A'), ~"A"); - test(fmt!("%.f", 5.82), ~"6"); - test(fmt!("%.0d", 0), ~""); - test(fmt!("%.0u", 0u), ~""); - test(fmt!("%.0x", 0u), ~""); - test(fmt!("%.0t", 0u), ~""); - test(fmt!("%.0d", 10), ~"10"); - test(fmt!("%.0d", -10), ~"-10"); - test(fmt!("%.0u", 10u), ~"10"); - test(fmt!("%.0s", "test"), ~""); - test(fmt!("%.0x", 127u), ~"7f"); - test(fmt!("%.0o", 10u), ~"12"); - test(fmt!("%.0t", 3u), ~"11"); - test(fmt!("%.0c", 'A'), ~"A"); - test(fmt!("%.0f", 5.892), ~"6"); - test(fmt!("%.1d", 0), ~"0"); - test(fmt!("%.1u", 0u), ~"0"); - test(fmt!("%.1x", 0u), ~"0"); - test(fmt!("%.1t", 0u), ~"0"); - test(fmt!("%.1d", 10), ~"10"); - test(fmt!("%.1d", -10), ~"-10"); - test(fmt!("%.1u", 10u), ~"10"); - test(fmt!("%.1s", "test"), ~"t"); - test(fmt!("%.1x", 127u), ~"7f"); - test(fmt!("%.1o", 10u), ~"12"); - test(fmt!("%.1t", 3u), ~"11"); - test(fmt!("%.1c", 'A'), ~"A"); - test(fmt!("%.1f", 5.82), ~"5.8"); -} -fn part4() { - test(fmt!("%.5d", 0), ~"00000"); - test(fmt!("%.5u", 0u), ~"00000"); - test(fmt!("%.5x", 0u), ~"00000"); - test(fmt!("%.5t", 0u), ~"00000"); - test(fmt!("%.5d", 10), ~"00010"); - test(fmt!("%.5d", -10), ~"-00010"); - test(fmt!("%.5u", 10u), ~"00010"); - test(fmt!("%.5s", "test"), ~"test"); - test(fmt!("%.5x", 127u), ~"0007f"); - test(fmt!("%.5o", 10u), ~"00012"); - test(fmt!("%.5t", 3u), ~"00011"); - test(fmt!("%.5c", 'A'), ~"A"); - test(fmt!("%.5f", 5.82), ~"5.82000"); - test(fmt!("%.5f", 5.0), ~"5.00000"); - test(fmt!("%.100f", 1.1), ~"1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000"); - - // Bool precision. I'm not sure if it's good or bad to have bool - // conversions support precision - it's not standard printf so we - // can do whatever. For now I'm making it behave the same as string - // conversions. - - test(fmt!("%.b", true), ~""); - test(fmt!("%.0b", true), ~""); - test(fmt!("%.1b", true), ~"t"); -} - -fn part5() { - // Explicit + sign. Only for signed conversions - - test(fmt!("%+d", 0), ~"+0"); - test(fmt!("%+d", 1), ~"+1"); - test(fmt!("%+d", -1), ~"-1"); - test(fmt!("%+f", 0.0), ~"+0"); - // Leave space for sign - - test(fmt!("% d", 0), ~" 0"); - test(fmt!("% d", 1), ~" 1"); - test(fmt!("% d", -1), ~"-1"); - test(fmt!("% f", 0.0), ~" 0"); - // Plus overrides space - - test(fmt!("% +d", 0), ~"+0"); - test(fmt!("%+ d", 0), ~"+0"); - test(fmt!("% +f", 0.0), ~"+0"); - test(fmt!("%+ f", 0.0), ~"+0"); - // 0-padding - - test(fmt!("%05d", 0), ~"00000"); - test(fmt!("%05d", 1), ~"00001"); - test(fmt!("%05d", -1), ~"-0001"); - test(fmt!("%05u", 1u), ~"00001"); - test(fmt!("%05x", 127u), ~"0007f"); - test(fmt!("%05X", 127u), ~"0007F"); - test(fmt!("%05o", 10u), ~"00012"); - test(fmt!("%05t", 3u), ~"00011"); - test(fmt!("%05f", 5.82), ~"05.82"); - // 0-padding a string is undefined but glibc does this: - - test(fmt!("%05s", "test"), ~" test"); - test(fmt!("%05c", 'A'), ~" A"); - test(fmt!("%05b", true), ~" true"); - // Left-justify overrides 0-padding - - test(fmt!("%-05d", 0), ~"0 "); - test(fmt!("%-05d", 1), ~"1 "); - test(fmt!("%-05d", -1), ~"-1 "); - test(fmt!("%-05u", 1u), ~"1 "); - test(fmt!("%-05x", 127u), ~"7f "); - test(fmt!("%-05X", 127u), ~"7F "); - test(fmt!("%-05o", 10u), ~"12 "); - test(fmt!("%-05t", 3u), ~"11 "); - test(fmt!("%-05s", "test"), ~"test "); - test(fmt!("%-05c", 'A'), ~"A "); - test(fmt!("%-05b", true), ~"true "); - test(fmt!("%-05f", 5.82), ~"5.82 "); -} -fn part6() { - // Precision overrides 0-padding - // FIXME #2481: Recent gcc's report some of these as warnings - - test(fmt!("%06.5d", 0), ~" 00000"); - test(fmt!("%06.5u", 0u), ~" 00000"); - test(fmt!("%06.5x", 0u), ~" 00000"); - test(fmt!("%06.5d", 10), ~" 00010"); - test(fmt!("%06.5d", -10), ~"-00010"); - test(fmt!("%06.5u", 10u), ~" 00010"); - test(fmt!("%06.5s", "test"), ~" test"); - test(fmt!("%06.5c", 'A'), ~" A"); - test(fmt!("%06.5x", 127u), ~" 0007f"); - test(fmt!("%06.5X", 127u), ~" 0007F"); - test(fmt!("%06.5o", 10u), ~" 00012"); - - // Precision does not override zero-padding for floats - test(fmt!("%08.5f", 5.82), ~"05.82000"); - - // Signed combinations - - test(fmt!("% 5d", 1), ~" 1"); - test(fmt!("% 5d", -1), ~" -1"); - test(fmt!("%+5d", 1), ~" +1"); - test(fmt!("%+5d", -1), ~" -1"); - test(fmt!("% 05d", 1), ~" 0001"); - test(fmt!("% 05d", -1), ~"-0001"); - test(fmt!("%+05d", 1), ~"+0001"); - test(fmt!("%+05d", -1), ~"-0001"); - test(fmt!("%- 5d", 1), ~" 1 "); - test(fmt!("%- 5d", -1), ~"-1 "); - test(fmt!("%-+5d", 1), ~"+1 "); - test(fmt!("%-+5d", -1), ~"-1 "); - test(fmt!("%- 05d", 1), ~" 1 "); - test(fmt!("%- 05d", -1), ~"-1 "); - test(fmt!("%-+05d", 1), ~"+1 "); - test(fmt!("%-+05d", -1), ~"-1 "); -} - -fn percent() { - let s = fmt!("ab%%cd"); - assert_eq!(s, ~"ab%cd"); -} - -fn more_floats() { - assert_eq!(~"3.1416", fmt!("%.4f", 3.14159)); - assert_eq!(~"3", fmt!("%.0f", 3.14159)); - assert_eq!(~"99", fmt!("%.0f", 98.5)); - assert_eq!(~"7.0000", fmt!("%.4f", 6.999999999)); - assert_eq!(~"3.141590000", fmt!("%.9f", 3.14159)); -} - -fn pointer() { - do 10.times { - let x: uint = ::std::rand::random(); - assert_eq!(fmt!("%p", x as *uint), fmt!("0x%x", x)); - } - - let i = &1; - assert_eq!(fmt!("%p", i), fmt!("0x%x", i as *uint as uint)); -}