Skip to content

Commit cfe3db8

Browse files
committed
Reduce the amount of complexity in format!
This renames the syntax-extension file to format from ifmt, and it also reduces the amount of complexity inside by defining all other macros in terms of format_args!
1 parent 36872e4 commit cfe3db8

File tree

6 files changed

+74
-125
lines changed

6 files changed

+74
-125
lines changed

src/libstd/fmt/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,13 @@ pub fn write(output: &mut io::Writer, args: &Arguments) {
452452
unsafe { write_unsafe(output, args.fmt, args.args) }
453453
}
454454

455+
/// The `writeln` function takes the same arguments as `write`, except that it
456+
/// will also write a newline (`\n`) character at the end of the format string.
457+
pub fn writeln(output: &mut io::Writer, args: &Arguments) {
458+
unsafe { write_unsafe(output, args.fmt, args.args) }
459+
output.write(['\n' as u8]);
460+
}
461+
455462
/// The `write_unsafe` function takes an output stream, a precompiled format
456463
/// string, and a list of arguments. The arguments will be formatted according
457464
/// to the specified format string into the output stream provided.

src/libsyntax/ext/base.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,8 @@ pub fn syntax_expander_table() -> SyntaxEnv {
155155
@SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
156156
syntax_expanders.insert(intern(&"fmt"),
157157
builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
158-
syntax_expanders.insert(intern(&"format"),
159-
builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
160-
syntax_expanders.insert(intern(&"write"),
161-
builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
162-
syntax_expanders.insert(intern(&"writeln"),
163-
builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
164158
syntax_expanders.insert(intern(&"format_args"),
165-
builtin_normal_tt_no_ctxt(ext::ifmt::expand_format_args));
159+
builtin_normal_tt_no_ctxt(ext::format::expand_args));
166160
syntax_expanders.insert(
167161
intern(&"auto_encode"),
168162
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));

src/libsyntax/ext/expand.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -715,11 +715,11 @@ pub fn std_macros() -> @str {
715715
}
716716
})
717717
)
718-
macro_rules! error( ($($arg:tt)+) => (log!(1u32, $($arg)+)) )
719-
macro_rules! warn ( ($($arg:tt)+) => (log!(2u32, $($arg)+)) )
720-
macro_rules! info ( ($($arg:tt)+) => (log!(3u32, $($arg)+)) )
721-
macro_rules! debug( ($($arg:tt)+) => (
722-
if cfg!(debug) { log!(4u32, $($arg)+) }
718+
macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
719+
macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
720+
macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
721+
macro_rules! debug( ($($arg:tt)*) => (
722+
if cfg!(debug) { log!(4u32, $($arg)*) }
723723
))
724724

725725
macro_rules! log2(
@@ -730,11 +730,11 @@ pub fn std_macros() -> @str {
730730
}
731731
})
732732
)
733-
macro_rules! error2( ($($arg:tt)+) => (log2!(1u32, $($arg)+)) )
734-
macro_rules! warn2 ( ($($arg:tt)+) => (log2!(2u32, $($arg)+)) )
735-
macro_rules! info2 ( ($($arg:tt)+) => (log2!(3u32, $($arg)+)) )
736-
macro_rules! debug2( ($($arg:tt)+) => (
737-
if cfg!(debug) { log2!(4u32, $($arg)+) }
733+
macro_rules! error2( ($($arg:tt)*) => (log2!(1u32, $($arg)*)) )
734+
macro_rules! warn2 ( ($($arg:tt)*) => (log2!(2u32, $($arg)*)) )
735+
macro_rules! info2 ( ($($arg:tt)*) => (log2!(3u32, $($arg)*)) )
736+
macro_rules! debug2( ($($arg:tt)*) => (
737+
if cfg!(debug) { log2!(4u32, $($arg)*) }
738738
))
739739

740740
macro_rules! fail(
@@ -753,8 +753,8 @@ pub fn std_macros() -> @str {
753753
() => (
754754
fail!(\"explicit failure\")
755755
);
756-
($($arg:tt)+) => (
757-
::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
756+
($($arg:tt)*) => (
757+
::std::sys::FailWithCause::fail_with(format!($($arg)*), file!(), line!())
758758
)
759759
)
760760

@@ -958,17 +958,25 @@ pub fn std_macros() -> @str {
958958
)
959959
)
960960

961+
macro_rules! format(($($arg:tt)*) => (
962+
format_args!(::std::fmt::format, $($arg)*)
963+
))
964+
macro_rules! write(($dst:expr, $($arg:tt)*) => (
965+
format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
966+
))
967+
macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
968+
format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
969+
))
961970
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
962971
// allocation but should rather delegate to an invocation of
963972
// write! instead of format!
964973
macro_rules! print (
965-
($($arg:tt)+) => (::std::io::print(format!($($arg)+)))
974+
($($arg:tt)*) => (::std::io::print(format!($($arg)*)))
966975
)
967-
968976
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
969977
// allocation but should rather delegate to an io::Writer
970978
macro_rules! println (
971-
($($arg:tt)+) => (::std::io::println(format!($($arg)+)))
979+
($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
972980
)
973981

974982
// NOTE: use this after a snapshot lands to abstract the details

src/libsyntax/ext/ifmt.rs renamed to src/libsyntax/ext/format.rs

Lines changed: 37 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,16 @@ impl Context {
5454
/// Parses the arguments from the given list of tokens, returning None if
5555
/// there's a parse error so we can continue parsing other fmt! expressions.
5656
fn parse_args(&mut self, sp: Span,
57-
leading_expr: bool,
58-
tts: &[ast::token_tree]) -> (Option<@ast::Expr>,
59-
Option<@ast::Expr>) {
57+
tts: &[ast::token_tree]) -> (@ast::Expr, Option<@ast::Expr>) {
6058
let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
6159
self.ecx.cfg(),
6260
tts.to_owned());
63-
// If we want a leading expression, parse it here
64-
let extra = if leading_expr {
65-
let e = Some(p.parse_expr());
66-
if !p.eat(&token::COMMA) {
67-
self.ecx.span_err(sp, "expected token: `,`");
68-
return (e, None);
69-
}
70-
e
71-
} else { None };
61+
// Parse the leading function expression (maybe a block, maybe a path)
62+
let extra = p.parse_expr();
63+
if !p.eat(&token::COMMA) {
64+
self.ecx.span_err(sp, "expected token: `,`");
65+
return (extra, None);
66+
}
7267

7368
if *p.token == token::EOF {
7469
self.ecx.span_err(sp, "requires at least a format string argument");
@@ -547,7 +542,7 @@ impl Context {
547542

548543
/// Actually builds the expression which the ifmt! block will be expanded
549544
/// to
550-
fn to_expr(&self, extra: Option<@ast::Expr>, f: Option<&str>) -> @ast::Expr {
545+
fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
551546
let mut lets = ~[];
552547
let mut locals = ~[];
553548
let mut names = vec::from_fn(self.name_positions.len(), |_| None);
@@ -614,68 +609,33 @@ impl Context {
614609
self.ecx.expr_ident(e.span, lname)));
615610
}
616611

612+
// Now create the fmt::Arguments struct with all our locals we created.
617613
let args = names.move_iter().map(|a| a.unwrap());
618614
let mut args = locals.move_iter().chain(args);
619-
620-
let result = match f {
621-
// Invocation of write!()/format!(), call the function and we're
622-
// done.
623-
Some(f) => {
624-
let mut fmt_args = match extra {
625-
Some(e) => ~[e], None => ~[]
626-
};
627-
fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name));
628-
fmt_args.push(self.ecx.expr_vec_slice(self.fmtsp,
629-
args.collect()));
630-
631-
let result = self.ecx.expr_call_global(self.fmtsp, ~[
632-
self.ecx.ident_of("std"),
633-
self.ecx.ident_of("fmt"),
634-
self.ecx.ident_of(f),
635-
], fmt_args);
636-
637-
// sprintf is unsafe, but we just went through a lot of work to
638-
// validate that our call is save, so inject the unsafe block
639-
// for the user.
640-
self.ecx.expr_block(ast::Block {
641-
view_items: ~[],
642-
stmts: ~[],
643-
expr: Some(result),
644-
id: ast::DUMMY_NODE_ID,
645-
rules: ast::UnsafeBlock(ast::CompilerGenerated),
646-
span: self.fmtsp,
647-
})
648-
}
649-
650-
// Invocation of format_args!()
651-
None => {
652-
let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
653-
let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
654-
let result = self.ecx.expr_call_global(self.fmtsp, ~[
655-
self.ecx.ident_of("std"),
656-
self.ecx.ident_of("fmt"),
657-
self.ecx.ident_of("Arguments"),
658-
self.ecx.ident_of("new"),
659-
], ~[fmt, args]);
660-
661-
// We did all the work of making sure that the arguments
662-
// structure is safe, so we can safely have an unsafe block.
663-
let result = self.ecx.expr_block(ast::Block {
664-
view_items: ~[],
665-
stmts: ~[],
666-
expr: Some(result),
667-
id: ast::DUMMY_NODE_ID,
668-
rules: ast::UnsafeBlock(ast::CompilerGenerated),
669-
span: self.fmtsp,
670-
});
671-
let extra = extra.unwrap();
672-
let resname = self.ecx.ident_of("__args");
673-
lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
674-
let res = self.ecx.expr_ident(self.fmtsp, resname);
675-
self.ecx.expr_call(extra.span, extra, ~[
676-
self.ecx.expr_addr_of(extra.span, res)])
677-
}
678-
};
615+
let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
616+
let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
617+
let result = self.ecx.expr_call_global(self.fmtsp, ~[
618+
self.ecx.ident_of("std"),
619+
self.ecx.ident_of("fmt"),
620+
self.ecx.ident_of("Arguments"),
621+
self.ecx.ident_of("new"),
622+
], ~[fmt, args]);
623+
624+
// We did all the work of making sure that the arguments
625+
// structure is safe, so we can safely have an unsafe block.
626+
let result = self.ecx.expr_block(ast::Block {
627+
view_items: ~[],
628+
stmts: ~[],
629+
expr: Some(result),
630+
id: ast::DUMMY_NODE_ID,
631+
rules: ast::UnsafeBlock(ast::CompilerGenerated),
632+
span: self.fmtsp,
633+
});
634+
let resname = self.ecx.ident_of("__args");
635+
lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
636+
let res = self.ecx.expr_ident(self.fmtsp, resname);
637+
let result = self.ecx.expr_call(extra.span, extra, ~[
638+
self.ecx.expr_addr_of(extra.span, res)]);
679639
self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
680640
Some(result)))
681641
}
@@ -740,29 +700,8 @@ impl Context {
740700
}
741701
}
742702

743-
pub fn expand_format(ecx: @ExtCtxt, sp: Span,
744-
tts: &[ast::token_tree]) -> base::MacResult {
745-
expand_ifmt(ecx, sp, tts, false, false, Some("format_unsafe"))
746-
}
747-
748-
pub fn expand_write(ecx: @ExtCtxt, sp: Span,
749-
tts: &[ast::token_tree]) -> base::MacResult {
750-
expand_ifmt(ecx, sp, tts, true, false, Some("write_unsafe"))
751-
}
752-
753-
pub fn expand_writeln(ecx: @ExtCtxt, sp: Span,
754-
tts: &[ast::token_tree]) -> base::MacResult {
755-
expand_ifmt(ecx, sp, tts, true, true, Some("write_unsafe"))
756-
}
757-
758-
pub fn expand_format_args(ecx: @ExtCtxt, sp: Span,
759-
tts: &[ast::token_tree]) -> base::MacResult {
760-
expand_ifmt(ecx, sp, tts, true, false, None)
761-
}
762-
763-
fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
764-
leading_arg: bool, append_newline: bool,
765-
function: Option<&str>) -> base::MacResult {
703+
pub fn expand_args(ecx: @ExtCtxt, sp: Span,
704+
tts: &[ast::token_tree]) -> base::MacResult {
766705
let mut cx = Context {
767706
ecx: ecx,
768707
args: ~[],
@@ -776,14 +715,13 @@ fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
776715
method_statics: ~[],
777716
fmtsp: sp,
778717
};
779-
let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) {
718+
let (extra, efmt) = match cx.parse_args(sp, tts) {
780719
(extra, Some(e)) => (extra, e),
781720
(_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); }
782721
};
783722
cx.fmtsp = efmt.span;
784723
let fmt = expr_to_str(ecx, efmt,
785724
"format argument must be a string literal.");
786-
let fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() };
787725

788726
let mut err = false;
789727
do parse::parse_error::cond.trap(|m| {
@@ -814,5 +752,5 @@ fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
814752
}
815753
}
816754

817-
MRExpr(cx.to_expr(extra, function))
755+
MRExpr(cx.to_expr(extra))
818756
}

src/libsyntax/syntax.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub mod ext {
7272

7373
pub mod cfg;
7474
pub mod fmt;
75-
pub mod ifmt;
75+
pub mod format;
7676
pub mod env;
7777
pub mod bytes;
7878
pub mod concat_idents;

src/test/compile-fail/ifmt-bad-arg.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
fn main() {
1212
// bad arguments to the format! call
1313

14-
format!(); //~ ERROR: requires at least a format string
1514
format!("{}"); //~ ERROR: invalid reference to argument
1615

1716
format!("{1}", 1); //~ ERROR: invalid reference to argument `1`
@@ -30,8 +29,6 @@ fn main() {
3029
format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
3130
format!("#"); //~ ERROR: `#` reference used
3231
format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
33-
format!("" 1); //~ ERROR: expected token: `,`
34-
format!("", 1 1); //~ ERROR: expected token: `,`
3532

3633
format!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector
3734
format!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector
@@ -74,4 +71,9 @@ fn main() {
7471

7572
format!("foo } bar"); //~ ERROR: unmatched `}` found
7673
format!("foo }"); //~ ERROR: unmatched `}` found
74+
75+
// FIXME(#5794) the spans on these errors are pretty terrible
76+
//format!();
77+
//format!("" 1);
78+
//format!("", 1 1);
7779
}

0 commit comments

Comments
 (0)