2013-07-29 03:12:41 -05:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-06 02:05:53 -06:00
|
|
|
use self::ArgumentType::*;
|
|
|
|
use self::Position::*;
|
|
|
|
|
2013-07-29 03:12:41 -05:00
|
|
|
use ast;
|
2013-08-31 11:13:04 -05:00
|
|
|
use codemap::{Span, respan};
|
2013-07-29 03:12:41 -05:00
|
|
|
use ext::base::*;
|
|
|
|
use ext::base;
|
|
|
|
use ext::build::AstBuilder;
|
2014-08-18 10:29:44 -05:00
|
|
|
use fmt_macros as parse;
|
2015-04-03 03:27:04 -05:00
|
|
|
use fold::Folder;
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
use parse::token::special_idents;
|
2014-01-08 12:35:15 -06:00
|
|
|
use parse::token;
|
2014-09-13 11:06:01 -05:00
|
|
|
use ptr::P;
|
2014-02-19 21:29:58 -06:00
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
use std::collections::HashMap;
|
2014-12-30 12:51:18 -06:00
|
|
|
use std::iter::repeat;
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2015-01-03 21:54:18 -06:00
|
|
|
#[derive(PartialEq)]
|
2013-07-29 03:12:41 -05:00
|
|
|
enum ArgumentType {
|
2014-12-20 15:37:25 -06:00
|
|
|
Known(String),
|
2014-09-20 08:37:14 -05:00
|
|
|
Unsigned
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
|
2013-12-25 23:55:05 -06:00
|
|
|
enum Position {
|
2015-01-17 17:33:05 -06:00
|
|
|
Exact(usize),
|
2014-12-20 15:37:25 -06:00
|
|
|
Named(String),
|
2013-12-25 23:55:05 -06:00
|
|
|
}
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
struct Context<'a, 'b:'a> {
|
2014-03-09 09:54:34 -05:00
|
|
|
ecx: &'a mut ExtCtxt<'b>,
|
2015-04-10 06:11:21 -05:00
|
|
|
/// The macro's call site. References to unstable formatting internals must
|
|
|
|
/// use this span to pass the stability checker.
|
|
|
|
macsp: Span,
|
|
|
|
/// The span of the format string literal.
|
2013-08-31 11:13:04 -05:00
|
|
|
fmtsp: Span,
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-06-09 15:12:30 -05:00
|
|
|
/// Parsed argument expressions and the types that we've found so far for
|
|
|
|
/// them.
|
2014-09-13 11:06:01 -05:00
|
|
|
args: Vec<P<ast::Expr>>,
|
2014-02-28 15:09:09 -06:00
|
|
|
arg_types: Vec<Option<ArgumentType>>,
|
2014-06-09 15:12:30 -05:00
|
|
|
/// Parsed named expressions and the types that we've found for them so far.
|
|
|
|
/// Note that we keep a side-array of the ordering of the named arguments
|
|
|
|
/// found to be sure that we can translate them in the same order that they
|
|
|
|
/// were declared in.
|
2014-12-20 15:37:25 -06:00
|
|
|
names: HashMap<String, P<ast::Expr>>,
|
|
|
|
name_types: HashMap<String, ArgumentType>,
|
|
|
|
name_ordering: Vec<String>,
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-08-21 08:34:00 -05:00
|
|
|
/// The latest consecutive literal strings, or empty if there weren't any.
|
2014-12-20 15:37:25 -06:00
|
|
|
literal: String,
|
2014-07-20 09:31:43 -05:00
|
|
|
|
2014-08-21 08:34:00 -05:00
|
|
|
/// Collection of the compiled `rt::Argument` structures
|
2014-09-13 11:06:01 -05:00
|
|
|
pieces: Vec<P<ast::Expr>>,
|
2014-08-21 08:34:00 -05:00
|
|
|
/// Collection of string literals
|
2014-09-13 11:06:01 -05:00
|
|
|
str_pieces: Vec<P<ast::Expr>>,
|
2014-08-25 08:26:18 -05:00
|
|
|
/// Stays `true` if all formatting parameters are default (as in "{}{}").
|
|
|
|
all_pieces_simple: bool,
|
|
|
|
|
2015-01-17 17:33:05 -06:00
|
|
|
name_positions: HashMap<String, usize>,
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-06-09 15:12:30 -05:00
|
|
|
/// Updated as arguments are consumed or methods are entered
|
2015-01-17 17:33:05 -06:00
|
|
|
nest_level: usize,
|
|
|
|
next_arg: usize,
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
|
2014-02-05 15:50:36 -06:00
|
|
|
/// Parses the arguments from the given list of tokens, returning None
|
|
|
|
/// if there's a parse error so we can continue parsing other format!
|
|
|
|
/// expressions.
|
|
|
|
///
|
2014-12-21 03:28:18 -06:00
|
|
|
/// If parsing succeeds, the return value is:
|
2014-02-05 15:50:36 -06:00
|
|
|
///
|
2014-02-27 19:07:27 -06:00
|
|
|
/// Some((fmtstr, unnamed arguments, ordering of named arguments,
|
|
|
|
/// named arguments))
|
2014-12-21 03:28:18 -06:00
|
|
|
fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|
|
|
-> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, Vec<String>,
|
|
|
|
HashMap<String, P<ast::Expr>>)> {
|
2014-02-28 15:09:09 -06:00
|
|
|
let mut args = Vec::new();
|
2014-12-20 15:37:25 -06:00
|
|
|
let mut names = HashMap::<String, P<ast::Expr>>::new();
|
2014-02-28 14:54:01 -06:00
|
|
|
let mut order = Vec::new();
|
2014-02-05 15:50:36 -06:00
|
|
|
|
2014-07-03 04:42:24 -05:00
|
|
|
let mut p = ecx.new_parser_from_tts(tts);
|
2013-08-20 02:40:27 -05:00
|
|
|
|
2014-10-27 03:22:52 -05:00
|
|
|
if p.token == token::Eof {
|
2014-02-05 15:50:36 -06:00
|
|
|
ecx.span_err(sp, "requires at least a format string argument");
|
2014-12-21 03:28:18 -06:00
|
|
|
return None;
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
|
|
|
let fmtstr = p.parse_expr();
|
|
|
|
let mut named = false;
|
2014-10-27 03:22:52 -05:00
|
|
|
while p.token != token::Eof {
|
2015-03-28 16:58:51 -05:00
|
|
|
if !panictry!(p.eat(&token::Comma)) {
|
2014-02-05 15:50:36 -06:00
|
|
|
ecx.span_err(sp, "expected token: `,`");
|
2014-12-21 03:28:18 -06:00
|
|
|
return None;
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2014-10-27 03:22:52 -05:00
|
|
|
if p.token == token::Eof { break } // accept trailing commas
|
2014-10-27 07:33:30 -05:00
|
|
|
if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) {
|
2014-02-05 15:50:36 -06:00
|
|
|
named = true;
|
|
|
|
let ident = match p.token {
|
2014-10-27 03:22:52 -05:00
|
|
|
token::Ident(i, _) => {
|
2015-03-28 16:58:51 -05:00
|
|
|
panictry!(p.bump());
|
2014-02-05 15:50:36 -06:00
|
|
|
i
|
|
|
|
}
|
|
|
|
_ if named => {
|
|
|
|
ecx.span_err(p.span,
|
|
|
|
"expected ident, positional arguments \
|
|
|
|
cannot follow named arguments");
|
2014-12-21 03:28:18 -06:00
|
|
|
return None;
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ecx.span_err(p.span,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("expected ident for named argument, found `{}`",
|
2015-02-20 13:08:14 -06:00
|
|
|
p.this_token_to_string()));
|
2014-12-21 03:28:18 -06:00
|
|
|
return None;
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
|
|
|
};
|
2014-02-13 23:07:09 -06:00
|
|
|
let interned_name = token::get_ident(ident);
|
2015-02-18 13:48:57 -06:00
|
|
|
let name = &interned_name[..];
|
2015-02-03 16:31:06 -06:00
|
|
|
|
2015-03-28 16:58:51 -05:00
|
|
|
panictry!(p.expect(&token::Eq));
|
2014-02-05 15:50:36 -06:00
|
|
|
let e = p.parse_expr();
|
2014-11-12 17:51:51 -06:00
|
|
|
match names.get(name) {
|
2014-02-05 15:50:36 -06:00
|
|
|
None => {}
|
|
|
|
Some(prev) => {
|
2014-05-16 12:45:16 -05:00
|
|
|
ecx.span_err(e.span,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("duplicate argument named `{}`",
|
2015-02-20 13:08:14 -06:00
|
|
|
name));
|
2014-02-05 15:50:36 -06:00
|
|
|
ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
|
|
|
|
continue
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
2014-05-25 05:17:19 -05:00
|
|
|
order.push(name.to_string());
|
|
|
|
names.insert(name.to_string(), e);
|
2014-02-05 15:50:36 -06:00
|
|
|
} else {
|
|
|
|
args.push(p.parse_expr());
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
2014-12-21 03:28:18 -06:00
|
|
|
Some((fmtstr, args, order, names))
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-03-09 09:54:34 -05:00
|
|
|
impl<'a, 'b> Context<'a, 'b> {
|
2013-07-29 03:12:41 -05:00
|
|
|
/// Verifies one piece of a parse string. All errors are not emitted as
|
|
|
|
/// fatal so we can continue giving errors about this and possibly other
|
|
|
|
/// format strings.
|
|
|
|
fn verify_piece(&mut self, p: &parse::Piece) {
|
|
|
|
match *p {
|
2013-11-28 14:22:53 -06:00
|
|
|
parse::String(..) => {}
|
2014-09-11 00:07:49 -05:00
|
|
|
parse::NextArgument(ref arg) => {
|
2013-08-10 02:28:47 -05:00
|
|
|
// width/precision first, if they have implicit positional
|
|
|
|
// parameters it makes more sense to consume them first.
|
|
|
|
self.verify_count(arg.format.width);
|
|
|
|
self.verify_count(arg.format.precision);
|
|
|
|
|
|
|
|
// argument second, if it's an implicit positional parameter
|
|
|
|
// it's written second, so it should come after width/precision.
|
2013-07-29 03:12:41 -05:00
|
|
|
let pos = match arg.position {
|
|
|
|
parse::ArgumentNext => {
|
|
|
|
let i = self.next_arg;
|
|
|
|
if self.check_positional_ok() {
|
|
|
|
self.next_arg += 1;
|
|
|
|
}
|
2013-12-25 23:55:05 -06:00
|
|
|
Exact(i)
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2013-12-25 23:55:05 -06:00
|
|
|
parse::ArgumentIs(i) => Exact(i),
|
2014-05-25 05:17:19 -05:00
|
|
|
parse::ArgumentNamed(s) => Named(s.to_string()),
|
2013-07-29 03:12:41 -05:00
|
|
|
};
|
|
|
|
|
2014-05-28 11:24:28 -05:00
|
|
|
let ty = Known(arg.format.ty.to_string());
|
|
|
|
self.verify_arg_type(pos, ty);
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn verify_count(&mut self, c: parse::Count) {
|
|
|
|
match c {
|
2013-11-28 14:22:53 -06:00
|
|
|
parse::CountImplied | parse::CountIs(..) => {}
|
2013-07-29 03:12:41 -05:00
|
|
|
parse::CountIsParam(i) => {
|
2013-12-25 23:55:05 -06:00
|
|
|
self.verify_arg_type(Exact(i), Unsigned);
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2013-10-12 22:00:58 -05:00
|
|
|
parse::CountIsName(s) => {
|
2014-05-25 05:17:19 -05:00
|
|
|
self.verify_arg_type(Named(s.to_string()), Unsigned);
|
2013-10-12 22:00:58 -05:00
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
parse::CountIsNextParam => {
|
|
|
|
if self.check_positional_ok() {
|
2014-06-13 22:48:09 -05:00
|
|
|
let next_arg = self.next_arg;
|
|
|
|
self.verify_arg_type(Exact(next_arg), Unsigned);
|
2013-07-29 03:12:41 -05:00
|
|
|
self.next_arg += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_positional_ok(&mut self) -> bool {
|
|
|
|
if self.nest_level != 0 {
|
|
|
|
self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
|
|
|
|
arguments nested inside methods");
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-20 15:37:25 -06:00
|
|
|
fn describe_num_args(&self) -> String {
|
2014-07-18 13:39:38 -05:00
|
|
|
match self.args.len() {
|
|
|
|
0 => "no arguments given".to_string(),
|
|
|
|
1 => "there is 1 argument".to_string(),
|
|
|
|
x => format!("there are {} arguments", x),
|
2014-07-18 11:34:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-25 23:55:05 -06:00
|
|
|
fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
|
2013-07-29 03:12:41 -05:00
|
|
|
match arg {
|
2013-12-25 23:55:05 -06:00
|
|
|
Exact(arg) => {
|
2014-05-04 13:48:16 -05:00
|
|
|
if self.args.len() <= arg {
|
2014-11-17 13:29:38 -06:00
|
|
|
let msg = format!("invalid reference to argument `{}` ({})",
|
2014-07-18 11:34:49 -05:00
|
|
|
arg, self.describe_num_args());
|
|
|
|
|
2015-02-18 13:48:57 -06:00
|
|
|
self.ecx.span_err(self.fmtsp, &msg[..]);
|
2013-07-29 03:12:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2014-01-21 12:08:10 -06:00
|
|
|
{
|
2014-10-15 01:05:01 -05:00
|
|
|
let arg_type = match self.arg_types[arg] {
|
|
|
|
None => None,
|
|
|
|
Some(ref x) => Some(x)
|
2014-01-21 12:08:10 -06:00
|
|
|
};
|
2014-10-15 01:05:01 -05:00
|
|
|
self.verify_same(self.args[arg].span, &ty, arg_type);
|
2014-01-21 12:08:10 -06:00
|
|
|
}
|
2014-10-15 01:05:01 -05:00
|
|
|
if self.arg_types[arg].is_none() {
|
2014-10-23 10:42:21 -05:00
|
|
|
self.arg_types[arg] = Some(ty);
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-25 23:55:05 -06:00
|
|
|
Named(name) => {
|
2014-11-06 11:25:16 -06:00
|
|
|
let span = match self.names.get(&name) {
|
2013-07-29 03:12:41 -05:00
|
|
|
Some(e) => e.span,
|
|
|
|
None => {
|
2013-09-27 23:01:58 -05:00
|
|
|
let msg = format!("there is no argument named `{}`", name);
|
2015-02-18 13:48:57 -06:00
|
|
|
self.ecx.span_err(self.fmtsp, &msg[..]);
|
2013-07-29 03:12:41 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
2014-11-06 11:25:16 -06:00
|
|
|
self.verify_same(span, &ty, self.name_types.get(&name));
|
2013-09-26 15:44:54 -05:00
|
|
|
if !self.name_types.contains_key(&name) {
|
2014-01-21 12:08:10 -06:00
|
|
|
self.name_types.insert(name.clone(), ty);
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
// Assign this named argument a slot in the arguments array if
|
|
|
|
// it hasn't already been assigned a slot.
|
|
|
|
if !self.name_positions.contains_key(&name) {
|
|
|
|
let slot = self.name_positions.len();
|
|
|
|
self.name_positions.insert(name, slot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// When we're keeping track of the types that are declared for certain
|
|
|
|
/// arguments, we assume that `None` means we haven't seen this argument
|
|
|
|
/// yet, `Some(None)` means that we've seen the argument, but no format was
|
|
|
|
/// specified, and `Some(Some(x))` means that the argument was declared to
|
|
|
|
/// have type `x`.
|
|
|
|
///
|
|
|
|
/// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
|
|
|
|
/// that: `Some(None) == Some(Some(x))`
|
2014-01-21 12:08:10 -06:00
|
|
|
fn verify_same(&self,
|
|
|
|
sp: Span,
|
|
|
|
ty: &ArgumentType,
|
|
|
|
before: Option<&ArgumentType>) {
|
2013-07-29 03:12:41 -05:00
|
|
|
let cur = match before {
|
2013-09-26 15:44:54 -05:00
|
|
|
None => return,
|
2013-07-29 03:12:41 -05:00
|
|
|
Some(t) => t,
|
|
|
|
};
|
2014-01-21 12:08:10 -06:00
|
|
|
if *ty == *cur {
|
|
|
|
return
|
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
match (cur, ty) {
|
2014-01-21 12:08:10 -06:00
|
|
|
(&Known(ref cur), &Known(ref ty)) => {
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.span_err(sp,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("argument redeclared with type `{}` when \
|
2014-01-21 12:08:10 -06:00
|
|
|
it was previously `{}`",
|
|
|
|
*ty,
|
2015-02-20 13:08:14 -06:00
|
|
|
*cur));
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2014-01-21 12:08:10 -06:00
|
|
|
(&Known(ref cur), _) => {
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.span_err(sp,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("argument used to format with `{}` was \
|
2013-09-27 23:01:58 -05:00
|
|
|
attempted to not be used for formatting",
|
2015-02-20 13:08:14 -06:00
|
|
|
*cur));
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2014-01-21 12:08:10 -06:00
|
|
|
(_, &Known(ref ty)) => {
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.span_err(sp,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("argument previously used as a format \
|
2013-09-27 23:01:58 -05:00
|
|
|
argument attempted to be used as `{}`",
|
2015-02-20 13:08:14 -06:00
|
|
|
*ty));
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
(_, _) => {
|
|
|
|
self.ecx.span_err(sp, "argument declared with multiple formats");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-13 11:06:01 -05:00
|
|
|
fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec<ast::Ident> {
|
2014-09-07 16:57:26 -05:00
|
|
|
vec![ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("rt"),
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
ecx.ident_of("v1"), ecx.ident_of(s)]
|
2014-02-07 13:45:46 -06:00
|
|
|
}
|
|
|
|
|
2014-09-13 11:06:01 -05:00
|
|
|
fn trans_count(&self, c: parse::Count) -> P<ast::Expr> {
|
2015-04-10 06:11:21 -05:00
|
|
|
let sp = self.macsp;
|
2015-02-01 11:44:15 -06:00
|
|
|
let count = |c, arg| {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
let mut path = Context::rtpath(self.ecx, "Count");
|
|
|
|
path.push(self.ecx.ident_of(c));
|
|
|
|
match arg {
|
|
|
|
Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
|
|
|
|
None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
};
|
|
|
|
match c {
|
|
|
|
parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
|
2014-02-07 13:45:46 -06:00
|
|
|
parse::CountIsParam(i) => {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
count("Param", Some(self.ecx.expr_usize(sp, i)))
|
2014-02-07 13:45:46 -06:00
|
|
|
}
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
parse::CountImplied => count("Implied", None),
|
|
|
|
parse::CountIsNextParam => count("NextParam", None),
|
2014-02-07 13:45:46 -06:00
|
|
|
parse::CountIsName(n) => {
|
2014-11-12 17:51:51 -06:00
|
|
|
let i = match self.name_positions.get(n) {
|
2014-02-07 13:45:46 -06:00
|
|
|
Some(&i) => i,
|
|
|
|
None => 0, // error already emitted elsewhere
|
|
|
|
};
|
|
|
|
let i = i + self.args.len();
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
count("Param", Some(self.ecx.expr_usize(sp, i)))
|
2014-02-07 13:45:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 08:34:00 -05:00
|
|
|
/// Translate the accumulated string literals to a literal expression
|
2014-09-13 11:06:01 -05:00
|
|
|
fn trans_literal_string(&mut self) -> P<ast::Expr> {
|
2014-07-20 09:31:43 -05:00
|
|
|
let sp = self.fmtsp;
|
2015-02-20 13:08:14 -06:00
|
|
|
let s = token::intern_and_get_ident(&self.literal);
|
2014-08-21 08:34:00 -05:00
|
|
|
self.literal.clear();
|
|
|
|
self.ecx.expr_str(sp, s)
|
2014-07-20 09:31:43 -05:00
|
|
|
}
|
|
|
|
|
2014-08-21 08:34:00 -05:00
|
|
|
/// Translate a `parse::Piece` to a static `rt::Argument` or append
|
|
|
|
/// to the `literal` string.
|
2014-09-13 11:06:01 -05:00
|
|
|
fn trans_piece(&mut self, piece: &parse::Piece) -> Option<P<ast::Expr>> {
|
2015-04-10 06:11:21 -05:00
|
|
|
let sp = self.macsp;
|
2013-07-29 03:12:41 -05:00
|
|
|
match *piece {
|
|
|
|
parse::String(s) => {
|
2014-08-21 08:34:00 -05:00
|
|
|
self.literal.push_str(s);
|
2014-07-20 09:31:43 -05:00
|
|
|
None
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2014-09-11 00:07:49 -05:00
|
|
|
parse::NextArgument(ref arg) => {
|
2013-07-29 03:12:41 -05:00
|
|
|
// Translate the position
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
let pos = {
|
2015-02-01 11:44:15 -06:00
|
|
|
let pos = |c, arg| {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
let mut path = Context::rtpath(self.ecx, "Position");
|
|
|
|
path.push(self.ecx.ident_of(c));
|
|
|
|
match arg {
|
|
|
|
Some(i) => {
|
|
|
|
let arg = self.ecx.expr_usize(sp, i);
|
|
|
|
self.ecx.expr_call_global(sp, path, vec![arg])
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.ecx.expr_path(self.ecx.path_global(sp, path))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match arg.position {
|
|
|
|
// These two have a direct mapping
|
|
|
|
parse::ArgumentNext => pos("Next", None),
|
|
|
|
parse::ArgumentIs(i) => pos("At", Some(i)),
|
|
|
|
|
|
|
|
// Named arguments are converted to positional arguments
|
|
|
|
// at the end of the list of arguments
|
|
|
|
parse::ArgumentNamed(n) => {
|
|
|
|
let i = match self.name_positions.get(n) {
|
|
|
|
Some(&i) => i,
|
|
|
|
None => 0, // error already emitted elsewhere
|
|
|
|
};
|
|
|
|
let i = i + self.args.len();
|
|
|
|
pos("At", Some(i))
|
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-08-25 08:26:18 -05:00
|
|
|
let simple_arg = parse::Argument {
|
|
|
|
position: parse::ArgumentNext,
|
|
|
|
format: parse::FormatSpec {
|
|
|
|
fill: arg.format.fill,
|
|
|
|
align: parse::AlignUnknown,
|
|
|
|
flags: 0,
|
|
|
|
precision: parse::CountImplied,
|
|
|
|
width: parse::CountImplied,
|
|
|
|
ty: arg.format.ty
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-29 03:12:41 -05:00
|
|
|
let fill = match arg.format.fill { Some(c) => c, None => ' ' };
|
2014-08-25 08:26:18 -05:00
|
|
|
|
|
|
|
if *arg != simple_arg || fill != ' ' {
|
|
|
|
self.all_pieces_simple = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate the format
|
2014-05-01 08:35:06 -05:00
|
|
|
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
|
2015-02-01 11:44:15 -06:00
|
|
|
let align = |name| {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
let mut p = Context::rtpath(self.ecx, "Alignment");
|
|
|
|
p.push(self.ecx.ident_of(name));
|
|
|
|
self.ecx.path_global(sp, p)
|
|
|
|
};
|
2013-07-29 03:12:41 -05:00
|
|
|
let align = match arg.format.align {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
parse::AlignLeft => align("Left"),
|
|
|
|
parse::AlignRight => align("Right"),
|
|
|
|
parse::AlignCenter => align("Center"),
|
|
|
|
parse::AlignUnknown => align("Unknown"),
|
2013-07-29 03:12:41 -05:00
|
|
|
};
|
2013-08-10 18:50:42 -05:00
|
|
|
let align = self.ecx.expr_path(align);
|
2015-02-22 21:07:38 -06:00
|
|
|
let flags = self.ecx.expr_u32(sp, arg.format.flags);
|
2014-02-07 13:45:46 -06:00
|
|
|
let prec = self.trans_count(arg.format.precision);
|
|
|
|
let width = self.trans_count(arg.format.width);
|
2014-09-13 11:06:01 -05:00
|
|
|
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
|
2014-02-28 15:09:09 -06:00
|
|
|
let fmt = self.ecx.expr_struct(sp, path, vec!(
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
|
2013-08-10 18:50:42 -05:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
|
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
|
2014-02-28 15:09:09 -06:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-09-13 11:06:01 -05:00
|
|
|
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument"));
|
2014-08-21 08:34:00 -05:00
|
|
|
Some(self.ecx.expr_struct(sp, path, vec!(
|
2013-07-29 03:12:41 -05:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
|
2014-08-21 08:34:00 -05:00
|
|
|
self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt))))
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 08:16:16 -06:00
|
|
|
fn static_array(ecx: &mut ExtCtxt,
|
|
|
|
name: &str,
|
|
|
|
piece_ty: P<ast::Ty>,
|
|
|
|
pieces: Vec<P<ast::Expr>>)
|
|
|
|
-> P<ast::Expr> {
|
2015-04-10 06:11:21 -05:00
|
|
|
let sp = piece_ty.span;
|
|
|
|
let ty = ecx.ty_rptr(sp,
|
|
|
|
ecx.ty(sp, ast::TyVec(piece_ty)),
|
|
|
|
Some(ecx.lifetime(sp, special_idents::static_lifetime.name)),
|
2014-12-19 08:16:16 -06:00
|
|
|
ast::MutImmutable);
|
2015-04-10 06:11:21 -05:00
|
|
|
let slice = ecx.expr_vec_slice(sp, pieces);
|
2014-12-19 08:16:16 -06:00
|
|
|
let st = ast::ItemStatic(ty, ast::MutImmutable, slice);
|
|
|
|
|
|
|
|
let name = ecx.ident_of(name);
|
2015-04-10 06:11:21 -05:00
|
|
|
let item = ecx.item(sp, name, vec![], st);
|
|
|
|
let decl = respan(sp, ast::DeclItem(item));
|
2014-12-19 08:16:16 -06:00
|
|
|
|
|
|
|
// Wrap the declaration in a block so that it forms a single expression.
|
2015-04-10 06:11:21 -05:00
|
|
|
ecx.expr_block(ecx.block(sp,
|
|
|
|
vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))],
|
|
|
|
Some(ecx.expr_ident(sp, name))))
|
2014-08-25 08:26:18 -05:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:01:58 -05:00
|
|
|
/// Actually builds the expression which the iformat! block will be expanded
|
2013-07-29 03:12:41 -05:00
|
|
|
/// to
|
2014-12-21 03:28:18 -06:00
|
|
|
fn into_expr(mut self) -> P<ast::Expr> {
|
2014-02-28 15:09:09 -06:00
|
|
|
let mut locals = Vec::new();
|
2014-12-30 12:51:18 -06:00
|
|
|
let mut names: Vec<_> = repeat(None).take(self.name_positions.len()).collect();
|
2014-02-28 15:09:09 -06:00
|
|
|
let mut pats = Vec::new();
|
|
|
|
let mut heads = Vec::new();
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2014-12-18 17:31:02 -06:00
|
|
|
// First, build up the static array which will become our precompiled
|
2013-07-29 03:12:41 -05:00
|
|
|
// format "string"
|
2014-12-19 08:16:16 -06:00
|
|
|
let static_lifetime = self.ecx.lifetime(self.fmtsp, special_idents::static_lifetime.name);
|
2014-08-25 08:26:18 -05:00
|
|
|
let piece_ty = self.ecx.ty_rptr(
|
2013-08-28 04:22:45 -05:00
|
|
|
self.fmtsp,
|
2014-08-25 08:26:18 -05:00
|
|
|
self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")),
|
|
|
|
Some(static_lifetime),
|
|
|
|
ast::MutImmutable);
|
2014-12-19 08:16:16 -06:00
|
|
|
let pieces = Context::static_array(self.ecx,
|
|
|
|
"__STATIC_FMTSTR",
|
|
|
|
piece_ty,
|
|
|
|
self.str_pieces);
|
|
|
|
|
2013-07-29 03:12:41 -05:00
|
|
|
|
|
|
|
// Right now there is a bug such that for the expression:
|
|
|
|
// foo(bar(&1))
|
|
|
|
// the lifetime of `1` doesn't outlast the call to `bar`, so it's not
|
2014-09-02 00:35:58 -05:00
|
|
|
// valid for the call to `foo`. To work around this all arguments to the
|
2013-09-27 23:01:58 -05:00
|
|
|
// format! string are shoved into locals. Furthermore, we shove the address
|
2013-09-03 01:53:13 -05:00
|
|
|
// of each variable because we don't want to move out of the arguments
|
|
|
|
// passed to this function.
|
2014-09-14 22:27:36 -05:00
|
|
|
for (i, e) in self.args.into_iter().enumerate() {
|
2014-10-15 01:05:01 -05:00
|
|
|
let arg_ty = match self.arg_types[i].as_ref() {
|
2014-09-13 11:06:01 -05:00
|
|
|
Some(ty) => ty,
|
|
|
|
None => continue // error already generated
|
|
|
|
};
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2015-02-20 13:08:14 -06:00
|
|
|
let name = self.ecx.ident_of(&format!("__arg{}", i));
|
2014-02-17 13:32:12 -06:00
|
|
|
pats.push(self.ecx.pat_ident(e.span, name));
|
2015-04-10 06:11:21 -05:00
|
|
|
locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
|
2014-09-13 11:06:01 -05:00
|
|
|
self.ecx.expr_ident(e.span, name)));
|
2014-02-17 13:32:12 -06:00
|
|
|
heads.push(self.ecx.expr_addr_of(e.span, e));
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2015-01-31 11:20:46 -06:00
|
|
|
for name in &self.name_ordering {
|
2014-11-06 11:25:16 -06:00
|
|
|
let e = match self.names.remove(name) {
|
2014-09-13 11:06:01 -05:00
|
|
|
Some(e) => e,
|
|
|
|
None => continue
|
|
|
|
};
|
2014-11-06 11:25:16 -06:00
|
|
|
let arg_ty = match self.name_types.get(name) {
|
2014-09-13 11:06:01 -05:00
|
|
|
Some(ty) => ty,
|
|
|
|
None => continue
|
2014-02-27 19:07:27 -06:00
|
|
|
};
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2015-01-07 10:58:31 -06:00
|
|
|
let lname = self.ecx.ident_of(&format!("__arg{}",
|
2015-02-20 13:08:14 -06:00
|
|
|
*name));
|
2014-02-17 13:32:12 -06:00
|
|
|
pats.push(self.ecx.pat_ident(e.span, lname));
|
2015-03-21 20:15:47 -05:00
|
|
|
names[*self.name_positions.get(name).unwrap()] =
|
2015-04-10 06:11:21 -05:00
|
|
|
Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
|
2014-09-13 11:06:01 -05:00
|
|
|
self.ecx.expr_ident(e.span, lname)));
|
|
|
|
heads.push(self.ecx.expr_addr_of(e.span, e));
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
// Now create a vector containing all the arguments
|
2014-12-03 14:56:39 -06:00
|
|
|
let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap()));
|
2014-01-15 13:39:08 -06:00
|
|
|
|
2014-12-20 13:57:47 -06:00
|
|
|
let args_array = self.ecx.expr_vec(self.fmtsp, args.collect());
|
|
|
|
|
|
|
|
// Constructs an AST equivalent to:
|
|
|
|
//
|
|
|
|
// match (&arg0, &arg1) {
|
|
|
|
// (tmp0, tmp1) => args_array
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// It was:
|
|
|
|
//
|
|
|
|
// let tmp0 = &arg0;
|
|
|
|
// let tmp1 = &arg1;
|
|
|
|
// args_array
|
|
|
|
//
|
|
|
|
// Because of #11585 the new temporary lifetime rule, the enclosing
|
|
|
|
// statements for these temporaries become the let's themselves.
|
|
|
|
// If one or more of them are RefCell's, RefCell borrow() will also
|
|
|
|
// end there; they don't last long enough for args_array to use them.
|
|
|
|
// The match expression solves the scope problem.
|
|
|
|
//
|
|
|
|
// Note, it may also very well be transformed to:
|
|
|
|
//
|
|
|
|
// match arg0 {
|
|
|
|
// ref tmp0 => {
|
|
|
|
// match arg1 => {
|
|
|
|
// ref tmp1 => args_array } } }
|
|
|
|
//
|
|
|
|
// But the nested match expression is proved to perform not as well
|
|
|
|
// as series of let's; the first approach does.
|
|
|
|
let pat = self.ecx.pat_tuple(self.fmtsp, pats);
|
|
|
|
let arm = self.ecx.arm(self.fmtsp, vec!(pat), args_array);
|
|
|
|
let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
|
|
|
|
let result = self.ecx.expr_match(self.fmtsp, head, vec!(arm));
|
|
|
|
|
|
|
|
let args_slice = self.ecx.expr_addr_of(self.fmtsp, result);
|
2014-08-25 08:26:18 -05:00
|
|
|
|
2014-12-20 13:57:47 -06:00
|
|
|
// Now create the fmt::Arguments struct with all our locals we created.
|
2014-08-25 08:26:18 -05:00
|
|
|
let (fn_name, fn_args) = if self.all_pieces_simple {
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
("new_v1", vec![pieces, args_slice])
|
2014-08-25 08:26:18 -05:00
|
|
|
} else {
|
2014-12-19 08:16:16 -06:00
|
|
|
// Build up the static array which will store our precompiled
|
|
|
|
// nonstandard placeholders, if there are any.
|
2015-01-09 17:31:56 -06:00
|
|
|
let piece_ty = self.ecx.ty_path(self.ecx.path_global(
|
2015-04-10 06:11:21 -05:00
|
|
|
self.macsp,
|
2015-01-09 17:31:56 -06:00
|
|
|
Context::rtpath(self.ecx, "Argument")));
|
2014-12-19 08:16:16 -06:00
|
|
|
let fmt = Context::static_array(self.ecx,
|
|
|
|
"__STATIC_FMTARGS",
|
|
|
|
piece_ty,
|
|
|
|
self.pieces);
|
|
|
|
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
("new_v1_formatted", vec![pieces, args_slice, fmt])
|
2014-08-25 08:26:18 -05:00
|
|
|
};
|
|
|
|
|
2015-04-10 06:11:21 -05:00
|
|
|
self.ecx.expr_call_global(self.macsp, vec!(
|
2014-09-07 16:57:26 -05:00
|
|
|
self.ecx.ident_of_std("core"),
|
2013-09-12 21:36:58 -05:00
|
|
|
self.ecx.ident_of("fmt"),
|
|
|
|
self.ecx.ident_of("Arguments"),
|
2014-12-21 03:28:18 -06:00
|
|
|
self.ecx.ident_of(fn_name)), fn_args)
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
|
2015-04-10 06:11:21 -05:00
|
|
|
fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span,
|
2014-09-13 11:06:01 -05:00
|
|
|
ty: &ArgumentType, arg: P<ast::Expr>)
|
|
|
|
-> P<ast::Expr> {
|
2014-10-31 12:07:13 -05:00
|
|
|
let trait_ = match *ty {
|
2014-01-21 12:08:10 -06:00
|
|
|
Known(ref tyname) => {
|
2015-02-18 13:48:57 -06:00
|
|
|
match &tyname[..] {
|
2015-01-20 17:45:07 -06:00
|
|
|
"" => "Display",
|
|
|
|
"?" => "Debug",
|
2014-10-31 12:07:13 -05:00
|
|
|
"e" => "LowerExp",
|
|
|
|
"E" => "UpperExp",
|
|
|
|
"o" => "Octal",
|
|
|
|
"p" => "Pointer",
|
2014-11-17 13:29:38 -06:00
|
|
|
"b" => "Binary",
|
2014-10-31 12:07:13 -05:00
|
|
|
"x" => "LowerHex",
|
|
|
|
"X" => "UpperHex",
|
2013-07-29 03:12:41 -05:00
|
|
|
_ => {
|
2014-09-13 11:06:01 -05:00
|
|
|
ecx.span_err(sp,
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("unknown format trait `{}`",
|
2015-02-20 13:08:14 -06:00
|
|
|
*tyname));
|
2014-10-31 12:07:13 -05:00
|
|
|
"Dummy"
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2013-08-14 22:40:15 -05:00
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
Unsigned => {
|
2015-04-10 06:11:21 -05:00
|
|
|
return ecx.expr_call_global(macsp, vec![
|
2014-09-07 16:57:26 -05:00
|
|
|
ecx.ident_of_std("core"),
|
2014-09-13 11:06:01 -05:00
|
|
|
ecx.ident_of("fmt"),
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
ecx.ident_of("ArgumentV1"),
|
2015-02-22 21:07:38 -06:00
|
|
|
ecx.ident_of("from_usize")], vec![arg])
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
2013-08-14 22:40:15 -05:00
|
|
|
};
|
|
|
|
|
2014-09-13 11:06:01 -05:00
|
|
|
let format_fn = ecx.path_global(sp, vec![
|
2014-09-07 16:57:26 -05:00
|
|
|
ecx.ident_of_std("core"),
|
2014-09-13 11:06:01 -05:00
|
|
|
ecx.ident_of("fmt"),
|
2014-10-31 12:07:13 -05:00
|
|
|
ecx.ident_of(trait_),
|
|
|
|
ecx.ident_of("fmt")]);
|
2015-04-10 06:11:21 -05:00
|
|
|
ecx.expr_call_global(macsp, vec![
|
2014-09-07 16:57:26 -05:00
|
|
|
ecx.ident_of_std("core"),
|
2014-09-13 11:06:01 -05:00
|
|
|
ecx.ident_of("fmt"),
|
std: Stabilize the std::fmt module
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.
There are three primary details used by the `format_args!` macro:
1. `Arguments` - an opaque package of a "compiled format string". This structure
is passed around and the `write` function is the source of truth for
transforming a compiled format string into a string at runtime. This must be
able to be constructed in stable code.
2. `Argument` - an opaque structure representing an argument to a format string.
This is *almost* a trait object as it's just a pointer/function pair, but due
to the function originating from one of many traits, it's not actually a
trait object. Like `Arguments`, this must be constructed from stable code.
3. `fmt::rt` - this module contains the runtime type definitions primarily for
the `rt::Argument` structure. Whenever an argument is formatted with
nonstandard flags, a corresponding `rt::Argument` is generated describing how
the argument is being formatted. This can be used to construct an
`Arguments`.
The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.
The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.
One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md
Specifically, the following changes were made:
* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable
Within the contents of the `fmt::rt::v1` module, the following actions were
taken:
* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.
In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.
In some other modules:
* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)
This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs.
Closes #20661
[breaking-change]
2015-01-13 17:42:53 -06:00
|
|
|
ecx.ident_of("ArgumentV1"),
|
|
|
|
ecx.ident_of("new")], vec![arg, ecx.expr_path(format_fn)])
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 20:46:52 -05:00
|
|
|
pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
|
|
|
|
tts: &[ast::TokenTree])
|
|
|
|
-> Box<base::MacResult+'cx> {
|
syntax: Add a macro, format_args_method!()
Currently, the format_args!() macro takes as its first argument an expression
which is the callee of an ExprCall. This means that if format_args!() is used
with calling a method a closure must be used. Consider this code, however:
format_args!(|args| { foo.writer.write_fmt(args) }, "{}", foo.field)
The closure borrows the entire `foo` structure, disallowing the later borrow of
`foo.field`. To preserve the semantics of the `write!` macro, it is also
impossible to borrow specifically the `writer` field of the `foo` structure
because it must be borrowed mutably, but the `foo` structure is not guaranteed
to be mutable itself.
This new macro is invoked like:
format_args_method!(foo.writer, write_fmt, "{}", foo.field)
This macro will generate an ExprMethodCall which allows the borrow checker to
understand that `writer` and `field` should be borrowed separately.
This macro is not strictly necessary, with DST or possibly UFCS other
workarounds could be used. For now, though, it looks like this is required to
implement the `write!` macro.
2014-05-10 15:53:40 -05:00
|
|
|
|
2014-12-21 03:28:18 -06:00
|
|
|
match parse_args(ecx, sp, tts) {
|
|
|
|
Some((efmt, args, order, names)) => {
|
2015-02-27 13:14:42 -06:00
|
|
|
MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt,
|
syntax: Add a macro, format_args_method!()
Currently, the format_args!() macro takes as its first argument an expression
which is the callee of an ExprCall. This means that if format_args!() is used
with calling a method a closure must be used. Consider this code, however:
format_args!(|args| { foo.writer.write_fmt(args) }, "{}", foo.field)
The closure borrows the entire `foo` structure, disallowing the later borrow of
`foo.field`. To preserve the semantics of the `write!` macro, it is also
impossible to borrow specifically the `writer` field of the `foo` structure
because it must be borrowed mutably, but the `foo` structure is not guaranteed
to be mutable itself.
This new macro is invoked like:
format_args_method!(foo.writer, write_fmt, "{}", foo.field)
This macro will generate an ExprMethodCall which allows the borrow checker to
understand that `writer` and `field` should be borrowed separately.
This macro is not strictly necessary, with DST or possibly UFCS other
workarounds could be used. For now, though, it looks like this is required to
implement the `write!` macro.
2014-05-10 15:53:40 -05:00
|
|
|
args, order, names))
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
2014-12-21 03:28:18 -06:00
|
|
|
None => DummyResult::expr(sp)
|
2014-02-05 15:50:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 03:28:18 -06:00
|
|
|
/// Take the various parts of `format_args!(efmt, args..., name=names...)`
|
|
|
|
/// and construct the appropriate formatting expression.
|
2014-02-05 15:50:36 -06:00
|
|
|
pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
|
2014-09-13 11:06:01 -05:00
|
|
|
efmt: P<ast::Expr>,
|
|
|
|
args: Vec<P<ast::Expr>>,
|
2014-12-21 03:28:18 -06:00
|
|
|
name_ordering: Vec<String>,
|
|
|
|
names: HashMap<String, P<ast::Expr>>)
|
2014-09-13 11:06:01 -05:00
|
|
|
-> P<ast::Expr> {
|
2015-01-26 15:05:07 -06:00
|
|
|
let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect();
|
2015-04-10 06:11:21 -05:00
|
|
|
let macsp = ecx.call_site();
|
2015-04-03 03:27:04 -05:00
|
|
|
// Expand the format literal so that efmt.span will have a backtrace. This
|
|
|
|
// is essential for locating a bug when the format literal is generated in
|
|
|
|
// a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")).
|
|
|
|
let efmt = ecx.expander().fold_expr(efmt);
|
2013-07-29 03:12:41 -05:00
|
|
|
let mut cx = Context {
|
|
|
|
ecx: ecx,
|
2014-02-05 15:50:36 -06:00
|
|
|
args: args,
|
|
|
|
arg_types: arg_types,
|
|
|
|
names: names,
|
2013-07-29 03:12:41 -05:00
|
|
|
name_positions: HashMap::new(),
|
|
|
|
name_types: HashMap::new(),
|
2014-02-27 19:07:27 -06:00
|
|
|
name_ordering: name_ordering,
|
2013-07-29 03:12:41 -05:00
|
|
|
nest_level: 0,
|
|
|
|
next_arg: 0,
|
2014-12-20 15:37:25 -06:00
|
|
|
literal: String::new(),
|
2014-02-28 15:09:09 -06:00
|
|
|
pieces: Vec::new(),
|
2014-08-21 08:34:00 -05:00
|
|
|
str_pieces: Vec::new(),
|
2014-08-25 08:26:18 -05:00
|
|
|
all_pieces_simple: true,
|
2015-04-10 06:11:21 -05:00
|
|
|
macsp: macsp,
|
2015-04-03 03:27:04 -05:00
|
|
|
fmtsp: efmt.span,
|
2013-07-29 03:12:41 -05:00
|
|
|
};
|
2014-06-21 05:39:03 -05:00
|
|
|
let fmt = match expr_to_string(cx.ecx,
|
2014-12-21 03:28:18 -06:00
|
|
|
efmt,
|
|
|
|
"format argument must be a string literal.") {
|
2014-01-17 08:53:10 -06:00
|
|
|
Some((fmt, _)) => fmt,
|
2014-04-15 07:00:14 -05:00
|
|
|
None => return DummyResult::raw_expr(sp)
|
2014-01-17 08:53:10 -06:00
|
|
|
};
|
2013-07-29 03:12:41 -05:00
|
|
|
|
2015-02-04 14:48:12 -06:00
|
|
|
let mut parser = parse::Parser::new(&fmt);
|
2015-02-03 16:31:06 -06:00
|
|
|
|
Remove std::condition
This has been a long time coming. Conditions in rust were initially envisioned
as being a good alternative to error code return pattern. The idea is that all
errors are fatal-by-default, and you can opt-in to handling the error by
registering an error handler.
While sounding nice, conditions ended up having some unforseen shortcomings:
* Actually handling an error has some very awkward syntax:
let mut result = None;
let mut answer = None;
io::io_error::cond.trap(|e| { result = Some(e) }).inside(|| {
answer = Some(some_io_operation());
});
match result {
Some(err) => { /* hit an I/O error */ }
None => {
let answer = answer.unwrap();
/* deal with the result of I/O */
}
}
This pattern can certainly use functions like io::result, but at its core
actually handling conditions is fairly difficult
* The "zero value" of a function is often confusing. One of the main ideas
behind using conditions was to change the signature of I/O functions. Instead
of read_be_u32() returning a result, it returned a u32. Errors were notified
via a condition, and if you caught the condition you understood that the "zero
value" returned is actually a garbage value. These zero values are often
difficult to understand, however.
One case of this is the read_bytes() function. The function takes an integer
length of the amount of bytes to read, and returns an array of that size. The
array may actually be shorter, however, if an error occurred.
Another case is fs::stat(). The theoretical "zero value" is a blank stat
struct, but it's a little awkward to create and return a zero'd out stat
struct on a call to stat().
In general, the return value of functions that can raise error are much more
natural when using a Result as opposed to an always-usable zero-value.
* Conditions impose a necessary runtime requirement on *all* I/O. In theory I/O
is as simple as calling read() and write(), but using conditions imposed the
restriction that a rust local task was required if you wanted to catch errors
with I/O. While certainly an surmountable difficulty, this was always a bit of
a thorn in the side of conditions.
* Functions raising conditions are not always clear that they are raising
conditions. This suffers a similar problem to exceptions where you don't
actually know whether a function raises a condition or not. The documentation
likely explains, but if someone retroactively adds a condition to a function
there's nothing forcing upstream users to acknowledge a new point of task
failure.
* Libaries using I/O are not guaranteed to correctly raise on conditions when an
error occurs. In developing various I/O libraries, it's much easier to just
return `None` from a read rather than raising an error. The silent contract of
"don't raise on EOF" was a little difficult to understand and threw a wrench
into the answer of the question "when do I raise a condition?"
Many of these difficulties can be overcome through documentation, examples, and
general practice. In the end, all of these difficulties added together ended up
being too overwhelming and improving various aspects didn't end up helping that
much.
A result-based I/O error handling strategy also has shortcomings, but the
cognitive burden is much smaller. The tooling necessary to make this strategy as
usable as conditions were is much smaller than the tooling necessary for
conditions.
Perhaps conditions may manifest themselves as a future entity, but for now
we're going to remove them from the standard library.
Closes #9795
Closes #8968
2014-02-04 21:02:10 -06:00
|
|
|
loop {
|
|
|
|
match parser.next() {
|
|
|
|
Some(piece) => {
|
2015-03-24 18:54:09 -05:00
|
|
|
if !parser.errors.is_empty() { break }
|
2013-07-29 03:12:41 -05:00
|
|
|
cx.verify_piece(&piece);
|
2014-07-20 09:31:43 -05:00
|
|
|
match cx.trans_piece(&piece) {
|
|
|
|
Some(piece) => {
|
2014-08-21 08:34:00 -05:00
|
|
|
let s = cx.trans_literal_string();
|
|
|
|
cx.str_pieces.push(s);
|
2014-07-20 09:31:43 -05:00
|
|
|
cx.pieces.push(piece);
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
Remove std::condition
This has been a long time coming. Conditions in rust were initially envisioned
as being a good alternative to error code return pattern. The idea is that all
errors are fatal-by-default, and you can opt-in to handling the error by
registering an error handler.
While sounding nice, conditions ended up having some unforseen shortcomings:
* Actually handling an error has some very awkward syntax:
let mut result = None;
let mut answer = None;
io::io_error::cond.trap(|e| { result = Some(e) }).inside(|| {
answer = Some(some_io_operation());
});
match result {
Some(err) => { /* hit an I/O error */ }
None => {
let answer = answer.unwrap();
/* deal with the result of I/O */
}
}
This pattern can certainly use functions like io::result, but at its core
actually handling conditions is fairly difficult
* The "zero value" of a function is often confusing. One of the main ideas
behind using conditions was to change the signature of I/O functions. Instead
of read_be_u32() returning a result, it returned a u32. Errors were notified
via a condition, and if you caught the condition you understood that the "zero
value" returned is actually a garbage value. These zero values are often
difficult to understand, however.
One case of this is the read_bytes() function. The function takes an integer
length of the amount of bytes to read, and returns an array of that size. The
array may actually be shorter, however, if an error occurred.
Another case is fs::stat(). The theoretical "zero value" is a blank stat
struct, but it's a little awkward to create and return a zero'd out stat
struct on a call to stat().
In general, the return value of functions that can raise error are much more
natural when using a Result as opposed to an always-usable zero-value.
* Conditions impose a necessary runtime requirement on *all* I/O. In theory I/O
is as simple as calling read() and write(), but using conditions imposed the
restriction that a rust local task was required if you wanted to catch errors
with I/O. While certainly an surmountable difficulty, this was always a bit of
a thorn in the side of conditions.
* Functions raising conditions are not always clear that they are raising
conditions. This suffers a similar problem to exceptions where you don't
actually know whether a function raises a condition or not. The documentation
likely explains, but if someone retroactively adds a condition to a function
there's nothing forcing upstream users to acknowledge a new point of task
failure.
* Libaries using I/O are not guaranteed to correctly raise on conditions when an
error occurs. In developing various I/O libraries, it's much easier to just
return `None` from a read rather than raising an error. The silent contract of
"don't raise on EOF" was a little difficult to understand and threw a wrench
into the answer of the question "when do I raise a condition?"
Many of these difficulties can be overcome through documentation, examples, and
general practice. In the end, all of these difficulties added together ended up
being too overwhelming and improving various aspects didn't end up helping that
much.
A result-based I/O error handling strategy also has shortcomings, but the
cognitive burden is much smaller. The tooling necessary to make this strategy as
usable as conditions were is much smaller than the tooling necessary for
conditions.
Perhaps conditions may manifest themselves as a future entity, but for now
we're going to remove them from the standard library.
Closes #9795
Closes #8968
2014-02-04 21:02:10 -06:00
|
|
|
None => break
|
|
|
|
}
|
|
|
|
}
|
2014-12-30 12:51:18 -06:00
|
|
|
if !parser.errors.is_empty() {
|
2015-01-07 10:58:31 -06:00
|
|
|
cx.ecx.span_err(cx.fmtsp, &format!("invalid format string: {}",
|
2015-02-20 13:08:14 -06:00
|
|
|
parser.errors.remove(0)));
|
2014-12-30 12:51:18 -06:00
|
|
|
return DummyResult::raw_expr(sp);
|
Remove std::condition
This has been a long time coming. Conditions in rust were initially envisioned
as being a good alternative to error code return pattern. The idea is that all
errors are fatal-by-default, and you can opt-in to handling the error by
registering an error handler.
While sounding nice, conditions ended up having some unforseen shortcomings:
* Actually handling an error has some very awkward syntax:
let mut result = None;
let mut answer = None;
io::io_error::cond.trap(|e| { result = Some(e) }).inside(|| {
answer = Some(some_io_operation());
});
match result {
Some(err) => { /* hit an I/O error */ }
None => {
let answer = answer.unwrap();
/* deal with the result of I/O */
}
}
This pattern can certainly use functions like io::result, but at its core
actually handling conditions is fairly difficult
* The "zero value" of a function is often confusing. One of the main ideas
behind using conditions was to change the signature of I/O functions. Instead
of read_be_u32() returning a result, it returned a u32. Errors were notified
via a condition, and if you caught the condition you understood that the "zero
value" returned is actually a garbage value. These zero values are often
difficult to understand, however.
One case of this is the read_bytes() function. The function takes an integer
length of the amount of bytes to read, and returns an array of that size. The
array may actually be shorter, however, if an error occurred.
Another case is fs::stat(). The theoretical "zero value" is a blank stat
struct, but it's a little awkward to create and return a zero'd out stat
struct on a call to stat().
In general, the return value of functions that can raise error are much more
natural when using a Result as opposed to an always-usable zero-value.
* Conditions impose a necessary runtime requirement on *all* I/O. In theory I/O
is as simple as calling read() and write(), but using conditions imposed the
restriction that a rust local task was required if you wanted to catch errors
with I/O. While certainly an surmountable difficulty, this was always a bit of
a thorn in the side of conditions.
* Functions raising conditions are not always clear that they are raising
conditions. This suffers a similar problem to exceptions where you don't
actually know whether a function raises a condition or not. The documentation
likely explains, but if someone retroactively adds a condition to a function
there's nothing forcing upstream users to acknowledge a new point of task
failure.
* Libaries using I/O are not guaranteed to correctly raise on conditions when an
error occurs. In developing various I/O libraries, it's much easier to just
return `None` from a read rather than raising an error. The silent contract of
"don't raise on EOF" was a little difficult to understand and threw a wrench
into the answer of the question "when do I raise a condition?"
Many of these difficulties can be overcome through documentation, examples, and
general practice. In the end, all of these difficulties added together ended up
being too overwhelming and improving various aspects didn't end up helping that
much.
A result-based I/O error handling strategy also has shortcomings, but the
cognitive burden is much smaller. The tooling necessary to make this strategy as
usable as conditions were is much smaller than the tooling necessary for
conditions.
Perhaps conditions may manifest themselves as a future entity, but for now
we're going to remove them from the standard library.
Closes #9795
Closes #8968
2014-02-04 21:02:10 -06:00
|
|
|
}
|
2014-08-21 08:34:00 -05:00
|
|
|
if !cx.literal.is_empty() {
|
|
|
|
let s = cx.trans_literal_string();
|
|
|
|
cx.str_pieces.push(s);
|
|
|
|
}
|
2013-07-29 03:12:41 -05:00
|
|
|
|
|
|
|
// Make sure that all arguments were used and all arguments have types.
|
|
|
|
for (i, ty) in cx.arg_types.iter().enumerate() {
|
|
|
|
if ty.is_none() {
|
2014-10-15 01:05:01 -05:00
|
|
|
cx.ecx.span_err(cx.args[i].span, "argument never used");
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
2015-01-31 11:20:46 -06:00
|
|
|
for (name, e) in &cx.names {
|
2013-07-29 03:12:41 -05:00
|
|
|
if !cx.name_types.contains_key(name) {
|
2013-12-28 23:06:22 -06:00
|
|
|
cx.ecx.span_err(e.span, "named argument never used");
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 03:28:18 -06:00
|
|
|
cx.into_expr()
|
2013-07-29 03:12:41 -05:00
|
|
|
}
|