Skip to content

Commit 8f24804

Browse files
committed
auto merge of #9932 : alexcrichton/rust/better-fmt-errors, r=cmr
Instead of just saying "unterminated format string" and friends, instead print information about what was expected and what was found. Closes #9931
2 parents 34a1e3d + a447c3c commit 8f24804

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed

src/libstd/fmt/parse.rs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,7 @@ impl<'self> Iterator<Piece<'self>> for Parser<'self> {
170170
Some((_, '{')) => {
171171
self.cur.next();
172172
let ret = Some(Argument(self.argument()));
173-
if !self.consume('}') {
174-
self.err(~"unterminated format string");
175-
}
173+
self.must_consume('}');
176174
ret
177175
}
178176
Some((pos, '\\')) => {
@@ -223,6 +221,25 @@ impl<'self> Parser<'self> {
223221
}
224222
}
225223

224+
/// Forces consumption of the specified character. If the character is not
225+
/// found, an error is emitted.
226+
fn must_consume(&mut self, c: char) {
227+
self.ws();
228+
match self.cur.clone().next() {
229+
Some((_, maybe)) if c == maybe => {
230+
self.cur.next();
231+
}
232+
Some((_, other)) => {
233+
parse_error::cond.raise(
234+
format!("expected `{}` but found `{}`", c, other));
235+
}
236+
None => {
237+
parse_error::cond.raise(
238+
format!("expected `{}` but string was terminated", c));
239+
}
240+
}
241+
}
242+
226243
/// Attempts to consume any amount of whitespace followed by a character
227244
fn wsconsume(&mut self, c: char) -> bool {
228245
self.ws(); self.consume(c)
@@ -386,15 +403,11 @@ impl<'self> Parser<'self> {
386403
self.ws();
387404
match self.word() {
388405
"select" => {
389-
if !self.wsconsume(',') {
390-
self.err(~"`select` must be followed by `,`");
391-
}
406+
self.must_consume(',');
392407
Some(self.select())
393408
}
394409
"plural" => {
395-
if !self.wsconsume(',') {
396-
self.err(~"`plural` must be followed by `,`");
397-
}
410+
self.must_consume(',');
398411
Some(self.plural())
399412
}
400413
"" => {
@@ -420,15 +433,11 @@ impl<'self> Parser<'self> {
420433
self.err(~"cannot have an empty selector");
421434
break
422435
}
423-
if !self.wsconsume('{') {
424-
self.err(~"selector must be followed by `{`");
425-
}
436+
self.must_consume('{');
426437
self.depth += 1;
427438
let pieces = self.collect();
428439
self.depth -= 1;
429-
if !self.wsconsume('}') {
430-
self.err(~"selector case must be terminated by `}`");
431-
}
440+
self.must_consume('}');
432441
if selector == "other" {
433442
if !other.is_none() {
434443
self.err(~"multiple `other` statements in `select");
@@ -475,9 +484,7 @@ impl<'self> Parser<'self> {
475484
self.err(format!("expected `offset`, found `{}`",
476485
word));
477486
} else {
478-
if !self.consume(':') {
479-
self.err(~"`offset` must be followed by `:`");
480-
}
487+
self.must_consume(':');
481488
match self.integer() {
482489
Some(i) => { offset = Some(i); }
483490
None => {
@@ -524,15 +531,11 @@ impl<'self> Parser<'self> {
524531
}
525532
}
526533
};
527-
if !self.wsconsume('{') {
528-
self.err(~"selector must be followed by `{`");
529-
}
534+
self.must_consume('{');
530535
self.depth += 1;
531536
let pieces = self.collect();
532537
self.depth -= 1;
533-
if !self.wsconsume('}') {
534-
self.err(~"selector case must be terminated by `}`");
535-
}
538+
self.must_consume('}');
536539
if isother {
537540
if !other.is_none() {
538541
self.err(~"multiple `other` statements in `select");

src/test/compile-fail/ifmt-bad-arg.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@ fn main() {
3636

3737
// bad syntax of the format string
3838

39-
format!("{"); //~ ERROR: unterminated format string
39+
format!("{"); //~ ERROR: expected `}` but string was terminated
4040
format!("\\ "); //~ ERROR: invalid escape
4141
format!("\\"); //~ ERROR: expected an escape
4242

4343
format!("{0, }", 1); //~ ERROR: expected method
4444
format!("{0, foo}", 1); //~ ERROR: unknown method
45-
format!("{0, select}", "a"); //~ ERROR: must be followed by
46-
format!("{0, plural}", 1); //~ ERROR: must be followed by
45+
format!("{0, select}", "a"); //~ ERROR: expected `,` but found `}`
46+
format!("{0, plural}", 1); //~ ERROR: expected `,` but found `}`
4747

48-
format!("{0, select, a{{}", 1); //~ ERROR: must be terminated
48+
format!("{0, select, a{{}", 1); //~ ERROR: expected `}` but string was terminated
4949
format!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
5050
format!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
5151
format!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
52-
format!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
52+
format!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: expected `:` but found `1`
5353
format!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
5454
format!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
5555
format!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`

0 commit comments

Comments
 (0)