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:
bors 2014-06-13 14:42:03 +00:00
commit 0422934e24
57 changed files with 736 additions and 1087 deletions

View file

@ -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 {

View file

@ -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();

View file

@ -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!()

View file

@ -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))
}
}

View file

@ -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)

View file

@ -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) {

View file

@ -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());
}