auto merge of #14831 : alexcrichton/rust/format-intl, r=brson
* The select/plural methods from format strings are removed
* The # character no longer needs to be escaped
* The \-based escapes have been removed
* '{{' is now an escape for '{'
* '}}' is now an escape for '}'
Closes #14810
[breaking-change]
This commit is contained in:
commit
0422934e24
57 changed files with 736 additions and 1087 deletions
|
|
@ -32,6 +32,7 @@ pub struct CrateId {
|
|||
}
|
||||
|
||||
impl fmt::Show for CrateId {
|
||||
#[cfg(stage0)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{}", self.path));
|
||||
let version = match self.version {
|
||||
|
|
@ -47,6 +48,22 @@ impl fmt::Show for CrateId {
|
|||
write!(f, "\\#{}:{}", self.name, version)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{}", self.path));
|
||||
let version = match self.version {
|
||||
None => "0.0",
|
||||
Some(ref version) => version.as_slice(),
|
||||
};
|
||||
if self.path == self.name ||
|
||||
self.path
|
||||
.as_slice()
|
||||
.ends_with(format!("/{}", self.name).as_slice()) {
|
||||
write!(f, "#{}", version)
|
||||
} else {
|
||||
write!(f, "#{}:{}", self.name, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CrateId {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|||
inputs.push((constraint, input));
|
||||
}
|
||||
}
|
||||
#[cfg(stage0)]
|
||||
Clobbers => {
|
||||
let mut clobs = Vec::new();
|
||||
while p.token != token::EOF &&
|
||||
|
|
@ -164,6 +165,28 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|||
|
||||
cons = clobs.connect(",");
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
Clobbers => {
|
||||
let mut clobs = Vec::new();
|
||||
while p.token != token::EOF &&
|
||||
p.token != token::COLON &&
|
||||
p.token != token::MOD_SEP {
|
||||
|
||||
if clobs.len() != 0 {
|
||||
p.eat(&token::COMMA);
|
||||
}
|
||||
|
||||
let (s, _str_style) = p.parse_str();
|
||||
let clob = format!("~{{{}}}", s);
|
||||
clobs.push(clob);
|
||||
|
||||
if OPTIONS.iter().any(|opt| s.equiv(opt)) {
|
||||
cx.span_warn(p.last_span, "expected a clobber, but found an option");
|
||||
}
|
||||
}
|
||||
|
||||
cons = clobs.connect(",");
|
||||
}
|
||||
Options => {
|
||||
let (option, _str_style) = p.parse_str();
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
|||
} else {
|
||||
// normal struct/struct variant
|
||||
|
||||
format_string.push_str(" \\{");
|
||||
format_string.push_str(" {{");
|
||||
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i != 0 { format_string.push_str(","); }
|
||||
|
|
@ -113,7 +113,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
|||
exprs.push(field.self_);
|
||||
}
|
||||
|
||||
format_string.push_str(" \\}");
|
||||
format_string.push_str(" }}");
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use parse::token;
|
|||
use rsparse = parse;
|
||||
|
||||
use parse = fmt_macros;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashMap;
|
||||
use std::gc::Gc;
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
|
|
@ -165,13 +165,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
fn verify_piece(&mut self, p: &parse::Piece) {
|
||||
match *p {
|
||||
parse::String(..) => {}
|
||||
parse::CurrentArgument => {
|
||||
if self.nest_level == 0 {
|
||||
self.ecx.span_err(self.fmtsp,
|
||||
"`#` reference used with nothing to \
|
||||
reference back to");
|
||||
}
|
||||
}
|
||||
parse::Argument(ref arg) => {
|
||||
// width/precision first, if they have implicit positional
|
||||
// parameters it makes more sense to consume them first.
|
||||
|
|
@ -192,24 +185,12 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
parse::ArgumentNamed(s) => Named(s.to_string()),
|
||||
};
|
||||
|
||||
// and finally the method being applied
|
||||
match arg.method {
|
||||
None => {
|
||||
let ty = Known(arg.format.ty.to_string());
|
||||
self.verify_arg_type(pos, ty);
|
||||
}
|
||||
Some(ref method) => { self.verify_method(pos, *method); }
|
||||
}
|
||||
let ty = Known(arg.format.ty.to_string());
|
||||
self.verify_arg_type(pos, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
|
||||
for piece in pieces.iter() {
|
||||
self.verify_piece(piece);
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_count(&mut self, c: parse::Count) {
|
||||
match c {
|
||||
parse::CountImplied | parse::CountIs(..) => {}
|
||||
|
|
@ -238,53 +219,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn verify_method(&mut self, pos: Position, m: &parse::Method) {
|
||||
self.nest_level += 1;
|
||||
match *m {
|
||||
parse::Plural(_, ref arms, ref default) => {
|
||||
let mut seen_cases = HashSet::new();
|
||||
self.verify_arg_type(pos, Unsigned);
|
||||
for arm in arms.iter() {
|
||||
if !seen_cases.insert(arm.selector) {
|
||||
match arm.selector {
|
||||
parse::Keyword(name) => {
|
||||
self.ecx.span_err(self.fmtsp,
|
||||
format!("duplicate \
|
||||
selector `{}`",
|
||||
name).as_slice());
|
||||
}
|
||||
parse::Literal(idx) => {
|
||||
self.ecx.span_err(self.fmtsp,
|
||||
format!("duplicate \
|
||||
selector `={}`",
|
||||
idx).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.verify_pieces(arm.result.as_slice());
|
||||
}
|
||||
self.verify_pieces(default.as_slice());
|
||||
}
|
||||
parse::Select(ref arms, ref default) => {
|
||||
self.verify_arg_type(pos, String);
|
||||
let mut seen_cases = HashSet::new();
|
||||
for arm in arms.iter() {
|
||||
if !seen_cases.insert(arm.selector) {
|
||||
self.ecx.span_err(self.fmtsp,
|
||||
format!("duplicate selector `{}`",
|
||||
arm.selector).as_slice());
|
||||
} else if arm.selector == "" {
|
||||
self.ecx.span_err(self.fmtsp,
|
||||
"empty selector in `select`");
|
||||
}
|
||||
self.verify_pieces(arm.result.as_slice());
|
||||
}
|
||||
self.verify_pieces(default.as_slice());
|
||||
}
|
||||
}
|
||||
self.nest_level -= 1;
|
||||
}
|
||||
|
||||
fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
|
||||
match arg {
|
||||
Exact(arg) => {
|
||||
|
|
@ -400,23 +334,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.ecx.ident_of("rt"), self.ecx.ident_of(s))
|
||||
}
|
||||
|
||||
fn none(&self) -> Gc<ast::Expr> {
|
||||
let none = self.ecx.path_global(self.fmtsp, vec!(
|
||||
self.ecx.ident_of("std"),
|
||||
self.ecx.ident_of("option"),
|
||||
self.ecx.ident_of("None")));
|
||||
self.ecx.expr_path(none)
|
||||
}
|
||||
|
||||
fn some(&self, e: Gc<ast::Expr>) -> Gc<ast::Expr> {
|
||||
let p = self.ecx.path_global(self.fmtsp, vec!(
|
||||
self.ecx.ident_of("std"),
|
||||
self.ecx.ident_of("option"),
|
||||
self.ecx.ident_of("Some")));
|
||||
let p = self.ecx.expr_path(p);
|
||||
self.ecx.expr_call(self.fmtsp, p, vec!(e))
|
||||
}
|
||||
|
||||
fn trans_count(&self, c: parse::Count) -> Gc<ast::Expr> {
|
||||
let sp = self.fmtsp;
|
||||
match c {
|
||||
|
|
@ -448,86 +365,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn trans_method(&mut self, method: &parse::Method) -> Gc<ast::Expr> {
|
||||
let sp = self.fmtsp;
|
||||
let method = match *method {
|
||||
parse::Select(ref arms, ref default) => {
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, self.rtpath("SelectArm"));
|
||||
let result = arm.result.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
let s = token::intern_and_get_ident(arm.selector);
|
||||
let selector = self.ecx.expr_str(sp, s);
|
||||
self.ecx.expr_struct(sp, p, vec!(
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result))))
|
||||
}).collect();
|
||||
let default = default.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Select"), vec!(
|
||||
self.ecx.expr_vec_slice(sp, arms),
|
||||
self.ecx.expr_vec_slice(sp, default)))
|
||||
}
|
||||
parse::Plural(offset, ref arms, ref default) => {
|
||||
let offset = match offset {
|
||||
Some(i) => { self.some(self.ecx.expr_uint(sp, i)) }
|
||||
None => { self.none() }
|
||||
};
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, self.rtpath("PluralArm"));
|
||||
let result = arm.result.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
let (lr, selarg) = match arm.selector {
|
||||
parse::Keyword(t) => {
|
||||
let p = self.rtpath(t.to_str().as_slice());
|
||||
let p = self.ecx.path_global(sp, p);
|
||||
(self.rtpath("Keyword"), self.ecx.expr_path(p))
|
||||
}
|
||||
parse::Literal(i) => {
|
||||
(self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
|
||||
}
|
||||
};
|
||||
let selector = self.ecx.expr_call_global(sp,
|
||||
lr, vec!(selarg));
|
||||
self.ecx.expr_struct(sp, p, vec!(
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result))))
|
||||
}).collect();
|
||||
let default = default.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Plural"), vec!(
|
||||
offset,
|
||||
self.ecx.expr_vec_slice(sp, arms),
|
||||
self.ecx.expr_vec_slice(sp, default)))
|
||||
}
|
||||
};
|
||||
let life = self.ecx.lifetime(sp, self.ecx.ident_of("static").name);
|
||||
let ty = self.ecx.ty_path(self.ecx.path_all(
|
||||
sp,
|
||||
true,
|
||||
self.rtpath("Method"),
|
||||
vec!(life),
|
||||
Vec::new()
|
||||
), None);
|
||||
let st = ast::ItemStatic(ty, ast::MutImmutable, method);
|
||||
let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
|
||||
self.method_statics
|
||||
.len()).as_slice());
|
||||
let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
|
||||
self.method_statics.push(item);
|
||||
self.ecx.expr_ident(sp, static_name)
|
||||
}
|
||||
|
||||
/// Translate a `parse::Piece` to a static `rt::Piece`
|
||||
fn trans_piece(&mut self, piece: &parse::Piece) -> Gc<ast::Expr> {
|
||||
let sp = self.fmtsp;
|
||||
|
|
@ -540,10 +377,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.ecx.expr_str(sp, s)
|
||||
))
|
||||
}
|
||||
parse::CurrentArgument => {
|
||||
let nil = self.ecx.expr_lit(sp, ast::LitNil);
|
||||
self.ecx.expr_call_global(sp, self.rtpath("CurrentArgument"), vec!(nil))
|
||||
}
|
||||
parse::Argument(ref arg) => {
|
||||
// Translate the position
|
||||
let pos = match arg.position {
|
||||
|
|
@ -596,19 +429,10 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("width"), width)));
|
||||
|
||||
// Translate the method (if any)
|
||||
let method = match arg.method {
|
||||
None => { self.none() }
|
||||
Some(ref m) => {
|
||||
let m = self.trans_method(*m);
|
||||
self.some(self.ecx.expr_addr_of(sp, m))
|
||||
}
|
||||
};
|
||||
let path = self.ecx.path_global(sp, self.rtpath("Argument"));
|
||||
let s = self.ecx.expr_struct(sp, path, vec!(
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("method"), method)));
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt)));
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Argument"), vec!(s))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,11 +129,13 @@ fn generic_extension(cx: &ExtCtxt,
|
|||
rhses: &[Rc<NamedMatch>])
|
||||
-> Box<MacResult> {
|
||||
if cx.trace_macros() {
|
||||
println!("{}! \\{ {} \\}",
|
||||
println!("{}! {} {} {}",
|
||||
token::get_ident(name),
|
||||
"{",
|
||||
print::pprust::tt_to_str(&TTDelim(Rc::new(arg.iter()
|
||||
.map(|x| (*x).clone())
|
||||
.collect()))));
|
||||
.collect()))),
|
||||
"}");
|
||||
}
|
||||
|
||||
// Which arm's failure should we report? (the one furthest along)
|
||||
|
|
|
|||
|
|
@ -89,11 +89,18 @@ impl<'a> ParserAttr for Parser<'a> {
|
|||
let hi = self.span.hi;
|
||||
(mk_sp(lo, hi), meta_item, style)
|
||||
}
|
||||
#[cfg(stage0)]
|
||||
_ => {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.fatal(format!("expected `\\#` but found `{}`",
|
||||
token_str).as_slice());
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
_ => {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.fatal(format!("expected `#` but found `{}`",
|
||||
token_str).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
if permit_inner && self.eat(&token::SEMI) {
|
||||
|
|
|
|||
|
|
@ -1208,11 +1208,18 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
_ => {
|
||||
let token_str = p.this_token_to_str();
|
||||
p.fatal((format!("expected `;` or `\\{` but found `{}`",
|
||||
token_str)).as_slice())
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
_ => {
|
||||
let token_str = p.this_token_to_str();
|
||||
p.fatal((format!("expected `;` or `{{` but found `{}`",
|
||||
token_str)).as_slice())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -2739,7 +2746,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
if self.token != token::RBRACE {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.fatal(format!("expected `\\}`, found `{}`",
|
||||
self.fatal(format!("expected `{}`, found `{}`", "}",
|
||||
token_str).as_slice())
|
||||
}
|
||||
etc = true;
|
||||
|
|
@ -3149,6 +3156,7 @@ impl<'a> Parser<'a> {
|
|||
// consuming more tokens).
|
||||
let (bra, ket) = match token::close_delimiter_for(&self.token) {
|
||||
Some(ket) => (self.token.clone(), ket),
|
||||
#[cfg(stage0)]
|
||||
None => {
|
||||
// we only expect an ident if we didn't parse one
|
||||
// above.
|
||||
|
|
@ -3162,6 +3170,20 @@ impl<'a> Parser<'a> {
|
|||
ident_str,
|
||||
tok_str).as_slice())
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
None => {
|
||||
// we only expect an ident if we didn't parse one
|
||||
// above.
|
||||
let ident_str = if id == token::special_idents::invalid {
|
||||
"identifier, "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let tok_str = self.this_token_to_str();
|
||||
self.fatal(format!("expected {}`(` or `{{`, but found `{}`",
|
||||
ident_str,
|
||||
tok_str).as_slice())
|
||||
}
|
||||
};
|
||||
|
||||
let tts = self.parse_unspanned_seq(
|
||||
|
|
@ -4041,8 +4063,8 @@ impl<'a> Parser<'a> {
|
|||
fields = Vec::new();
|
||||
} else {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.fatal(format!("expected `\\{`, `(`, or `;` after struct \
|
||||
name but found `{}`",
|
||||
self.fatal(format!("expected `{}`, `(`, or `;` after struct \
|
||||
name but found `{}`", "{",
|
||||
token_str).as_slice())
|
||||
}
|
||||
|
||||
|
|
@ -4069,12 +4091,20 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
}
|
||||
token::RBRACE => {}
|
||||
#[cfg(stage0)]
|
||||
_ => {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.span_fatal(self.span,
|
||||
format!("expected `,`, or `\\}` but found `{}`",
|
||||
token_str).as_slice())
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
_ => {
|
||||
let token_str = self.this_token_to_str();
|
||||
self.span_fatal(self.span,
|
||||
format!("expected `,`, or `}}` but found `{}`",
|
||||
token_str).as_slice())
|
||||
}
|
||||
}
|
||||
a_var
|
||||
}
|
||||
|
|
@ -4684,7 +4714,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let token_str = self.this_token_to_str();
|
||||
self.span_fatal(self.span,
|
||||
format!("expected `\\{` or `fn` but found `{}`",
|
||||
format!("expected `{}` or `fn` but found `{}`", "{",
|
||||
token_str).as_slice());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue