From 39207a358bdbaf3d4ba921c2b7cce786cf2c7cef Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Aug 2013 10:47:38 -0700 Subject: [PATCH 1/4] Remove ifmt hax and implement fprintf --- src/libstd/fmt/mod.rs | 56 ++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index db8a17c0bd0..03204fd30ea 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -399,6 +399,43 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); } #[allow(missing_doc)] pub trait Float { fn fmt(&Self, &mut Formatter); } +/// The fprintf function takes an output stream, a precompiled format string, +/// and a list of arguments. The arguments will be formatted according to the +/// specified format string into the output stream provided. +/// +/// See the documentation for `sprintf` for why this function is unsafe and care +/// should be taken if calling it manually. +/// +/// Thankfully the rust compiler provides the macro `fmtf!` which will perform +/// all of this validation at compile-time and provides a safe interface for +/// invoking this function. +/// +/// # Arguments +/// +/// * output - the buffer to write output to +/// * fmts - the precompiled format string to emit +/// * args - the list of arguments to the format string. These are only the +/// positional arguments (not named) +/// +/// Note that this function assumes that there are enough arguments for the +/// format string. +pub unsafe fn fprintf(output: &mut io::Writer, + fmt: &[rt::Piece], args: &[Argument]) { + let mut formatter = Formatter { + flags: 0, + width: None, + precision: None, + buf: output, + align: parse::AlignUnknown, + fill: ' ', + args: args, + curarg: args.iter(), + }; + for piece in fmt.iter() { + formatter.run(piece, None); + } +} + /// The sprintf function takes a precompiled format string and a list of /// arguments, to return the resulting formatted string. /// @@ -422,23 +459,8 @@ pub trait Float { fn fmt(&Self, &mut Formatter); } /// Note that this function assumes that there are enough arguments for the /// format string. pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str { - let output = MemWriter::new(); - { - let mut formatter = Formatter { - flags: 0, - width: None, - precision: None, - // FIXME(#8248): shouldn't need a transmute - buf: cast::transmute(&output as &io::Writer), - align: parse::AlignUnknown, - fill: ' ', - args: args, - curarg: args.iter(), - }; - for piece in fmt.iter() { - formatter.run(piece, None); - } - } + let mut output = MemWriter::new(); + fprintf(&mut output as &mut io::Writer, fmt, args); return str::from_bytes_owned(output.inner()); } From 67512f717e7592d347fc825d2917b786a19b78bd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 20 Aug 2013 00:40:27 -0700 Subject: [PATCH 2/4] Implement a wrapper macro around fprintf -- ifmtf --- src/libsyntax/ext/base.rs | 4 ++- src/libsyntax/ext/ifmt.rs | 68 +++++++++++++++++++++++++++------------ src/test/run-pass/ifmt.rs | 22 ++++++++++++- 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dfaffa0c275..560cb26d09a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -140,7 +140,9 @@ pub fn syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt(ext::fmt::expand_syntax_ext)); syntax_expanders.insert(intern(&"ifmt"), - builtin_normal_tt(ext::ifmt::expand_syntax_ext)); + builtin_normal_tt(ext::ifmt::expand_sprintf)); + syntax_expanders.insert(intern(&"ifmtf"), + builtin_normal_tt(ext::ifmt::expand_fprintf)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index 35be77b95c5..ae098735e5b 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -54,20 +54,32 @@ impl Context { /// Parses the arguments from the given list of tokens, returning None if /// there's a parse error so we can continue parsing other fmt! expressions. fn parse_args(&mut self, sp: span, - tts: &[ast::token_tree]) -> Option<@ast::expr> { + leading_expr: bool, + tts: &[ast::token_tree]) -> (Option<@ast::expr>, + Option<@ast::expr>) { let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(), self.ecx.cfg(), tts.to_owned()); + // If we want a leading expression (for ifmtf), parse it here + let extra = if leading_expr { + let e = Some(p.parse_expr()); + if !p.eat(&token::COMMA) { + self.ecx.span_err(sp, "expected token: `,`"); + return (e, None); + } + e + } else { None }; + if *p.token == token::EOF { - self.ecx.span_err(sp, "ifmt! expects at least one argument"); - return None; + self.ecx.span_err(sp, "requires at least a format string argument"); + return (extra, None); } let fmtstr = p.parse_expr(); let mut named = false; while *p.token != token::EOF { if !p.eat(&token::COMMA) { self.ecx.span_err(sp, "expected token: `,`"); - return None; + return (extra, None); } if named || (token::is_ident(p.token) && p.look_ahead(1, |t| *t == token::EQ)) { @@ -81,14 +93,14 @@ impl Context { self.ecx.span_err(*p.span, "expected ident, positional arguments \ cannot follow named arguments"); - return None; + return (extra, None); } _ => { self.ecx.span_err(*p.span, fmt!("expected ident for named \ argument, but found `%s`", p.this_token_to_str())); - return None; + return (extra, None); } }; let name = self.ecx.str_of(ident); @@ -110,7 +122,7 @@ impl Context { self.arg_types.push(None); } } - return Some(fmtstr); + return (extra, Some(fmtstr)); } /// Verifies one piece of a parse string. All errors are not emitted as @@ -530,7 +542,7 @@ impl Context { /// Actually builds the expression which the ifmt! block will be expanded /// to - fn to_expr(&self) -> @ast::expr { + fn to_expr(&self, extra: Option<@ast::expr>, f: &str) -> @ast::expr { let mut lets = ~[]; let mut locals = ~[]; let mut names = vec::from_fn(self.name_positions.len(), |_| None); @@ -596,15 +608,18 @@ impl Context { let args = names.move_iter().map(|a| a.unwrap()); let mut args = locals.move_iter().chain(args); - // Next, build up the actual call to the sprintf function. + let mut fmt_args = match extra { + Some(e) => ~[e], None => ~[] + }; + fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name)); + fmt_args.push(self.ecx.expr_vec(self.fmtsp, args.collect())); + + // Next, build up the actual call to the {s,f}printf function. let result = self.ecx.expr_call_global(self.fmtsp, ~[ self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), - self.ecx.ident_of("sprintf"), - ], ~[ - self.ecx.expr_ident(self.fmtsp, static_name), - self.ecx.expr_vec(self.fmtsp, args.collect()), - ]); + self.ecx.ident_of(f), + ], fmt_args); // sprintf is unsafe, but we just went through a lot of work to // validate that our call is save, so inject the unsafe block for the @@ -682,8 +697,19 @@ impl Context { } } -pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, - tts: &[ast::token_tree]) -> base::MacResult { +pub fn expand_sprintf(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, false, "sprintf") +} + +pub fn expand_fprintf(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, true, "fprintf") +} + + +fn expand_ifmt(ecx: @ExtCtxt, sp: span, tts: &[ast::token_tree], + leading_arg: bool, function: &str) -> base::MacResult { let mut cx = Context { ecx: ecx, args: ~[], @@ -697,13 +723,13 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, method_statics: ~[], fmtsp: sp, }; - let efmt = match cx.parse_args(sp, tts) { - Some(e) => e, - None => { return MRExpr(ecx.expr_uint(sp, 2)); } + let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) { + (extra, Some(e)) => (extra, e), + (_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); } }; cx.fmtsp = efmt.span; let fmt = expr_to_str(ecx, efmt, - "first argument to ifmt! must be a string literal."); + "format argument must be a string literal."); let mut err = false; do parse::parse_error::cond.trap(|m| { @@ -734,5 +760,5 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, } } - MRExpr(cx.to_expr()) + MRExpr(cx.to_expr(extra, function)) } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index cba28463f99..b5341ca80c5 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -21,8 +21,9 @@ impl fmt::Signed for B { fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); } } +macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) }) + pub fn main() { - macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) }) // Make sure there's a poly formatter that takes anything t!(ifmt!("{:?}", 1), "1"); @@ -209,5 +210,24 @@ pub fn main() { t!(ifmt!("{:10.3f}", 1.0f), " 1.000"); t!(ifmt!("{:+10.3f}", 1.0f), " +1.000"); t!(ifmt!("{:+10.3f}", -1.0f), " -1.000"); + + test_ifmtf(); } +fn test_ifmtf() { + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; + use std::rt::io; + use std::str; + + let mut buf = MemWriter::new(); + ifmtf!(&mut buf as &mut io::Writer, "{}", 3); + { + let w = &mut buf as &mut io::Writer; + ifmtf!(w, "{foo}", foo=4); + ifmtf!(w, "{:s}", "hello"); + } + + let s = str::from_bytes_owned(buf.inner()); + t!(s, "34hello"); +} From eb836dd61ed2d780ca9639f73876c3d3e05ef079 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 Aug 2013 18:14:11 -0700 Subject: [PATCH 3/4] Settle on the format/write/print family of names --- src/libstd/fmt/mod.rs | 52 +-- src/libsyntax/ext/base.rs | 10 +- src/libsyntax/ext/expand.rs | 17 + src/libsyntax/ext/ifmt.rs | 20 +- src/test/compile-fail/ifmt-bad-arg.rs | 86 ++--- src/test/compile-fail/ifmt-bad-plural.rs | 2 +- src/test/compile-fail/ifmt-bad-select.rs | 2 +- src/test/compile-fail/ifmt-unimpl.rs | 2 +- src/test/compile-fail/ifmt-unknown-trait.rs | 2 +- src/test/run-pass/ifmt.rs | 353 ++++++++++---------- 10 files changed, 293 insertions(+), 253 deletions(-) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index 03204fd30ea..daf8c4afb07 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -12,33 +12,33 @@ # The Formatting Module -This module contains the runtime support for the `ifmt!` syntax extension. This +This module contains the runtime support for the `format!` syntax extension. This macro is implemented in the compiler to emit calls to this module in order to format arguments at runtime into strings and streams. The functions contained in this module should not normally be used in everyday -use cases of `ifmt!`. The assumptions made by these functions are unsafe for all +use cases of `format!`. The assumptions made by these functions are unsafe for all inputs, and the compiler performs a large amount of validation on the arguments -to `ifmt!` in order to ensure safety at runtime. While it is possible to call +to `format!` in order to ensure safety at runtime. While it is possible to call these functions directly, it is not recommended to do so in the general case. ## Usage -The `ifmt!` macro is intended to be familiar to those coming from C's -printf/sprintf functions or Python's `str.format` function. In its current -revision, the `ifmt!` macro returns a `~str` type which is the result of the +The `format!` macro is intended to be familiar to those coming from C's +printf/fprintf functions or Python's `str.format` function. In its current +revision, the `format!` macro returns a `~str` type which is the result of the formatting. In the future it will also be able to pass in a stream to format arguments directly while performing minimal allocations. -Some examples of the `ifmt!` extension are: +Some examples of the `format!` extension are: ~~~{.rust} -ifmt!("Hello") // => ~"Hello" -ifmt!("Hello, {:s}!", "world") // => ~"Hello, world!" -ifmt!("The number is {:d}", 1) // => ~"The number is 1" -ifmt!("{}", ~[3, 4]) // => ~"~[3, 4]" -ifmt!("{value}", value=4) // => ~"4" -ifmt!("{} {}", 1, 2) // => ~"1 2" +format!("Hello") // => ~"Hello" +format!("Hello, {:s}!", "world") // => ~"Hello, world!" +format!("The number is {:d}", 1) // => ~"The number is 1" +format!("{}", ~[3, 4]) // => ~"~[3, 4]" +format!("{value}", value=4) // => ~"4" +format!("{} {}", 1, 2) // => ~"1 2" ~~~ From these, you can see that the first argument is a format string. It is @@ -62,7 +62,7 @@ format string, although it must always be referred to with the same type. ### Named parameters Rust itself does not have a Python-like equivalent of named parameters to a -function, but the `ifmt!` macro is a syntax extension which allows it to +function, but the `format!` macro is a syntax extension which allows it to leverage named parameters. Named parameters are listed at the end of the argument list and have the syntax: @@ -146,7 +146,7 @@ helper methods. ## Internationalization -The formatting syntax supported by the `ifmt!` extension supports +The formatting syntax supported by the `format!` extension supports internationalization by providing "methods" which execute various different outputs depending on the input. The syntax and methods provided are similar to other internationalization systems, so again nothing should seem alien. @@ -164,7 +164,7 @@ to reference the string value of the argument which was selected upon. As an example: ~~~ -ifmt!("{0, select, other{#}}", "hello") // => ~"hello" +format!("{0, select, other{#}}", "hello") // => ~"hello" ~~~ This example is the equivalent of `{0:s}` essentially. @@ -399,11 +399,11 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); } #[allow(missing_doc)] pub trait Float { fn fmt(&Self, &mut Formatter); } -/// The fprintf function takes an output stream, a precompiled format string, +/// The `write` function takes an output stream, a precompiled format string, /// and a list of arguments. The arguments will be formatted according to the /// specified format string into the output stream provided. /// -/// See the documentation for `sprintf` for why this function is unsafe and care +/// See the documentation for `format` for why this function is unsafe and care /// should be taken if calling it manually. /// /// Thankfully the rust compiler provides the macro `fmtf!` which will perform @@ -419,8 +419,8 @@ pub trait Float { fn fmt(&Self, &mut Formatter); } /// /// Note that this function assumes that there are enough arguments for the /// format string. -pub unsafe fn fprintf(output: &mut io::Writer, - fmt: &[rt::Piece], args: &[Argument]) { +pub unsafe fn write(output: &mut io::Writer, + fmt: &[rt::Piece], args: &[Argument]) { let mut formatter = Formatter { flags: 0, width: None, @@ -436,7 +436,7 @@ pub unsafe fn fprintf(output: &mut io::Writer, } } -/// The sprintf function takes a precompiled format string and a list of +/// The format function takes a precompiled format string and a list of /// arguments, to return the resulting formatted string. /// /// This is currently an unsafe function because the types of all arguments @@ -446,7 +446,7 @@ pub unsafe fn fprintf(output: &mut io::Writer, /// for formatting the right type value. Because of this, the function is marked /// as `unsafe` if this is being called manually. /// -/// Thankfully the rust compiler provides the macro `ifmt!` which will perform +/// Thankfully the rust compiler provides the macro `format!` which will perform /// all of this validation at compile-time and provides a safe interface for /// invoking this function. /// @@ -458,9 +458,9 @@ pub unsafe fn fprintf(output: &mut io::Writer, /// /// Note that this function assumes that there are enough arguments for the /// format string. -pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str { +pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str { let mut output = MemWriter::new(); - fprintf(&mut output as &mut io::Writer, fmt, args); + write(&mut output as &mut io::Writer, fmt, args); return str::from_bytes_owned(output.inner()); } @@ -468,7 +468,7 @@ impl<'self> Formatter<'self> { // First up is the collection of functions used to execute a format string // at runtime. This consumes all of the compile-time statics generated by - // the ifmt! syntax extension. + // the format! syntax extension. fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) { let setcount = |slot: &mut Option, cnt: &parse::Count| { @@ -732,7 +732,7 @@ impl<'self> Formatter<'self> { } /// This is a function which calls are emitted to by the compiler itself to -/// create the Argument structures that are passed into the `sprintf` function. +/// create the Argument structures that are passed into the `format` function. #[doc(hidden)] pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter), t: &'a T) -> Argument<'a> { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 560cb26d09a..6f9585652bd 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -139,10 +139,12 @@ pub fn syntax_expander_table() -> SyntaxEnv { ext::tt::macro_rules::add_new_extension)); syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt(ext::fmt::expand_syntax_ext)); - syntax_expanders.insert(intern(&"ifmt"), - builtin_normal_tt(ext::ifmt::expand_sprintf)); - syntax_expanders.insert(intern(&"ifmtf"), - builtin_normal_tt(ext::ifmt::expand_fprintf)); + syntax_expanders.insert(intern(&"format"), + builtin_normal_tt(ext::ifmt::expand_format)); + syntax_expanders.insert(intern(&"write"), + builtin_normal_tt(ext::ifmt::expand_write)); + syntax_expanders.insert(intern(&"writeln"), + builtin_normal_tt(ext::ifmt::expand_writeln)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4bea1dc23e7..49b8c994dc2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -940,6 +940,7 @@ pub fn std_macros() -> @str { ); ) + // NOTE(acrichto): start removing this after the next snapshot macro_rules! printf ( ($arg:expr) => ( print(fmt!(\"%?\", $arg)) @@ -949,6 +950,7 @@ pub fn std_macros() -> @str { ) ) + // NOTE(acrichto): start removing this after the next snapshot macro_rules! printfln ( ($arg:expr) => ( println(fmt!(\"%?\", $arg)) @@ -958,6 +960,21 @@ pub fn std_macros() -> @str { ) ) + // FIXME(#6846) once stdio is redesigned, this shouldn't perform an + // allocation but should rather delegate to an invocation of + // write! instead of format! + macro_rules! print ( + () => (); + ($arg:expr) => ( ::std::io::print(format!(\"{}\", $arg))); + ($fmt:expr, $($arg:tt)+) => ( ::std::io::print(format!($fmt, $($arg)+))) + ) + + // FIXME(#6846) once stdio is redesigned, this shouldn't perform an + // allocation but should rather delegate to an io::Writer + macro_rules! println ( + ($($arg:tt)*) => ({ print!($($arg)*); ::std::io::println(\"\"); }) + ) + // NOTE: use this after a snapshot lands to abstract the details // of the TLS interface. macro_rules! local_data_key ( diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index ae098735e5b..d4274746a4e 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -697,19 +697,24 @@ impl Context { } } -pub fn expand_sprintf(ecx: @ExtCtxt, sp: span, - tts: &[ast::token_tree]) -> base::MacResult { - expand_ifmt(ecx, sp, tts, false, "sprintf") +pub fn expand_format(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, false, false, "format") } -pub fn expand_fprintf(ecx: @ExtCtxt, sp: span, - tts: &[ast::token_tree]) -> base::MacResult { - expand_ifmt(ecx, sp, tts, true, "fprintf") +pub fn expand_write(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, true, false, "write") } +pub fn expand_writeln(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, true, true, "write") +} fn expand_ifmt(ecx: @ExtCtxt, sp: span, tts: &[ast::token_tree], - leading_arg: bool, function: &str) -> base::MacResult { + leading_arg: bool, append_newline: bool, + function: &str) -> base::MacResult { let mut cx = Context { ecx: ecx, args: ~[], @@ -730,6 +735,7 @@ fn expand_ifmt(ecx: @ExtCtxt, sp: span, tts: &[ast::token_tree], cx.fmtsp = efmt.span; let fmt = expr_to_str(ecx, efmt, "format argument must be a string literal."); + let fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() }; let mut err = false; do parse::parse_error::cond.trap(|m| { diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 875ad0d2b62..273394794a9 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -9,66 +9,66 @@ // except according to those terms. fn main() { - // bad arguments to the ifmt! call + // bad arguments to the format! call - ifmt!(); //~ ERROR: expects at least one - ifmt!("{}"); //~ ERROR: invalid reference to argument + format!(); //~ ERROR: requires at least a format string + format!("{}"); //~ ERROR: invalid reference to argument - ifmt!("{1}", 1); //~ ERROR: invalid reference to argument `1` + format!("{1}", 1); //~ ERROR: invalid reference to argument `1` //~^ ERROR: argument never used - ifmt!("{foo}"); //~ ERROR: no argument named `foo` + format!("{foo}"); //~ ERROR: no argument named `foo` - ifmt!("{}", 1, 2); //~ ERROR: argument never used - ifmt!("{1}", 1, 2); //~ ERROR: argument never used - ifmt!("{}", 1, foo=2); //~ ERROR: named argument never used - ifmt!("{foo}", 1, foo=2); //~ ERROR: argument never used - ifmt!("", foo=2); //~ ERROR: named argument never used + format!("{}", 1, 2); //~ ERROR: argument never used + format!("{1}", 1, 2); //~ ERROR: argument never used + format!("{}", 1, foo=2); //~ ERROR: named argument never used + format!("{foo}", 1, foo=2); //~ ERROR: argument never used + format!("", foo=2); //~ ERROR: named argument never used - ifmt!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` - ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` + format!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` + format!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` - ifmt!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument - ifmt!("#"); //~ ERROR: `#` reference used - ifmt!("", foo=1, 2); //~ ERROR: positional arguments cannot follow - ifmt!("" 1); //~ ERROR: expected token: `,` - ifmt!("", 1 1); //~ ERROR: expected token: `,` + format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument + format!("#"); //~ ERROR: `#` reference used + format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow + format!("" 1); //~ ERROR: expected token: `,` + format!("", 1 1); //~ ERROR: expected token: `,` - ifmt!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector - ifmt!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector - ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector + format!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector + format!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector + format!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector // bad syntax of the format string - ifmt!("{"); //~ ERROR: unterminated format string - ifmt!("\\ "); //~ ERROR: invalid escape - ifmt!("\\"); //~ ERROR: expected an escape + format!("{"); //~ ERROR: unterminated format string + format!("\\ "); //~ ERROR: invalid escape + format!("\\"); //~ ERROR: expected an escape - ifmt!("{0, }", 1); //~ ERROR: expected method - ifmt!("{0, foo}", 1); //~ ERROR: unknown method - ifmt!("{0, select}", "a"); //~ ERROR: must be followed by - ifmt!("{0, plural}", 1); //~ ERROR: must be followed by + format!("{0, }", 1); //~ ERROR: expected method + format!("{0, foo}", 1); //~ ERROR: unknown method + format!("{0, select}", "a"); //~ ERROR: must be followed by + format!("{0, plural}", 1); //~ ERROR: must be followed by - ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated - ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector - ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other` - ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer - ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:` - ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer - ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural - ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other` - ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other` + format!("{0, select, a{{}", 1); //~ ERROR: must be terminated + format!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector + format!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other` + format!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer + format!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:` + format!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer + format!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural + format!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other` + format!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other` - ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as - ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to - ifmt!("{0, select, other{}} \ - {0, plural, other{}}", "a"); + format!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as + format!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to + format!("{0, select, other{}} \ + {0, plural, other{}}", "a"); //~^ ERROR: declared with multiple formats // It should be illegal to use implicit placement arguments nested inside of // format strings because otherwise the "internal pointer of which argument // is next" would be invalidated if different cases had different numbers of // arguments. - ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit - ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit - ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit + format!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit + format!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit + format!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit } diff --git a/src/test/compile-fail/ifmt-bad-plural.rs b/src/test/compile-fail/ifmt-bad-plural.rs index 76a697b174f..21c2d4b5934 100644 --- a/src/test/compile-fail/ifmt-bad-plural.rs +++ b/src/test/compile-fail/ifmt-bad-plural.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - ifmt!("{0, plural, other{}}", "a"); + format!("{0, plural, other{}}", "a"); //~^ ERROR: expected uint but found } diff --git a/src/test/compile-fail/ifmt-bad-select.rs b/src/test/compile-fail/ifmt-bad-select.rs index abe3b6ed65a..8a72b7920d7 100644 --- a/src/test/compile-fail/ifmt-bad-select.rs +++ b/src/test/compile-fail/ifmt-bad-select.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - ifmt!("{0, select, other{}}", 2); + format!("{0, select, other{}}", 2); //~^ ERROR: expected &str but found integral } diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs index 427f5ea562c..830b041bbc7 100644 --- a/src/test/compile-fail/ifmt-unimpl.rs +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - ifmt!("{:d}", "3"); + format!("{:d}", "3"); //~^ ERROR: failed to find an implementation of trait std::fmt::Signed } diff --git a/src/test/compile-fail/ifmt-unknown-trait.rs b/src/test/compile-fail/ifmt-unknown-trait.rs index 85556f9501a..d90b3d3cf81 100644 --- a/src/test/compile-fail/ifmt-unknown-trait.rs +++ b/src/test/compile-fail/ifmt-unknown-trait.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - ifmt!("{:notimplemented}", "3"); + format!("{:notimplemented}", "3"); //~^ ERROR: unknown format trait `notimplemented` } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index b5341ca80c5..e067e16f54b 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -26,208 +26,223 @@ macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) }) pub fn main() { // Make sure there's a poly formatter that takes anything - t!(ifmt!("{:?}", 1), "1"); - t!(ifmt!("{:?}", A), "{}"); - t!(ifmt!("{:?}", ()), "()"); - t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")"); + t!(format!("{:?}", 1), "1"); + t!(format!("{:?}", A), "{}"); + t!(format!("{:?}", ()), "()"); + t!(format!("{:?}", @(~1, "foo")), "@(~1, \"foo\")"); // Various edge cases without formats - t!(ifmt!(""), ""); - t!(ifmt!("hello"), "hello"); - t!(ifmt!("hello \\{"), "hello {"); + t!(format!(""), ""); + t!(format!("hello"), "hello"); + t!(format!("hello \\{"), "hello {"); // default formatters should work - t!(ifmt!("{}", 1i), "1"); - t!(ifmt!("{}", 1i8), "1"); - t!(ifmt!("{}", 1i16), "1"); - t!(ifmt!("{}", 1i32), "1"); - t!(ifmt!("{}", 1i64), "1"); - t!(ifmt!("{}", 1u), "1"); - t!(ifmt!("{}", 1u8), "1"); - t!(ifmt!("{}", 1u16), "1"); - t!(ifmt!("{}", 1u32), "1"); - t!(ifmt!("{}", 1u64), "1"); - t!(ifmt!("{}", 1.0f), "1"); - t!(ifmt!("{}", 1.0f32), "1"); - t!(ifmt!("{}", 1.0f64), "1"); - t!(ifmt!("{}", "a"), "a"); - t!(ifmt!("{}", ~"a"), "a"); - t!(ifmt!("{}", @"a"), "a"); - t!(ifmt!("{}", false), "false"); - t!(ifmt!("{}", 'a'), "a"); + t!(format!("{}", 1i), "1"); + t!(format!("{}", 1i8), "1"); + t!(format!("{}", 1i16), "1"); + t!(format!("{}", 1i32), "1"); + t!(format!("{}", 1i64), "1"); + t!(format!("{}", 1u), "1"); + t!(format!("{}", 1u8), "1"); + t!(format!("{}", 1u16), "1"); + t!(format!("{}", 1u32), "1"); + t!(format!("{}", 1u64), "1"); + t!(format!("{}", 1.0f), "1"); + t!(format!("{}", 1.0f32), "1"); + t!(format!("{}", 1.0f64), "1"); + t!(format!("{}", "a"), "a"); + t!(format!("{}", ~"a"), "a"); + t!(format!("{}", @"a"), "a"); + t!(format!("{}", false), "false"); + t!(format!("{}", 'a'), "a"); // At least exercise all the formats - t!(ifmt!("{:b}", true), "true"); - t!(ifmt!("{:c}", '☃'), "☃"); - t!(ifmt!("{:d}", 10), "10"); - t!(ifmt!("{:i}", 10), "10"); - t!(ifmt!("{:u}", 10u), "10"); - t!(ifmt!("{:o}", 10u), "12"); - t!(ifmt!("{:x}", 10u), "a"); - t!(ifmt!("{:X}", 10u), "A"); - t!(ifmt!("{:s}", "foo"), "foo"); - t!(ifmt!("{:s}", ~"foo"), "foo"); - t!(ifmt!("{:s}", @"foo"), "foo"); - t!(ifmt!("{:p}", 0x1234 as *int), "0x1234"); - t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234"); - t!(ifmt!("{:d}", A), "aloha"); - t!(ifmt!("{:d}", B), "adios"); - t!(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); - t!(ifmt!("{1} {0}", 0, 1), "1 0"); - t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1"); - t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); - t!(ifmt!("{} {0:s}", "a"), "a a"); - t!(ifmt!("{} {0}", "a"), "a a"); + t!(format!("{:b}", true), "true"); + t!(format!("{:c}", '☃'), "☃"); + t!(format!("{:d}", 10), "10"); + t!(format!("{:i}", 10), "10"); + t!(format!("{:u}", 10u), "10"); + t!(format!("{:o}", 10u), "12"); + t!(format!("{:x}", 10u), "a"); + t!(format!("{:X}", 10u), "A"); + t!(format!("{:s}", "foo"), "foo"); + t!(format!("{:s}", ~"foo"), "foo"); + t!(format!("{:s}", @"foo"), "foo"); + t!(format!("{:p}", 0x1234 as *int), "0x1234"); + t!(format!("{:p}", 0x1234 as *mut int), "0x1234"); + t!(format!("{:d}", A), "aloha"); + t!(format!("{:d}", B), "adios"); + t!(format!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{1} {0}", 0, 1), "1 0"); + t!(format!("{foo} {bar}", foo=0, bar=1), "0 1"); + t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); + t!(format!("{} {0:s}", "a"), "a a"); + t!(format!("{} {0}", "a"), "a a"); // Methods should probably work - t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0"); - t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1"); - t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2"); - t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3"); - t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa"); - t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb"); - t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc"); - t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd"); - t!(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab"); - t!(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb"); + t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0"); + t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1"); + t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2"); + t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3"); + t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa"); + t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb"); + t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc"); + t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd"); + t!(format!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab"); + t!(format!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb"); // Formatting strings and their arguments - t!(ifmt!("{:s}", "a"), "a"); - t!(ifmt!("{:4s}", "a"), "a "); - t!(ifmt!("{:>4s}", "a"), " a"); - t!(ifmt!("{:<4s}", "a"), "a "); - t!(ifmt!("{:.4s}", "a"), "a"); - t!(ifmt!("{:4.4s}", "a"), "a "); - t!(ifmt!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(ifmt!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(ifmt!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(ifmt!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(ifmt!("{:2.4s}", "aaaaa"), "aaaa"); - t!(ifmt!("{:2.4s}", "aaaa"), "aaaa"); - t!(ifmt!("{:2.4s}", "aaa"), "aaa"); - t!(ifmt!("{:2.4s}", "aa"), "aa"); - t!(ifmt!("{:2.4s}", "a"), "a "); - t!(ifmt!("{:0>2s}", "a"), "0a"); - t!(ifmt!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(ifmt!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(ifmt!("{:1$s}", "a", 4), "a "); - t!(ifmt!("{:-#s}", "a"), "a"); - t!(ifmt!("{:+#s}", "a"), "a"); + t!(format!("{:s}", "a"), "a"); + t!(format!("{:4s}", "a"), "a "); + t!(format!("{:>4s}", "a"), " a"); + t!(format!("{:<4s}", "a"), "a "); + t!(format!("{:.4s}", "a"), "a"); + t!(format!("{:4.4s}", "a"), "a "); + t!(format!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:2.4s}", "aaaaa"), "aaaa"); + t!(format!("{:2.4s}", "aaaa"), "aaaa"); + t!(format!("{:2.4s}", "aaa"), "aaa"); + t!(format!("{:2.4s}", "aa"), "aa"); + t!(format!("{:2.4s}", "a"), "a "); + t!(format!("{:0>2s}", "a"), "0a"); + t!(format!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:1$s}", "a", 4), "a "); + t!(format!("{:-#s}", "a"), "a"); + t!(format!("{:+#s}", "a"), "a"); // Formatting integers should select the right implementation based off the // type of the argument. Also, hex/octal/binary should be defined for // integers, but they shouldn't emit the negative sign. - t!(ifmt!("{:d}", -1i), "-1"); - t!(ifmt!("{:d}", -1i8), "-1"); - t!(ifmt!("{:d}", -1i16), "-1"); - t!(ifmt!("{:d}", -1i32), "-1"); - t!(ifmt!("{:d}", -1i64), "-1"); - t!(ifmt!("{:t}", 1i), "1"); - t!(ifmt!("{:t}", 1i8), "1"); - t!(ifmt!("{:t}", 1i16), "1"); - t!(ifmt!("{:t}", 1i32), "1"); - t!(ifmt!("{:t}", 1i64), "1"); - t!(ifmt!("{:x}", 1i), "1"); - t!(ifmt!("{:x}", 1i8), "1"); - t!(ifmt!("{:x}", 1i16), "1"); - t!(ifmt!("{:x}", 1i32), "1"); - t!(ifmt!("{:x}", 1i64), "1"); - t!(ifmt!("{:X}", 1i), "1"); - t!(ifmt!("{:X}", 1i8), "1"); - t!(ifmt!("{:X}", 1i16), "1"); - t!(ifmt!("{:X}", 1i32), "1"); - t!(ifmt!("{:X}", 1i64), "1"); - t!(ifmt!("{:o}", 1i), "1"); - t!(ifmt!("{:o}", 1i8), "1"); - t!(ifmt!("{:o}", 1i16), "1"); - t!(ifmt!("{:o}", 1i32), "1"); - t!(ifmt!("{:o}", 1i64), "1"); + t!(format!("{:d}", -1i), "-1"); + t!(format!("{:d}", -1i8), "-1"); + t!(format!("{:d}", -1i16), "-1"); + t!(format!("{:d}", -1i32), "-1"); + t!(format!("{:d}", -1i64), "-1"); + t!(format!("{:t}", 1i), "1"); + t!(format!("{:t}", 1i8), "1"); + t!(format!("{:t}", 1i16), "1"); + t!(format!("{:t}", 1i32), "1"); + t!(format!("{:t}", 1i64), "1"); + t!(format!("{:x}", 1i), "1"); + t!(format!("{:x}", 1i8), "1"); + t!(format!("{:x}", 1i16), "1"); + t!(format!("{:x}", 1i32), "1"); + t!(format!("{:x}", 1i64), "1"); + t!(format!("{:X}", 1i), "1"); + t!(format!("{:X}", 1i8), "1"); + t!(format!("{:X}", 1i16), "1"); + t!(format!("{:X}", 1i32), "1"); + t!(format!("{:X}", 1i64), "1"); + t!(format!("{:o}", 1i), "1"); + t!(format!("{:o}", 1i8), "1"); + t!(format!("{:o}", 1i16), "1"); + t!(format!("{:o}", 1i32), "1"); + t!(format!("{:o}", 1i64), "1"); - t!(ifmt!("{:u}", 1u), "1"); - t!(ifmt!("{:u}", 1u8), "1"); - t!(ifmt!("{:u}", 1u16), "1"); - t!(ifmt!("{:u}", 1u32), "1"); - t!(ifmt!("{:u}", 1u64), "1"); - t!(ifmt!("{:t}", 1u), "1"); - t!(ifmt!("{:t}", 1u8), "1"); - t!(ifmt!("{:t}", 1u16), "1"); - t!(ifmt!("{:t}", 1u32), "1"); - t!(ifmt!("{:t}", 1u64), "1"); - t!(ifmt!("{:x}", 1u), "1"); - t!(ifmt!("{:x}", 1u8), "1"); - t!(ifmt!("{:x}", 1u16), "1"); - t!(ifmt!("{:x}", 1u32), "1"); - t!(ifmt!("{:x}", 1u64), "1"); - t!(ifmt!("{:X}", 1u), "1"); - t!(ifmt!("{:X}", 1u8), "1"); - t!(ifmt!("{:X}", 1u16), "1"); - t!(ifmt!("{:X}", 1u32), "1"); - t!(ifmt!("{:X}", 1u64), "1"); - t!(ifmt!("{:o}", 1u), "1"); - t!(ifmt!("{:o}", 1u8), "1"); - t!(ifmt!("{:o}", 1u16), "1"); - t!(ifmt!("{:o}", 1u32), "1"); - t!(ifmt!("{:o}", 1u64), "1"); + t!(format!("{:u}", 1u), "1"); + t!(format!("{:u}", 1u8), "1"); + t!(format!("{:u}", 1u16), "1"); + t!(format!("{:u}", 1u32), "1"); + t!(format!("{:u}", 1u64), "1"); + t!(format!("{:t}", 1u), "1"); + t!(format!("{:t}", 1u8), "1"); + t!(format!("{:t}", 1u16), "1"); + t!(format!("{:t}", 1u32), "1"); + t!(format!("{:t}", 1u64), "1"); + t!(format!("{:x}", 1u), "1"); + t!(format!("{:x}", 1u8), "1"); + t!(format!("{:x}", 1u16), "1"); + t!(format!("{:x}", 1u32), "1"); + t!(format!("{:x}", 1u64), "1"); + t!(format!("{:X}", 1u), "1"); + t!(format!("{:X}", 1u8), "1"); + t!(format!("{:X}", 1u16), "1"); + t!(format!("{:X}", 1u32), "1"); + t!(format!("{:X}", 1u64), "1"); + t!(format!("{:o}", 1u), "1"); + t!(format!("{:o}", 1u8), "1"); + t!(format!("{:o}", 1u16), "1"); + t!(format!("{:o}", 1u32), "1"); + t!(format!("{:o}", 1u64), "1"); // Test the flags for formatting integers - t!(ifmt!("{:3d}", 1), " 1"); - t!(ifmt!("{:>3d}", 1), " 1"); - t!(ifmt!("{:>+3d}", 1), " +1"); - t!(ifmt!("{:<3d}", 1), "1 "); - t!(ifmt!("{:#d}", 1), "1"); - t!(ifmt!("{:#x}", 10), "0xa"); - t!(ifmt!("{:#X}", 10), "0xA"); - t!(ifmt!("{:#5x}", 10), " 0xa"); - t!(ifmt!("{:#o}", 10), "0o12"); - t!(ifmt!("{:08x}", 10), "0000000a"); - t!(ifmt!("{:8x}", 10), " a"); - t!(ifmt!("{:<8x}", 10), "a "); - t!(ifmt!("{:>8x}", 10), " a"); - t!(ifmt!("{:#08x}", 10), "0x00000a"); - t!(ifmt!("{:08d}", -10), "-0000010"); - t!(ifmt!("{:x}", -1u8), "ff"); - t!(ifmt!("{:X}", -1u8), "FF"); - t!(ifmt!("{:t}", -1u8), "11111111"); - t!(ifmt!("{:o}", -1u8), "377"); - t!(ifmt!("{:#x}", -1u8), "0xff"); - t!(ifmt!("{:#X}", -1u8), "0xFF"); - t!(ifmt!("{:#t}", -1u8), "0b11111111"); - t!(ifmt!("{:#o}", -1u8), "0o377"); + t!(format!("{:3d}", 1), " 1"); + t!(format!("{:>3d}", 1), " 1"); + t!(format!("{:>+3d}", 1), " +1"); + t!(format!("{:<3d}", 1), "1 "); + t!(format!("{:#d}", 1), "1"); + t!(format!("{:#x}", 10), "0xa"); + t!(format!("{:#X}", 10), "0xA"); + t!(format!("{:#5x}", 10), " 0xa"); + t!(format!("{:#o}", 10), "0o12"); + t!(format!("{:08x}", 10), "0000000a"); + t!(format!("{:8x}", 10), " a"); + t!(format!("{:<8x}", 10), "a "); + t!(format!("{:>8x}", 10), " a"); + t!(format!("{:#08x}", 10), "0x00000a"); + t!(format!("{:08d}", -10), "-0000010"); + t!(format!("{:x}", -1u8), "ff"); + t!(format!("{:X}", -1u8), "FF"); + t!(format!("{:t}", -1u8), "11111111"); + t!(format!("{:o}", -1u8), "377"); + t!(format!("{:#x}", -1u8), "0xff"); + t!(format!("{:#X}", -1u8), "0xFF"); + t!(format!("{:#t}", -1u8), "0b11111111"); + t!(format!("{:#o}", -1u8), "0o377"); // Signed combinations - t!(ifmt!("{:+5d}", 1), " +1"); - t!(ifmt!("{:+5d}", -1), " -1"); - t!(ifmt!("{:05d}", 1), "00001"); - t!(ifmt!("{:05d}", -1), "-0001"); - t!(ifmt!("{:+05d}", 1), "+0001"); - t!(ifmt!("{:+05d}", -1), "-0001"); + t!(format!("{:+5d}", 1), " +1"); + t!(format!("{:+5d}", -1), " -1"); + t!(format!("{:05d}", 1), "00001"); + t!(format!("{:05d}", -1), "-0001"); + t!(format!("{:+05d}", 1), "+0001"); + t!(format!("{:+05d}", -1), "-0001"); // Some float stuff - t!(ifmt!("{:f}", 1.0f), "1"); - t!(ifmt!("{:f}", 1.0f32), "1"); - t!(ifmt!("{:f}", 1.0f64), "1"); - t!(ifmt!("{:.3f}", 1.0f), "1.000"); - t!(ifmt!("{:10.3f}", 1.0f), " 1.000"); - t!(ifmt!("{:+10.3f}", 1.0f), " +1.000"); - t!(ifmt!("{:+10.3f}", -1.0f), " -1.000"); + t!(format!("{:f}", 1.0f), "1"); + t!(format!("{:f}", 1.0f32), "1"); + t!(format!("{:f}", 1.0f64), "1"); + t!(format!("{:.3f}", 1.0f), "1.000"); + t!(format!("{:10.3f}", 1.0f), " 1.000"); + t!(format!("{:+10.3f}", 1.0f), " +1.000"); + t!(format!("{:+10.3f}", -1.0f), " -1.000"); - test_ifmtf(); + test_write(); + test_print(); } -fn test_ifmtf() { +// Basic test to make sure that we can invoke the `write!` macro with an +// io::Writer instance. +fn test_write() { use std::rt::io::Decorator; use std::rt::io::mem::MemWriter; use std::rt::io; use std::str; let mut buf = MemWriter::new(); - ifmtf!(&mut buf as &mut io::Writer, "{}", 3); + write!(&mut buf as &mut io::Writer, "{}", 3); { let w = &mut buf as &mut io::Writer; - ifmtf!(w, "{foo}", foo=4); - ifmtf!(w, "{:s}", "hello"); + write!(w, "{foo}", foo=4); + write!(w, "{:s}", "hello"); + writeln!(w, "{}", "line"); + writeln!(w, "{foo}", foo="bar"); } let s = str::from_bytes_owned(buf.inner()); - t!(s, "34hello"); + t!(s, "34helloline\nbar\n"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +fn test_print() { + print!(1); + print!("{:?}", ~[0u8]); + println!("hello"); + println!("this is a {}", "test"); + println!("{foo}", foo="bar"); } From a3e39b945402475dbe0eae91833981dad4622cb7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 Aug 2013 12:46:55 -0700 Subject: [PATCH 4/4] Introduce alternate forms of logging These new macros are all based on format! instead of fmt! and purely exist for bootstrapping purposes. After the next snapshot, all uses of logging will be migrated to these macros, and then after the next snapshot after that we can drop the `2` suffix on everything --- src/libsyntax/ext/expand.rs | 53 +++++++++++++++++++++---------------- src/test/run-pass/ifmt.rs | 2 +- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 49b8c994dc2..7b493e11ef7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -758,32 +758,32 @@ pub fn std_macros() -> @str { ) ) - // conditionally define debug!, but keep it type checking even - // in non-debug builds. - macro_rules! __debug ( + macro_rules! debug ( ($arg:expr) => ( - __log(4u32, fmt!( \"%?\", $arg )) + if cfg!(debug) { __log(4u32, fmt!( \"%?\", $arg )) } ); ($( $arg:expr ),+) => ( - __log(4u32, fmt!( $($arg),+ )) + if cfg!(debug) { __log(4u32, fmt!( $($arg),+ )) } ) ) - #[cfg(debug)] - #[macro_escape] - mod debug_macro { - macro_rules! debug (($($arg:expr),*) => { - __debug!($($arg),*) - }) - } + macro_rules! error2 ( + ($($arg:tt)*) => ( __log(1u32, format!($($arg)*))) + ) - #[cfg(not(debug))] - #[macro_escape] - mod debug_macro { - macro_rules! debug (($($arg:expr),*) => { - if false { __debug!($($arg),*) } - }) - } + macro_rules! warn2 ( + ($($arg:tt)*) => ( __log(2u32, format!($($arg)*))) + ) + + macro_rules! info2 ( + ($($arg:tt)*) => ( __log(3u32, format!($($arg)*))) + ) + + macro_rules! debug2 ( + ($($arg:tt)*) => ( + if cfg!(debug) { __log(4u32, format!($($arg)*)) } + ) + ) macro_rules! fail( () => ( @@ -797,6 +797,15 @@ pub fn std_macros() -> @str { ) ) + macro_rules! fail2( + () => ( + fail!(\"explicit failure\") + ); + ($($arg:tt)+) => ( + ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!()) + ) + ) + macro_rules! assert( ($cond:expr) => { if !$cond { @@ -964,15 +973,13 @@ pub fn std_macros() -> @str { // allocation but should rather delegate to an invocation of // write! instead of format! macro_rules! print ( - () => (); - ($arg:expr) => ( ::std::io::print(format!(\"{}\", $arg))); - ($fmt:expr, $($arg:tt)+) => ( ::std::io::print(format!($fmt, $($arg)+))) + ($($arg:tt)+) => ( ::std::io::print(format!($($arg)+))) ) // FIXME(#6846) once stdio is redesigned, this shouldn't perform an // allocation but should rather delegate to an io::Writer macro_rules! println ( - ($($arg:tt)*) => ({ print!($($arg)*); ::std::io::println(\"\"); }) + ($($arg:tt)+) => ({ print!($($arg)+); ::std::io::println(\"\"); }) ) // NOTE: use this after a snapshot lands to abstract the details diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index e067e16f54b..7bf9d004ee0 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -240,7 +240,7 @@ fn test_write() { // Just make sure that the macros are defined, there's not really a lot that we // can do with them just yet (to test the output) fn test_print() { - print!(1); + print!("hi"); print!("{:?}", ~[0u8]); println!("hello"); println!("this is a {}", "test");