name_types: HashMap<String, ArgumentType>,
name_ordering: Vec<String>,
+ /// The latest consecutive literal strings
+ literal: Option<String>,
+
/// Collection of the compiled `rt::Piece` structures
pieces: Vec<Gc<ast::Expr>>,
name_positions: HashMap<String, uint>,
/// These attributes are applied to all statics that this syntax extension
/// will generate.
fn static_attrs(&self) -> Vec<ast::Attribute> {
+ // Flag statics as `inline` so LLVM can merge duplicate globals as much
+ // as possible (which we're generating a whole lot of).
+ let unnamed = self.ecx.meta_word(self.fmtsp, InternedString::new("inline"));
+ let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+
// Do not warn format string as dead code
let dead_code = self.ecx.meta_word(self.fmtsp,
InternedString::new("dead_code"));
InternedString::new("allow"),
vec!(dead_code));
let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
- return vec!(allow_dead_code);
+ return vec!(unnamed, allow_dead_code);
}
fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
}
}
+ /// Translate the accumulated string literals to a static `rt::Piece`
+ fn trans_literal_string(&mut self) -> Option<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)
+ ))
+ })
+ }
+
/// Translate a `parse::Piece` to a static `rt::Piece`
- fn trans_piece(&mut self, piece: &parse::Piece) -> Gc<ast::Expr> {
+ fn trans_piece(&mut self, piece: &parse::Piece) -> Option<Gc<ast::Expr>> {
let sp = self.fmtsp;
match *piece {
parse::String(s) => {
- let s = token::intern_and_get_ident(s);
- self.ecx.expr_call_global(sp,
- self.rtpath("String"),
- vec!(
- self.ecx.expr_str(sp, s)
- ))
+ match self.literal {
+ Some(ref mut sb) => sb.push_str(s),
+ ref mut empty => *empty = Some(String::from_str(s)),
+ }
+ None
}
parse::Argument(ref arg) => {
// Translate the position
let s = 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)));
- self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))
+ Some(self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s)))
}
}
}
name_ordering: name_ordering,
nest_level: 0,
next_arg: 0,
+ literal: None,
pieces: Vec::new(),
method_statics: Vec::new(),
fmtsp: sp,
Some(piece) => {
if parser.errors.len() > 0 { break }
cx.verify_piece(&piece);
- let piece = cx.trans_piece(&piece);
- cx.pieces.push(piece);
+ match cx.trans_piece(&piece) {
+ Some(piece) => {
+ cx.trans_literal_string().map(|piece|
+ cx.pieces.push(piece));
+ cx.pieces.push(piece);
+ }
+ None => {}
+ }
}
None => break
}
}
None => {}
}
+ cx.trans_literal_string().map(|piece| cx.pieces.push(piece));
// Make sure that all arguments were used and all arguments have types.
for (i, ty) in cx.arg_types.iter().enumerate() {