Decouple string and argument pieces
This commit is contained in:
parent
6f34760e41
commit
696367fb8d
4 changed files with 134 additions and 45 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue