about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-08-24 19:21:17 -0700
committerbors <bors@rust-lang.org>2013-08-24 19:21:17 -0700
commita17c7e4f2c0cfd800ce873b83334e8b17bef2f70 (patch)
treedcc5745a47c06dcbed739a2f80ee02cd91cfebea /src/libsyntax
parentf7f1d896497b10cb56389730e784aff6e513b0e8 (diff)
parenta3e39b945402475dbe0eae91833981dad4622cb7 (diff)
downloadrust-a17c7e4f2c0cfd800ce873b83334e8b17bef2f70.tar.gz
rust-a17c7e4f2c0cfd800ce873b83334e8b17bef2f70.zip
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.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs62
-rw-r--r--src/libsyntax/ext/ifmt.rs74
3 files changed, 102 insertions, 42 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index dfaffa0c275..6f9585652bd 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -139,8 +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_syntax_ext));
+    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..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 {
@@ -940,6 +949,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 +959,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 +969,19 @@ 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: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(\"\"); })
+    )
+
     // 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 35be77b95c5..d4274746a4e 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,24 @@ impl Context {
     }
 }
 
-pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
-                         tts: &[ast::token_tree]) -> base::MacResult {
+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_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, append_newline: bool,
+               function: &str) -> base::MacResult {
     let mut cx = Context {
         ecx: ecx,
         args: ~[],
@@ -697,13 +728,14 @@ 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 fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() };
 
     let mut err = false;
     do parse::parse_error::cond.trap(|m| {
@@ -734,5 +766,5 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
         }
     }
 
-    MRExpr(cx.to_expr())
+    MRExpr(cx.to_expr(extra, function))
 }