about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-09-15 01:50:50 -0700
committerbors <bors@rust-lang.org>2013-09-15 01:50:50 -0700
commit4ecb0a372d4b246f694bf780d50809dc0fb32018 (patch)
tree187f30d8b9ae662bc385558473e1c9c1fa5b6424 /src/libsyntax
parent36872e4180331e4a7f00329abe7972488ce216cf (diff)
parent640613892fc5ab055853b48934b6e4ecf895c2dd (diff)
downloadrust-4ecb0a372d4b246f694bf780d50809dc0fb32018.tar.gz
rust-4ecb0a372d4b246f694bf780d50809dc0fb32018.zip
auto merge of #9153 : alexcrichton/rust/simplify-format, r=huonw
This follows from the discussion in #9012.

* All macros are now defined in terms of `format_args!` allowing for removal of a good bit of code in the syntax extension
* The syntax extension is now in a more aptly-named file, `format.rs`
* Documentation was added for the `format!`-related macros.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs78
-rw-r--r--src/libsyntax/ext/format.rs (renamed from src/libsyntax/ext/ifmt.rs)136
-rw-r--r--src/libsyntax/syntax.rs2
4 files changed, 87 insertions, 137 deletions
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..ac094c27a81 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -81,20 +81,10 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                             // be the root of the call stack. That's the most
                             // relevant span and it's the actual invocation of
                             // the macro.
-                            let mut relevant_info = cx.backtrace();
-                            let mut einfo = relevant_info.unwrap();
-                            loop {
-                                match relevant_info {
-                                    None => { break }
-                                    Some(e) => {
-                                        einfo = e;
-                                        relevant_info = einfo.call_site.expn_info;
-                                    }
-                                }
-                            }
+                            let mac_span = original_span(cx);
 
                             let expanded =
-                                match expandfun(cx, einfo.call_site,
+                                match expandfun(cx, mac_span.call_site,
                                                 marked_before, marked_ctxt) {
                                     MRExpr(e) => e,
                                     MRAny(expr_maker,_,_) => expr_maker(),
@@ -400,11 +390,11 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                 -> (Option<Stmt_>, Span) {
     // why the copying here and not in expand_expr?
     // looks like classic changed-in-only-one-place
-    let (mac, pth, tts, semi, ctxt) = match *s {
+    let (pth, tts, semi, ctxt) = match *s {
         StmtMac(ref mac, semi) => {
             match mac.node {
                 mac_invoc_tt(ref pth, ref tts, ctxt) => {
-                    ((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
+                    (pth, (*tts).clone(), semi, ctxt)
                 }
             }
         }
@@ -431,7 +421,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
             let marked_ctxt = new_mark(fm,ctxt);
-            let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
+
+            // See the comment in expand_expr for why we want the original span,
+            // not the current mac.span.
+            let mac_span = original_span(cx);
+
+            let expanded = match expandfun(cx, mac_span.call_site,
+                                           marked_tts, marked_ctxt) {
                 MRExpr(e) =>
                     @codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
                                         span: e.span},
@@ -715,11 +711,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 +726,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 +749,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 +954,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
@@ -1262,6 +1266,20 @@ pub fn mtwt_cancel_outer_mark(tts: &[ast::token_tree], ctxt: ast::SyntaxContext)
     mark_tts(tts,outer_mark)
 }
 
+fn original_span(cx: @ExtCtxt) -> @codemap::ExpnInfo {
+    let mut relevant_info = cx.backtrace();
+    let mut einfo = relevant_info.unwrap();
+    loop {
+        match relevant_info {
+            None => { break }
+            Some(e) => {
+                einfo = e;
+                relevant_info = einfo.call_site.expn_info;
+            }
+        }
+    }
+    return einfo;
+}
 
 #[cfg(test)]
 mod test {
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;