Skip to content

Commit a17c7e4

Browse files
committed
auto merge of #8637 : alexcrichton/rust/ifmt-less-hax, r=graydon
Recent improvements to `&mut Trait` have made this work possible, and it solidifies that `ifmt` doesn't always have to return a string, but rather it's based around writers.
2 parents f7f1d89 + a3e39b9 commit a17c7e4

File tree

10 files changed

+409
-292
lines changed

10 files changed

+409
-292
lines changed

src/libstd/fmt/mod.rs

+60-38
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,33 @@
1212
1313
# The Formatting Module
1414
15-
This module contains the runtime support for the `ifmt!` syntax extension. This
15+
This module contains the runtime support for the `format!` syntax extension. This
1616
macro is implemented in the compiler to emit calls to this module in order to
1717
format arguments at runtime into strings and streams.
1818
1919
The functions contained in this module should not normally be used in everyday
20-
use cases of `ifmt!`. The assumptions made by these functions are unsafe for all
20+
use cases of `format!`. The assumptions made by these functions are unsafe for all
2121
inputs, and the compiler performs a large amount of validation on the arguments
22-
to `ifmt!` in order to ensure safety at runtime. While it is possible to call
22+
to `format!` in order to ensure safety at runtime. While it is possible to call
2323
these functions directly, it is not recommended to do so in the general case.
2424
2525
## Usage
2626
27-
The `ifmt!` macro is intended to be familiar to those coming from C's
28-
printf/sprintf functions or Python's `str.format` function. In its current
29-
revision, the `ifmt!` macro returns a `~str` type which is the result of the
27+
The `format!` macro is intended to be familiar to those coming from C's
28+
printf/fprintf functions or Python's `str.format` function. In its current
29+
revision, the `format!` macro returns a `~str` type which is the result of the
3030
formatting. In the future it will also be able to pass in a stream to format
3131
arguments directly while performing minimal allocations.
3232
33-
Some examples of the `ifmt!` extension are:
33+
Some examples of the `format!` extension are:
3434
3535
~~~{.rust}
36-
ifmt!("Hello") // => ~"Hello"
37-
ifmt!("Hello, {:s}!", "world") // => ~"Hello, world!"
38-
ifmt!("The number is {:d}", 1) // => ~"The number is 1"
39-
ifmt!("{}", ~[3, 4]) // => ~"~[3, 4]"
40-
ifmt!("{value}", value=4) // => ~"4"
41-
ifmt!("{} {}", 1, 2) // => ~"1 2"
36+
format!("Hello") // => ~"Hello"
37+
format!("Hello, {:s}!", "world") // => ~"Hello, world!"
38+
format!("The number is {:d}", 1) // => ~"The number is 1"
39+
format!("{}", ~[3, 4]) // => ~"~[3, 4]"
40+
format!("{value}", value=4) // => ~"4"
41+
format!("{} {}", 1, 2) // => ~"1 2"
4242
~~~
4343
4444
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.
6262
### Named parameters
6363
6464
Rust itself does not have a Python-like equivalent of named parameters to a
65-
function, but the `ifmt!` macro is a syntax extension which allows it to
65+
function, but the `format!` macro is a syntax extension which allows it to
6666
leverage named parameters. Named parameters are listed at the end of the
6767
argument list and have the syntax:
6868
@@ -146,7 +146,7 @@ helper methods.
146146
147147
## Internationalization
148148
149-
The formatting syntax supported by the `ifmt!` extension supports
149+
The formatting syntax supported by the `format!` extension supports
150150
internationalization by providing "methods" which execute various different
151151
outputs depending on the input. The syntax and methods provided are similar to
152152
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
164164
example:
165165
166166
~~~
167-
ifmt!("{0, select, other{#}}", "hello") // => ~"hello"
167+
format!("{0, select, other{#}}", "hello") // => ~"hello"
168168
~~~
169169
170170
This example is the equivalent of `{0:s}` essentially.
@@ -399,7 +399,44 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); }
399399
#[allow(missing_doc)]
400400
pub trait Float { fn fmt(&Self, &mut Formatter); }
401401

402-
/// The sprintf function takes a precompiled format string and a list of
402+
/// The `write` function takes an output stream, a precompiled format string,
403+
/// and a list of arguments. The arguments will be formatted according to the
404+
/// specified format string into the output stream provided.
405+
///
406+
/// See the documentation for `format` for why this function is unsafe and care
407+
/// should be taken if calling it manually.
408+
///
409+
/// Thankfully the rust compiler provides the macro `fmtf!` which will perform
410+
/// all of this validation at compile-time and provides a safe interface for
411+
/// invoking this function.
412+
///
413+
/// # Arguments
414+
///
415+
/// * output - the buffer to write output to
416+
/// * fmts - the precompiled format string to emit
417+
/// * args - the list of arguments to the format string. These are only the
418+
/// positional arguments (not named)
419+
///
420+
/// Note that this function assumes that there are enough arguments for the
421+
/// format string.
422+
pub unsafe fn write(output: &mut io::Writer,
423+
fmt: &[rt::Piece], args: &[Argument]) {
424+
let mut formatter = Formatter {
425+
flags: 0,
426+
width: None,
427+
precision: None,
428+
buf: output,
429+
align: parse::AlignUnknown,
430+
fill: ' ',
431+
args: args,
432+
curarg: args.iter(),
433+
};
434+
for piece in fmt.iter() {
435+
formatter.run(piece, None);
436+
}
437+
}
438+
439+
/// The format function takes a precompiled format string and a list of
403440
/// arguments, to return the resulting formatted string.
404441
///
405442
/// This is currently an unsafe function because the types of all arguments
@@ -409,7 +446,7 @@ pub trait Float { fn fmt(&Self, &mut Formatter); }
409446
/// for formatting the right type value. Because of this, the function is marked
410447
/// as `unsafe` if this is being called manually.
411448
///
412-
/// Thankfully the rust compiler provides the macro `ifmt!` which will perform
449+
/// Thankfully the rust compiler provides the macro `format!` which will perform
413450
/// all of this validation at compile-time and provides a safe interface for
414451
/// invoking this function.
415452
///
@@ -421,32 +458,17 @@ pub trait Float { fn fmt(&Self, &mut Formatter); }
421458
///
422459
/// Note that this function assumes that there are enough arguments for the
423460
/// format string.
424-
pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
425-
let output = MemWriter::new();
426-
{
427-
let mut formatter = Formatter {
428-
flags: 0,
429-
width: None,
430-
precision: None,
431-
// FIXME(#8248): shouldn't need a transmute
432-
buf: cast::transmute(&output as &io::Writer),
433-
align: parse::AlignUnknown,
434-
fill: ' ',
435-
args: args,
436-
curarg: args.iter(),
437-
};
438-
for piece in fmt.iter() {
439-
formatter.run(piece, None);
440-
}
441-
}
461+
pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
462+
let mut output = MemWriter::new();
463+
write(&mut output as &mut io::Writer, fmt, args);
442464
return str::from_bytes_owned(output.inner());
443465
}
444466

445467
impl<'self> Formatter<'self> {
446468

447469
// First up is the collection of functions used to execute a format string
448470
// at runtime. This consumes all of the compile-time statics generated by
449-
// the ifmt! syntax extension.
471+
// the format! syntax extension.
450472

451473
fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
452474
let setcount = |slot: &mut Option<uint>, cnt: &parse::Count| {
@@ -710,7 +732,7 @@ impl<'self> Formatter<'self> {
710732
}
711733

712734
/// This is a function which calls are emitted to by the compiler itself to
713-
/// create the Argument structures that are passed into the `sprintf` function.
735+
/// create the Argument structures that are passed into the `format` function.
714736
#[doc(hidden)]
715737
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
716738
t: &'a T) -> Argument<'a> {

src/libsyntax/ext/base.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,12 @@ pub fn syntax_expander_table() -> SyntaxEnv {
139139
ext::tt::macro_rules::add_new_extension));
140140
syntax_expanders.insert(intern(&"fmt"),
141141
builtin_normal_tt(ext::fmt::expand_syntax_ext));
142-
syntax_expanders.insert(intern(&"ifmt"),
143-
builtin_normal_tt(ext::ifmt::expand_syntax_ext));
142+
syntax_expanders.insert(intern(&"format"),
143+
builtin_normal_tt(ext::ifmt::expand_format));
144+
syntax_expanders.insert(intern(&"write"),
145+
builtin_normal_tt(ext::ifmt::expand_write));
146+
syntax_expanders.insert(intern(&"writeln"),
147+
builtin_normal_tt(ext::ifmt::expand_writeln));
144148
syntax_expanders.insert(
145149
intern(&"auto_encode"),
146150
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));

src/libsyntax/ext/expand.rs

+43-19
Original file line numberDiff line numberDiff line change
@@ -758,32 +758,32 @@ pub fn std_macros() -> @str {
758758
)
759759
)
760760

761-
// conditionally define debug!, but keep it type checking even
762-
// in non-debug builds.
763-
macro_rules! __debug (
761+
macro_rules! debug (
764762
($arg:expr) => (
765-
__log(4u32, fmt!( \"%?\", $arg ))
763+
if cfg!(debug) { __log(4u32, fmt!( \"%?\", $arg )) }
766764
);
767765
($( $arg:expr ),+) => (
768-
__log(4u32, fmt!( $($arg),+ ))
766+
if cfg!(debug) { __log(4u32, fmt!( $($arg),+ )) }
769767
)
770768
)
771769

772-
#[cfg(debug)]
773-
#[macro_escape]
774-
mod debug_macro {
775-
macro_rules! debug (($($arg:expr),*) => {
776-
__debug!($($arg),*)
777-
})
778-
}
770+
macro_rules! error2 (
771+
($($arg:tt)*) => ( __log(1u32, format!($($arg)*)))
772+
)
779773

780-
#[cfg(not(debug))]
781-
#[macro_escape]
782-
mod debug_macro {
783-
macro_rules! debug (($($arg:expr),*) => {
784-
if false { __debug!($($arg),*) }
785-
})
786-
}
774+
macro_rules! warn2 (
775+
($($arg:tt)*) => ( __log(2u32, format!($($arg)*)))
776+
)
777+
778+
macro_rules! info2 (
779+
($($arg:tt)*) => ( __log(3u32, format!($($arg)*)))
780+
)
781+
782+
macro_rules! debug2 (
783+
($($arg:tt)*) => (
784+
if cfg!(debug) { __log(4u32, format!($($arg)*)) }
785+
)
786+
)
787787

788788
macro_rules! fail(
789789
() => (
@@ -797,6 +797,15 @@ pub fn std_macros() -> @str {
797797
)
798798
)
799799

800+
macro_rules! fail2(
801+
() => (
802+
fail!(\"explicit failure\")
803+
);
804+
($($arg:tt)+) => (
805+
::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
806+
)
807+
)
808+
800809
macro_rules! assert(
801810
($cond:expr) => {
802811
if !$cond {
@@ -940,6 +949,7 @@ pub fn std_macros() -> @str {
940949
);
941950
)
942951

952+
// NOTE(acrichto): start removing this after the next snapshot
943953
macro_rules! printf (
944954
($arg:expr) => (
945955
print(fmt!(\"%?\", $arg))
@@ -949,6 +959,7 @@ pub fn std_macros() -> @str {
949959
)
950960
)
951961

962+
// NOTE(acrichto): start removing this after the next snapshot
952963
macro_rules! printfln (
953964
($arg:expr) => (
954965
println(fmt!(\"%?\", $arg))
@@ -958,6 +969,19 @@ pub fn std_macros() -> @str {
958969
)
959970
)
960971

972+
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
973+
// allocation but should rather delegate to an invocation of
974+
// write! instead of format!
975+
macro_rules! print (
976+
($($arg:tt)+) => ( ::std::io::print(format!($($arg)+)))
977+
)
978+
979+
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
980+
// allocation but should rather delegate to an io::Writer
981+
macro_rules! println (
982+
($($arg:tt)+) => ({ print!($($arg)+); ::std::io::println(\"\"); })
983+
)
984+
961985
// NOTE: use this after a snapshot lands to abstract the details
962986
// of the TLS interface.
963987
macro_rules! local_data_key (

0 commit comments

Comments
 (0)