Skip to content

Commit a447c3c

Browse files
committed
Try to improve format! error messages
Instead of just saying "unterminated format string" and friends, instead print information about what was expected and what was found. Closes #9931
1 parent a1848bc commit a447c3c

File tree

2 files changed

+32
-29
lines changed

2 files changed

+32
-29
lines changed

src/libstd/fmt/parse.rs

+27-24
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

+5-5
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)