test(attr(deny(warnings))))]
#![deny(rust_2018_idioms)]
+#![deny(internal)]
#![feature(nll)]
#![feature(rustc_private)]
use std::string;
use std::iter;
+use syntax_pos::{InnerSpan, Symbol};
+
+#[derive(Copy, Clone)]
+struct InnerOffset(usize);
+
+impl InnerOffset {
+ fn to(self, end: InnerOffset) -> InnerSpan {
+ InnerSpan::new(self.0, end.0)
+ }
+}
+
/// A piece is a portion of the format string which represents the next part
/// to emit. These are emitted as a stream by the `Parser` class.
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct Argument<'a> {
/// Where to find this argument
- pub position: Position<'a>,
+ pub position: Position,
/// How to format the argument
pub format: FormatSpec<'a>,
}
/// Packed version of various flags provided
pub flags: u32,
/// The integer precision to use
- pub precision: Count<'a>,
+ pub precision: Count,
/// The string width requested for the resulting format
- pub width: Count<'a>,
+ pub width: Count,
/// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although
/// it is required to be one word.
/// Enum describing where an argument for a format can be located.
#[derive(Copy, Clone, PartialEq)]
-pub enum Position<'a> {
+pub enum Position {
/// The argument is implied to be located at an index
ArgumentImplicitlyIs(usize),
/// The argument is located at a specific index given in the format
ArgumentIs(usize),
/// The argument has a name.
- ArgumentNamed(&'a str),
+ ArgumentNamed(Symbol),
}
-impl Position<'_> {
+impl Position {
pub fn index(&self) -> Option<usize> {
match self {
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
/// A count is used for the precision and width parameters of an integer, and
/// can reference either an argument or a literal integer.
#[derive(Copy, Clone, PartialEq)]
-pub enum Count<'a> {
+pub enum Count {
/// The count is specified explicitly.
CountIs(usize),
/// The count is specified by the argument with the given name.
- CountIsName(&'a str),
+ CountIsName(Symbol),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
/// The count is implied and cannot be explicitly specified.
pub description: string::String,
pub note: Option<string::String>,
pub label: string::String,
- pub start: SpanIndex,
- pub end: SpanIndex,
- pub secondary_label: Option<(string::String, SpanIndex, SpanIndex)>,
+ pub span: InnerSpan,
+ pub secondary_label: Option<(string::String, InnerSpan)>,
}
/// The parser structure for interpreting the input format string. This is
/// `Some(raw count)` when the string is "raw", used to position spans correctly
style: Option<usize>,
/// Start and end byte offset of every successfully parsed argument
- pub arg_places: Vec<(SpanIndex, SpanIndex)>,
+ pub arg_places: Vec<InnerSpan>,
/// Characters that need to be shifted
skips: Vec<usize>,
- /// Span offset of the last opening brace seen, used for error reporting
- last_opening_brace_pos: Option<SpanIndex>,
+ /// Span of the last opening brace seen, used for error reporting
+ last_opening_brace: Option<InnerSpan>,
/// Wether the source string is comes from `println!` as opposed to `format!` or `print!`
append_newline: bool,
}
-#[derive(Clone, Copy, Debug)]
-pub struct SpanIndex(pub usize);
-
-impl SpanIndex {
- pub fn unwrap(self) -> usize {
- self.0
- }
-}
-
impl<'a> Iterator for Parser<'a> {
type Item = Piece<'a>;
if let Some(&(pos, c)) = self.cur.peek() {
match c {
'{' => {
- let curr_last_brace = self.last_opening_brace_pos;
- self.last_opening_brace_pos = Some(self.to_span_index(pos));
+ let curr_last_brace = self.last_opening_brace;
+ let byte_pos = self.to_span_index(pos);
+ self.last_opening_brace = Some(byte_pos.to(byte_pos));
self.cur.next();
if self.consume('{') {
- self.last_opening_brace_pos = curr_last_brace;
+ self.last_opening_brace = curr_last_brace;
Some(String(self.string(pos + 1)))
} else {
let arg = self.argument();
- if let Some(arg_pos) = self.must_consume('}').map(|end| {
- (self.to_span_index(pos), self.to_span_index(end + 1))
- }) {
- self.arg_places.push(arg_pos);
+ if let Some(end) = self.must_consume('}') {
+ let start = self.to_span_index(pos);
+ let end = self.to_span_index(end + 1);
+ self.arg_places.push(start.to(end));
}
Some(NextArgument(arg))
}
"unmatched `}` found",
"unmatched `}`",
"if you intended to print `}`, you can escape it using `}}`",
- err_pos,
- err_pos,
+ err_pos.to(err_pos),
);
None
}
style,
arg_places: vec![],
skips,
- last_opening_brace_pos: None,
+ last_opening_brace: None,
append_newline,
}
}
&mut self,
description: S1,
label: S2,
- start: SpanIndex,
- end: SpanIndex,
+ span: InnerSpan,
) {
self.errors.push(ParseError {
description: description.into(),
note: None,
label: label.into(),
- start,
- end,
+ span,
secondary_label: None,
});
}
description: S1,
label: S2,
note: S3,
- start: SpanIndex,
- end: SpanIndex,
+ span: InnerSpan,
) {
self.errors.push(ParseError {
description: description.into(),
note: Some(note.into()),
label: label.into(),
- start,
- end,
+ span,
secondary_label: None,
});
}
}
}
- fn raw(&self) -> usize {
- self.style.map(|raw| raw + 1).unwrap_or(0)
- }
-
- fn to_span_index(&self, pos: usize) -> SpanIndex {
+ fn to_span_index(&self, pos: usize) -> InnerOffset {
let mut pos = pos;
+ let raw = self.style.map(|raw| raw + 1).unwrap_or(0);
for skip in &self.skips {
if pos > *skip {
pos += 1;
- } else if pos == *skip && self.raw() == 0 {
+ } else if pos == *skip && raw == 0 {
pos += 1;
} else {
break;
}
}
- SpanIndex(self.raw() + pos + 1)
+ InnerOffset(raw + pos + 1)
}
/// Forces consumption of the specified character. If the character is not
let label = "expected `}`".to_owned();
let (note, secondary_label) = if c == '}' {
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
- self.last_opening_brace_pos.map(|pos| {
- ("because of this opening brace".to_owned(), pos, pos)
+ self.last_opening_brace.map(|sp| {
+ ("because of this opening brace".to_owned(), sp)
}))
} else {
(None, None)
description,
note,
label,
- start: pos,
- end: pos,
+ span: pos.to(pos),
secondary_label,
});
None
let label = format!("expected `{:?}`", c);
let (note, secondary_label) = if c == '}' {
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
- self.last_opening_brace_pos.map(|pos| {
- ("because of this opening brace".to_owned(), pos, pos)
+ self.last_opening_brace.map(|sp| {
+ ("because of this opening brace".to_owned(), sp)
}))
} else {
(None, None)
description,
note,
label,
- start: pos,
- end: pos,
+ span: pos.to(pos),
secondary_label,
});
} else {
- self.err(description, format!("expected `{:?}`", c), pos, pos);
+ self.err(description, format!("expected `{:?}`", c), pos.to(pos));
}
None
}
/// integer index of an argument, a named argument, or a blank string.
/// Returns `Some(parsed_position)` if the position is not implicitly
/// consuming a macro argument, `None` if it's the case.
- fn position(&mut self) -> Option<Position<'a>> {
+ fn position(&mut self) -> Option<Position> {
if let Some(i) = self.integer() {
Some(ArgumentIs(i))
} else {
match self.cur.peek() {
- Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
+ Some(&(_, c)) if c.is_alphabetic() => {
+ Some(ArgumentNamed(Symbol::intern(self.word())))
+ }
Some(&(pos, c)) if c == '_' => {
let invalid_name = self.string(pos);
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
"invalid argument name",
"argument names cannot start with an underscore",
- self.to_span_index(pos),
- self.to_span_index(pos + invalid_name.len()));
- Some(ArgumentNamed(invalid_name))
+ self.to_span_index(pos).to(
+ self.to_span_index(pos + invalid_name.len())
+ ),
+ );
+ Some(ArgumentNamed(Symbol::intern(invalid_name)))
},
// This is an `ArgumentNext`.
/// Parses a Count parameter at the current position. This does not check
/// for 'CountIsNextParam' because that is only used in precision, not
/// width.
- fn count(&mut self) -> Count<'a> {
+ fn count(&mut self) -> Count {
if let Some(i) = self.integer() {
if self.consume('$') {
CountIsParam(i)
self.cur = tmp;
CountImplied
} else if self.consume('$') {
- CountIsName(word)
+ CountIsName(Symbol::intern(word))
} else {
self.cur = tmp;
CountImplied
}
#[test]
fn format_counts() {
+ use syntax_pos::{GLOBALS, Globals, edition};
+ GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
same("{:10s}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
fill: None,
align: AlignUnknown,
flags: 0,
- precision: CountIsName("b"),
- width: CountIsName("a"),
+ precision: CountIsName(Symbol::intern("b")),
+ width: CountIsName(Symbol::intern("a")),
ty: "s",
},
})]);
+ });
}
#[test]
fn format_flags() {