about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorPiotr Czarnecki <pioczarn@gmail.com>2014-08-21 14:34:00 +0100
committerPiotr Czarnecki <pioczarn@gmail.com>2014-09-09 20:34:41 +0100
commit696367fb8de63a3ff264c65981457b9fbd0e7b06 (patch)
tree4b5d33c711873f1fd881300a13f91b7a90d12be7 /src/libsyntax
parent6f34760e4173dda94162502153fe4c5a2a96fc9d (diff)
downloadrust-696367fb8de63a3ff264c65981457b9fbd0e7b06.tar.gz
rust-696367fb8de63a3ff264c65981457b9fbd0e7b06.zip
Decouple string and argument pieces
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/format.rs84
1 files changed, 54 insertions, 30 deletions
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index b3bb01e1d04..fc4d8c83c51 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -49,11 +49,13 @@ struct Context<'a, 'b:'a> {
     name_types: HashMap<String, ArgumentType>,
     name_ordering: Vec<String>,
 
-    /// The latest consecutive literal strings
-    literal: Option<String>,
+    /// The latest consecutive literal strings, or empty if there weren't any.
+    literal: String,
 
-    /// Collection of the compiled `rt::Piece` structures
+    /// Collection of the compiled `rt::Argument` structures
     pieces: Vec<Gc<ast::Expr>>,
+    /// Collection of string literals
+    str_pieces: Vec<Gc<ast::Expr>>,
     name_positions: HashMap<String, uint>,
     method_statics: Vec<Gc<ast::Item>>,
 
@@ -370,28 +372,22 @@ impl<'a, 'b> Context<'a, 'b> {
         }
     }
 
-    /// Translate the accumulated string literals to a static `rt::Piece`
-    fn trans_literal_string(&mut self) -> Option<Gc<ast::Expr>> {
+    /// Translate the accumulated string literals to a literal expression
+    fn trans_literal_string(&mut self) -> Gc<ast::Expr> {
         let sp = self.fmtsp;
-        self.literal.take().map(|s| {
-            let s = token::intern_and_get_ident(s.as_slice());
-            self.ecx.expr_call_global(sp,
-                                      self.rtpath("String"),
-                                      vec!(
-                self.ecx.expr_str(sp, s)
-            ))
-        })
+        let s = token::intern_and_get_ident(self.literal.as_slice());
+        self.literal.clear();
+        self.ecx.expr_str(sp, s)
     }
 
-    /// Translate a `parse::Piece` to a static `rt::Piece`
+    /// Translate a `parse::Piece` to a static `rt::Argument` or append
+    /// to the `literal` string.
     fn trans_piece(&mut self, piece: &parse::Piece) -> Option<Gc<ast::Expr>> {
+        // let mut is_not_default = true;
         let sp = self.fmtsp;
         match *piece {
             parse::String(s) => {
-                match self.literal {
-                    Some(ref mut sb) => sb.push_str(s),
-                    ref mut empty => *empty = Some(String::from_str(s)),
-                }
+                self.literal.push_str(s);
                 None
             }
             parse::Argument(ref arg) => {
@@ -450,10 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
                     self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
 
                 let path = self.ecx.path_global(sp, self.rtpath("Argument"));
-                let s = self.ecx.expr_struct(sp, path, vec!(
+                Some(self.ecx.expr_struct(sp, path, vec!(
                     self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
-                    self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)));
-                Some(self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s)))
+                    self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt))))
             }
         }
     }
@@ -476,6 +471,30 @@ impl<'a, 'b> Context<'a, 'b> {
 
         // Next, build up the static array which will become our precompiled
         // format "string"
+        let fmt = self.ecx.expr_vec(self.fmtsp, self.str_pieces.clone());
+        let piece_ty = self.ecx.ty_rptr(self.fmtsp,
+                                        self.ecx.ty_ident(self.fmtsp,
+                                             self.ecx.ident_of("str")),
+                                        Some(self.ecx.lifetime(self.fmtsp,
+                                             self.ecx.ident_of(
+                                                 "'static").name)),
+                                        ast::MutImmutable);
+
+        let ty = ast::TyFixedLengthVec(
+            piece_ty,
+            self.ecx.expr_uint(self.fmtsp, self.str_pieces.len())
+        );
+        let ty = self.ecx.ty(self.fmtsp, ty);
+        let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
+        let static_str_name = self.ecx.ident_of("__STATIC_FMTSTR");
+        let item = self.ecx.item(self.fmtsp, static_str_name,
+                                 self.static_attrs(), st);
+        let decl = respan(self.fmtsp, ast::DeclItem(item));
+        lets.push(box(GC) respan(self.fmtsp,
+                                 ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID)));
+
+        // Then, build up the static array which will become our precompiled
+        // format "string"
         let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
         let piece_ty = self.ecx.ty_path(self.ecx.path_all(
                 self.fmtsp,
@@ -483,7 +502,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     self.ecx.ident_of("std"),
                     self.ecx.ident_of("fmt"),
                     self.ecx.ident_of("rt"),
-                    self.ecx.ident_of("Piece")),
+                    self.ecx.ident_of("Argument")),
                 vec!(self.ecx.lifetime(self.fmtsp,
                                        self.ecx.ident_of("'static").name)),
                 Vec::new()
@@ -494,8 +513,8 @@ impl<'a, 'b> Context<'a, 'b> {
         );
         let ty = self.ecx.ty(self.fmtsp, ty);
         let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
-        let static_name = self.ecx.ident_of("__STATIC_FMTSTR");
-        let item = self.ecx.item(self.fmtsp, static_name,
+        let static_args_name = self.ecx.ident_of("__STATIC_FMTARGS");
+        let item = self.ecx.item(self.fmtsp, static_args_name,
                                  self.static_attrs(), st);
         let decl = respan(self.fmtsp, ast::DeclItem(item));
         lets.push(box(GC) respan(self.fmtsp,
@@ -545,13 +564,14 @@ impl<'a, 'b> Context<'a, 'b> {
         }
 
         // Now create the fmt::Arguments struct with all our locals we created.
-        let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
+        let pieces = self.ecx.expr_ident(self.fmtsp, static_str_name);
+        let fmt = self.ecx.expr_ident(self.fmtsp, static_args_name);
         let args_slice = self.ecx.expr_ident(self.fmtsp, slicename);
         let result = self.ecx.expr_call_global(self.fmtsp, vec!(
                 self.ecx.ident_of("std"),
                 self.ecx.ident_of("fmt"),
                 self.ecx.ident_of("Arguments"),
-                self.ecx.ident_of("new")), vec!(fmt, args_slice));
+                self.ecx.ident_of("new")), vec!(pieces, fmt, args_slice));
 
         // We did all the work of making sure that the arguments
         // structure is safe, so we can safely have an unsafe block.
@@ -718,8 +738,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         name_ordering: name_ordering,
         nest_level: 0,
         next_arg: 0,
-        literal: None,
+        literal: String::new(),
         pieces: Vec::new(),
+        str_pieces: Vec::new(),
         method_statics: Vec::new(),
         fmtsp: sp,
     };
@@ -739,8 +760,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
                 cx.verify_piece(&piece);
                 match cx.trans_piece(&piece) {
                     Some(piece) => {
-                        cx.trans_literal_string().map(|piece|
-                                                      cx.pieces.push(piece));
+                        let s = cx.trans_literal_string();
+                        cx.str_pieces.push(s);
                         cx.pieces.push(piece);
                     }
                     None => {}
@@ -758,7 +779,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         }
         None => {}
     }
-    cx.trans_literal_string().map(|piece| cx.pieces.push(piece));
+    if !cx.literal.is_empty() {
+        let s = cx.trans_literal_string();
+        cx.str_pieces.push(s);
+    }
 
     // Make sure that all arguments were used and all arguments have types.
     for (i, ty) in cx.arg_types.iter().enumerate() {