about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-09-12 19:36:58 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-15 01:09:00 -0700
commitcfe3db810b7991ef1144afaed4156ddc2586efef (patch)
tree070edc52983621820a65909f2b091d8bc152f43b
parent36872e4180331e4a7f00329abe7972488ce216cf (diff)
downloadrust-cfe3db810b7991ef1144afaed4156ddc2586efef.tar.gz
rust-cfe3db810b7991ef1144afaed4156ddc2586efef.zip
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!
-rw-r--r--src/libstd/fmt/mod.rs7
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs38
-rw-r--r--src/libsyntax/ext/format.rs (renamed from src/libsyntax/ext/ifmt.rs)136
-rw-r--r--src/libsyntax/syntax.rs2
-rw-r--r--src/test/compile-fail/ifmt-bad-arg.rs8
6 files changed, 74 insertions, 125 deletions
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
index c7ab508ea6e..61024ee834b 100644
--- a/src/libstd/fmt/mod.rs
+++ b/src/libstd/fmt/mod.rs
@@ -452,6 +452,13 @@ pub fn write(output: &mut io::Writer, args: &Arguments) {
     unsafe { write_unsafe(output, args.fmt, args.args) }
 }
 
+/// The `writeln` function takes the same arguments as `write`, except that it
+/// will also write a newline (`\n`) character at the end of the format string.
+pub fn writeln(output: &mut io::Writer, args: &Arguments) {
+    unsafe { write_unsafe(output, args.fmt, args.args) }
+    output.write(['\n' as u8]);
+}
+
 /// The `write_unsafe` 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.
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 284801ab123..2bcfafc3bb4 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -155,14 +155,8 @@ pub fn syntax_expander_table() -> SyntaxEnv {
                             @SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
     syntax_expanders.insert(intern(&"fmt"),
                             builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
-    syntax_expanders.insert(intern(&"format"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
-    syntax_expanders.insert(intern(&"write"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
-    syntax_expanders.insert(intern(&"writeln"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
     syntax_expanders.insert(intern(&"format_args"),
-                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_format_args));
+                            builtin_normal_tt_no_ctxt(ext::format::expand_args));
     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 0c8986fc6d7..e4c69c1973a 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -715,11 +715,11 @@ pub fn std_macros() -> @str {
             }
         })
     )
-    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!(debug) { log!(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!(debug) { log!(4u32, $($arg)*) }
     ))
 
     macro_rules! log2(
@@ -730,11 +730,11 @@ 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!(debug) { log2!(4u32, $($arg)+) }
+    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!(debug) { log2!(4u32, $($arg)*) }
     ))
 
     macro_rules! fail(
@@ -753,8 +753,8 @@ pub fn std_macros() -> @str {
         () => (
             fail!(\"explicit failure\")
         );
-        ($($arg:tt)+) => (
-            ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
+        ($($arg:tt)*) => (
+            ::std::sys::FailWithCause::fail_with(format!($($arg)*), file!(), line!())
         )
     )
 
@@ -958,17 +958,25 @@ pub fn std_macros() -> @str {
         )
     )
 
+    macro_rules! format(($($arg:tt)*) => (
+        format_args!(::std::fmt::format, $($arg)*)
+    ))
+    macro_rules! write(($dst:expr, $($arg:tt)*) => (
+        format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
+    ))
+    macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
+        format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
+    ))
     // 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:tt)+) => (::std::io::print(format!($($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)+) => (::std::io::println(format!($($arg)+)))
+        ($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
     )
 
     // NOTE: use this after a snapshot lands to abstract the details
diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/format.rs
index 2f040ef2519..9f4e55b1a92 100644
--- a/src/libsyntax/ext/ifmt.rs
+++ b/src/libsyntax/ext/format.rs
@@ -54,21 +54,16 @@ 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,
-                  leading_expr: bool,
-                  tts: &[ast::token_tree]) -> (Option<@ast::Expr>,
-                                               Option<@ast::Expr>) {
+                  tts: &[ast::token_tree]) -> (@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, 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 };
+        // Parse the leading function expression (maybe a block, maybe a path)
+        let extra = p.parse_expr();
+        if !p.eat(&token::COMMA) {
+            self.ecx.span_err(sp, "expected token: `,`");
+            return (extra, None);
+        }
 
         if *p.token == token::EOF {
             self.ecx.span_err(sp, "requires at least a format string argument");
@@ -547,7 +542,7 @@ impl Context {
 
     /// Actually builds the expression which the ifmt! block will be expanded
     /// to
-    fn to_expr(&self, extra: Option<@ast::Expr>, f: Option<&str>) -> @ast::Expr {
+    fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
         let mut lets = ~[];
         let mut locals = ~[];
         let mut names = vec::from_fn(self.name_positions.len(), |_| None);
@@ -614,68 +609,33 @@ impl Context {
                                      self.ecx.expr_ident(e.span, lname)));
         }
 
+        // Now create the fmt::Arguments struct with all our locals we created.
         let args = names.move_iter().map(|a| a.unwrap());
         let mut args = locals.move_iter().chain(args);
-
-        let result = match f {
-            // Invocation of write!()/format!(), call the function and we're
-            // done.
-            Some(f) => {
-                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_slice(self.fmtsp,
-                                                      args.collect()));
-
-                let result = self.ecx.expr_call_global(self.fmtsp, ~[
-                        self.ecx.ident_of("std"),
-                        self.ecx.ident_of("fmt"),
-                        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 user.
-                self.ecx.expr_block(ast::Block {
-                   view_items: ~[],
-                   stmts: ~[],
-                   expr: Some(result),
-                   id: ast::DUMMY_NODE_ID,
-                   rules: ast::UnsafeBlock(ast::CompilerGenerated),
-                   span: self.fmtsp,
-                })
-            }
-
-            // Invocation of format_args!()
-            None => {
-                let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
-                let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
-                let result = self.ecx.expr_call_global(self.fmtsp, ~[
-                        self.ecx.ident_of("std"),
-                        self.ecx.ident_of("fmt"),
-                        self.ecx.ident_of("Arguments"),
-                        self.ecx.ident_of("new"),
-                    ], ~[fmt, args]);
-
-                // We did all the work of making sure that the arguments
-                // structure is safe, so we can safely have an unsafe block.
-                let result = self.ecx.expr_block(ast::Block {
-                   view_items: ~[],
-                   stmts: ~[],
-                   expr: Some(result),
-                   id: ast::DUMMY_NODE_ID,
-                   rules: ast::UnsafeBlock(ast::CompilerGenerated),
-                   span: self.fmtsp,
-                });
-                let extra = extra.unwrap();
-                let resname = self.ecx.ident_of("__args");
-                lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
-                let res = self.ecx.expr_ident(self.fmtsp, resname);
-                self.ecx.expr_call(extra.span, extra, ~[
-                        self.ecx.expr_addr_of(extra.span, res)])
-            }
-        };
+        let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
+        let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
+        let result = self.ecx.expr_call_global(self.fmtsp, ~[
+                self.ecx.ident_of("std"),
+                self.ecx.ident_of("fmt"),
+                self.ecx.ident_of("Arguments"),
+                self.ecx.ident_of("new"),
+            ], ~[fmt, args]);
+
+        // We did all the work of making sure that the arguments
+        // structure is safe, so we can safely have an unsafe block.
+        let result = self.ecx.expr_block(ast::Block {
+           view_items: ~[],
+           stmts: ~[],
+           expr: Some(result),
+           id: ast::DUMMY_NODE_ID,
+           rules: ast::UnsafeBlock(ast::CompilerGenerated),
+           span: self.fmtsp,
+        });
+        let resname = self.ecx.ident_of("__args");
+        lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
+        let res = self.ecx.expr_ident(self.fmtsp, resname);
+        let result = self.ecx.expr_call(extra.span, extra, ~[
+                            self.ecx.expr_addr_of(extra.span, res)]);
         self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
                                            Some(result)))
     }
@@ -740,29 +700,8 @@ impl Context {
     }
 }
 
-pub fn expand_format(ecx: @ExtCtxt, sp: Span,
-                     tts: &[ast::token_tree]) -> base::MacResult {
-    expand_ifmt(ecx, sp, tts, false, false, Some("format_unsafe"))
-}
-
-pub fn expand_write(ecx: @ExtCtxt, sp: Span,
-                    tts: &[ast::token_tree]) -> base::MacResult {
-    expand_ifmt(ecx, sp, tts, true, false, Some("write_unsafe"))
-}
-
-pub fn expand_writeln(ecx: @ExtCtxt, sp: Span,
-                      tts: &[ast::token_tree]) -> base::MacResult {
-    expand_ifmt(ecx, sp, tts, true, true, Some("write_unsafe"))
-}
-
-pub fn expand_format_args(ecx: @ExtCtxt, sp: Span,
-                          tts: &[ast::token_tree]) -> base::MacResult {
-    expand_ifmt(ecx, sp, tts, true, false, None)
-}
-
-fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
-               leading_arg: bool, append_newline: bool,
-               function: Option<&str>) -> base::MacResult {
+pub fn expand_args(ecx: @ExtCtxt, sp: Span,
+                   tts: &[ast::token_tree]) -> base::MacResult {
     let mut cx = Context {
         ecx: ecx,
         args: ~[],
@@ -776,14 +715,13 @@ fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
         method_statics: ~[],
         fmtsp: sp,
     };
-    let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) {
+    let (extra, efmt) = match cx.parse_args(sp, 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,
                           "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| {
@@ -814,5 +752,5 @@ fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
         }
     }
 
-    MRExpr(cx.to_expr(extra, function))
+    MRExpr(cx.to_expr(extra))
 }
diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs
index fec3b88aab4..48270702e0d 100644
--- a/src/libsyntax/syntax.rs
+++ b/src/libsyntax/syntax.rs
@@ -72,7 +72,7 @@ pub mod ext {
 
     pub mod cfg;
     pub mod fmt;
-    pub mod ifmt;
+    pub mod format;
     pub mod env;
     pub mod bytes;
     pub mod concat_idents;
diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs
index 5da73a495f6..35085feaf15 100644
--- a/src/test/compile-fail/ifmt-bad-arg.rs
+++ b/src/test/compile-fail/ifmt-bad-arg.rs
@@ -11,7 +11,6 @@
 fn main() {
     // bad arguments to the format! call
 
-    format!();                //~ ERROR: requires at least a format string
     format!("{}");            //~ ERROR: invalid reference to argument
 
     format!("{1}", 1);        //~ ERROR: invalid reference to argument `1`
@@ -30,8 +29,6 @@ fn main() {
     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: `,`
 
     format!("{0, select, a{} a{} other{}}", "a");    //~ ERROR: duplicate selector
     format!("{0, plural, =1{} =1{} other{}}", 1u);   //~ ERROR: duplicate selector
@@ -74,4 +71,9 @@ fn main() {
 
     format!("foo } bar"); //~ ERROR: unmatched `}` found
     format!("foo }"); //~ ERROR: unmatched `}` found
+
+    // FIXME(#5794) the spans on these errors are pretty terrible
+    //format!();
+    //format!("" 1);
+    //format!("", 1 1);
 }