Skip to content

Commit 09e16e2

Browse files
committed
---
yaml --- r: 130685 b: refs/heads/snap-stage3 c: 5aaa606 h: refs/heads/master i: 130683: cb4bd8e v: v3
1 parent c2cefe7 commit 09e16e2

File tree

3 files changed

+126
-56
lines changed

3 files changed

+126
-56
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: ee72e46638f2b2ae92e99df2a7ea92690baa0d07
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 696367fb8de63a3ff264c65981457b9fbd0e7b06
4+
refs/heads/snap-stage3: 5aaa60693222c98c92fbde830f9a85c24f2e3f4f
55
refs/heads/try: a2473a89da106f7dd3be86e9d52fe23f43d5bfa5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/libcore/fmt/mod.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,25 @@ impl<'a> Arguments<'a> {
116116
#[cfg(not(stage0))]
117117
#[doc(hidden)] #[inline]
118118
pub unsafe fn new<'a>(pieces: &'static [&'static str],
119-
fmt: &'static [rt::Argument<'static>],
120119
args: &'a [Argument<'a>]) -> Arguments<'a> {
121120
Arguments {
122121
pieces: mem::transmute(pieces),
123-
fmt: mem::transmute(fmt),
122+
fmt: None,
123+
args: args
124+
}
125+
}
126+
127+
/// This function is used to specify nonstandard formatting parameters.
128+
/// The `pieces` array must be at least as long as `fmt` to construct
129+
/// a valid Arguments structure.
130+
#[cfg(not(stage0))]
131+
#[doc(hidden)] #[inline]
132+
pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str],
133+
fmt: &'static [rt::Argument<'static>],
134+
args: &'a [Argument<'a>]) -> Arguments<'a> {
135+
Arguments {
136+
pieces: mem::transmute(pieces),
137+
fmt: Some(mem::transmute(fmt)),
124138
args: args
125139
}
126140
}
@@ -144,8 +158,14 @@ impl<'a> Arguments<'a> {
144158
/// and `format` functions can be safely performed.
145159
#[cfg(not(stage0))]
146160
pub struct Arguments<'a> {
161+
// Format string pieces to print.
147162
pieces: &'a [&'a str],
148-
fmt: &'a [rt::Argument<'a>],
163+
164+
// Placeholder specs, or `None` if all specs are default (as in "{}{}").
165+
fmt: Option<&'a [rt::Argument<'a>]>,
166+
167+
// Dynamic arguments for interpolation, to be interleaved with string
168+
// pieces. (Every argument is preceded by a string piece.)
149169
args: &'a [Argument<'a>],
150170
}
151171

@@ -276,6 +296,18 @@ uniform_fn_call_workaround! {
276296
secret_upper_exp, UpperExp;
277297
}
278298

299+
#[cfg(not(stage0))]
300+
static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
301+
position: rt::ArgumentNext,
302+
format: rt::FormatSpec {
303+
fill: ' ',
304+
align: rt::AlignUnknown,
305+
flags: 0,
306+
precision: rt::CountImplied,
307+
width: rt::CountImplied,
308+
}
309+
};
310+
279311
/// The `write` function takes an output stream, a precompiled format string,
280312
/// and a list of arguments. The arguments will be formatted according to the
281313
/// specified format string into the output stream provided.
@@ -299,11 +331,25 @@ pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
299331

300332
let mut pieces = args.pieces.iter();
301333

302-
for arg in args.fmt.iter() {
303-
try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
304-
try!(formatter.run(arg));
334+
match args.fmt {
335+
None => {
336+
// We can use default formatting parameters for all arguments.
337+
for _ in range(0, args.args.len()) {
338+
try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
339+
try!(formatter.run(&DEFAULT_ARGUMENT));
340+
}
341+
}
342+
Some(fmt) => {
343+
// Every spec has a corresponding argument that is preceded by
344+
// a string piece.
345+
for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
346+
try!(formatter.buf.write(piece.as_bytes()));
347+
try!(formatter.run(arg));
348+
}
349+
}
305350
}
306351

352+
// There can be only one trailing string piece left.
307353
match pieces.next() {
308354
Some(piece) => {
309355
try!(formatter.buf.write(piece.as_bytes()));

branches/snap-stage3/src/libsyntax/ext/format.rs

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ struct Context<'a, 'b:'a> {
5656
pieces: Vec<Gc<ast::Expr>>,
5757
/// Collection of string literals
5858
str_pieces: Vec<Gc<ast::Expr>>,
59+
/// Stays `true` if all formatting parameters are default (as in "{}{}").
60+
all_pieces_simple: bool,
61+
5962
name_positions: HashMap<String, uint>,
6063
method_statics: Vec<Gc<ast::Item>>,
6164

@@ -383,7 +386,6 @@ impl<'a, 'b> Context<'a, 'b> {
383386
/// Translate a `parse::Piece` to a static `rt::Argument` or append
384387
/// to the `literal` string.
385388
fn trans_piece(&mut self, piece: &parse::Piece) -> Option<Gc<ast::Expr>> {
386-
// let mut is_not_default = true;
387389
let sp = self.fmtsp;
388390
match *piece {
389391
parse::String(s) => {
@@ -416,8 +418,25 @@ impl<'a, 'b> Context<'a, 'b> {
416418
}
417419
};
418420

419-
// Translate the format
421+
let simple_arg = parse::Argument {
422+
position: parse::ArgumentNext,
423+
format: parse::FormatSpec {
424+
fill: arg.format.fill,
425+
align: parse::AlignUnknown,
426+
flags: 0,
427+
precision: parse::CountImplied,
428+
width: parse::CountImplied,
429+
ty: arg.format.ty
430+
}
431+
};
432+
420433
let fill = match arg.format.fill { Some(c) => c, None => ' ' };
434+
435+
if *arg != simple_arg || fill != ' ' {
436+
self.all_pieces_simple = false;
437+
}
438+
439+
// Translate the format
421440
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
422441
let align = match arg.format.align {
423442
parse::AlignLeft => {
@@ -453,6 +472,26 @@ impl<'a, 'b> Context<'a, 'b> {
453472
}
454473
}
455474

475+
fn item_static_array(&self,
476+
name: ast::Ident,
477+
piece_ty: Gc<ast::Ty>,
478+
pieces: Vec<Gc<ast::Expr>>)
479+
-> ast::Stmt
480+
{
481+
let pieces_len = self.ecx.expr_uint(self.fmtsp, pieces.len());
482+
let fmt = self.ecx.expr_vec(self.fmtsp, pieces);
483+
let ty = ast::TyFixedLengthVec(
484+
piece_ty,
485+
pieces_len
486+
);
487+
let ty = self.ecx.ty(self.fmtsp, ty);
488+
let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
489+
let item = self.ecx.item(self.fmtsp, name,
490+
self.static_attrs(), st);
491+
let decl = respan(self.fmtsp, ast::DeclItem(item));
492+
respan(self.fmtsp, ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID))
493+
}
494+
456495
/// Actually builds the expression which the iformat! block will be expanded
457496
/// to
458497
fn to_expr(&self, invocation: Invocation) -> Gc<ast::Expr> {
@@ -471,54 +510,31 @@ impl<'a, 'b> Context<'a, 'b> {
471510

472511
// Next, build up the static array which will become our precompiled
473512
// format "string"
474-
let fmt = self.ecx.expr_vec(self.fmtsp, self.str_pieces.clone());
475-
let piece_ty = self.ecx.ty_rptr(self.fmtsp,
476-
self.ecx.ty_ident(self.fmtsp,
477-
self.ecx.ident_of("str")),
478-
Some(self.ecx.lifetime(self.fmtsp,
479-
self.ecx.ident_of(
480-
"'static").name)),
481-
ast::MutImmutable);
482-
483-
let ty = ast::TyFixedLengthVec(
484-
piece_ty,
485-
self.ecx.expr_uint(self.fmtsp, self.str_pieces.len())
486-
);
487-
let ty = self.ecx.ty(self.fmtsp, ty);
488-
let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
489513
let static_str_name = self.ecx.ident_of("__STATIC_FMTSTR");
490-
let item = self.ecx.item(self.fmtsp, static_str_name,
491-
self.static_attrs(), st);
492-
let decl = respan(self.fmtsp, ast::DeclItem(item));
493-
lets.push(box(GC) respan(self.fmtsp,
494-
ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID)));
495-
496-
// Then, build up the static array which will become our precompiled
497-
// format "string"
498-
let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
499-
let piece_ty = self.ecx.ty_path(self.ecx.path_all(
514+
let static_lifetime = self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("'static").name);
515+
let piece_ty = self.ecx.ty_rptr(
500516
self.fmtsp,
501-
true, vec!(
502-
self.ecx.ident_of("std"),
503-
self.ecx.ident_of("fmt"),
504-
self.ecx.ident_of("rt"),
505-
self.ecx.ident_of("Argument")),
506-
vec!(self.ecx.lifetime(self.fmtsp,
507-
self.ecx.ident_of("'static").name)),
508-
Vec::new()
509-
), None);
510-
let ty = ast::TyFixedLengthVec(
511-
piece_ty,
512-
self.ecx.expr_uint(self.fmtsp, self.pieces.len())
513-
);
514-
let ty = self.ecx.ty(self.fmtsp, ty);
515-
let st = ast::ItemStatic(ty, ast::MutImmutable, fmt);
517+
self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")),
518+
Some(static_lifetime),
519+
ast::MutImmutable);
520+
lets.push(box(GC) self.item_static_array(static_str_name,
521+
piece_ty,
522+
self.str_pieces.clone()));
523+
524+
// Then, build up the static array which will store our precompiled
525+
// nonstandard placeholders, if there are any.
516526
let static_args_name = self.ecx.ident_of("__STATIC_FMTARGS");
517-
let item = self.ecx.item(self.fmtsp, static_args_name,
518-
self.static_attrs(), st);
519-
let decl = respan(self.fmtsp, ast::DeclItem(item));
520-
lets.push(box(GC) respan(self.fmtsp,
521-
ast::StmtDecl(box(GC) decl, ast::DUMMY_NODE_ID)));
527+
if !self.all_pieces_simple {
528+
let piece_ty = self.ecx.ty_path(self.ecx.path_all(
529+
self.fmtsp,
530+
true, self.rtpath("Argument"),
531+
vec![static_lifetime],
532+
vec![]
533+
), None);
534+
lets.push(box(GC) self.item_static_array(static_args_name,
535+
piece_ty,
536+
self.pieces.clone()));
537+
}
522538

523539
// Right now there is a bug such that for the expression:
524540
// foo(bar(&1))
@@ -565,13 +581,20 @@ impl<'a, 'b> Context<'a, 'b> {
565581

566582
// Now create the fmt::Arguments struct with all our locals we created.
567583
let pieces = self.ecx.expr_ident(self.fmtsp, static_str_name);
568-
let fmt = self.ecx.expr_ident(self.fmtsp, static_args_name);
569584
let args_slice = self.ecx.expr_ident(self.fmtsp, slicename);
585+
586+
let (fn_name, fn_args) = if self.all_pieces_simple {
587+
("new", vec![pieces, args_slice])
588+
} else {
589+
let fmt = self.ecx.expr_ident(self.fmtsp, static_args_name);
590+
("with_placeholders", vec![pieces, fmt, args_slice])
591+
};
592+
570593
let result = self.ecx.expr_call_global(self.fmtsp, vec!(
571594
self.ecx.ident_of("std"),
572595
self.ecx.ident_of("fmt"),
573596
self.ecx.ident_of("Arguments"),
574-
self.ecx.ident_of("new")), vec!(pieces, fmt, args_slice));
597+
self.ecx.ident_of(fn_name)), fn_args);
575598

576599
// We did all the work of making sure that the arguments
577600
// structure is safe, so we can safely have an unsafe block.
@@ -741,6 +764,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
741764
literal: String::new(),
742765
pieces: Vec::new(),
743766
str_pieces: Vec::new(),
767+
all_pieces_simple: true,
744768
method_statics: Vec::new(),
745769
fmtsp: sp,
746770
};

0 commit comments

Comments
 (0)