format: remove all implicit ref handling outside of libfmt_macros
format: beautifully get rid of ArgumentNext and CountIsNextParam Now that CountIsNextParam and ArgumentNext are resolved during parse, the need for handling them outside of libfmt_macros is obviated. Note: *one* instance of implicit reference handling still remains, and that's for implementing `all_args_simple`. It's trivial enough though, so in this case it may be tolerable.
This commit is contained in:
parent
71949f3b0d
commit
06b034ae8b
3 changed files with 36 additions and 54 deletions
|
@ -80,8 +80,6 @@ pub struct FormatSpec<'a> {
|
|||
/// Enum describing where an argument for a format can be located.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Position<'a> {
|
||||
/// The argument will be in the next position. This is the default.
|
||||
ArgumentNext,
|
||||
/// The argument is located at a specific index.
|
||||
ArgumentIs(usize),
|
||||
/// The argument has a name.
|
||||
|
@ -127,8 +125,6 @@ pub enum Count<'a> {
|
|||
CountIsName(&'a str),
|
||||
/// The count is specified by the argument at the given index.
|
||||
CountIsParam(usize),
|
||||
/// The count is specified by the next parameter.
|
||||
CountIsNextParam,
|
||||
/// The count is implied and cannot be explicitly specified.
|
||||
CountImplied,
|
||||
}
|
||||
|
@ -262,37 +258,18 @@ impl<'a> Parser<'a> {
|
|||
/// Parses an Argument structure, or what's contained within braces inside
|
||||
/// the format string
|
||||
fn argument(&mut self) -> Argument<'a> {
|
||||
let mut pos = self.position();
|
||||
let mut format = self.format();
|
||||
let pos = self.position();
|
||||
let format = self.format();
|
||||
|
||||
// Resolve CountIsNextParam's into absolute references.
|
||||
// Current argument's position must be known so this is done after
|
||||
// format parsing.
|
||||
// Curiously, currently {:.*} for named arguments is implemented,
|
||||
// and it consumes a positional arg slot just like a positional {:.*}
|
||||
// does. The current behavior is reproduced to prevent any
|
||||
// incompatibilities.
|
||||
match format.precision {
|
||||
CountIsNextParam => {
|
||||
// eat the current implicit arg
|
||||
// Resolve position after parsing format spec.
|
||||
let pos = match pos {
|
||||
Some(position) => position,
|
||||
None => {
|
||||
let i = self.curarg;
|
||||
self.curarg += 1;
|
||||
format.precision = CountIsParam(i);
|
||||
ArgumentIs(i)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Resolve ArgumentNext's into absolute references.
|
||||
// This must come after count resolution because we may consume one
|
||||
// more arg if precision is CountIsNextParam.
|
||||
match pos {
|
||||
ArgumentNext => {
|
||||
let i = self.curarg;
|
||||
self.curarg += 1;
|
||||
pos = ArgumentIs(i);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
Argument {
|
||||
position: pos,
|
||||
|
@ -302,13 +279,19 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses a positional argument for a format. This could either be an
|
||||
/// integer index of an argument, a named argument, or a blank string.
|
||||
fn position(&mut self) -> Position<'a> {
|
||||
/// 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>> {
|
||||
if let Some(i) = self.integer() {
|
||||
ArgumentIs(i)
|
||||
Some(ArgumentIs(i))
|
||||
} else {
|
||||
match self.cur.peek() {
|
||||
Some(&(_, c)) if c.is_alphabetic() => ArgumentNamed(self.word()),
|
||||
_ => ArgumentNext,
|
||||
Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
|
||||
|
||||
// This is an `ArgumentNext`.
|
||||
// Record the fact and do the resolution after parsing the
|
||||
// format spec, to make things like `{:.*}` work.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +358,11 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
if self.consume('.') {
|
||||
if self.consume('*') {
|
||||
spec.precision = CountIsNextParam;
|
||||
// Resolve `CountIsNextParam`.
|
||||
// We can do this immediately as `position` is resolved later.
|
||||
let i = self.curarg;
|
||||
self.curarg += 1;
|
||||
spec.precision = CountIsParam(i);
|
||||
} else {
|
||||
spec.precision = self.count();
|
||||
}
|
||||
|
|
|
@ -881,7 +881,7 @@ fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
}
|
||||
},
|
||||
// `{:1}` and `{}` are not to be used
|
||||
Position::ArgumentIs(_) | Position::ArgumentNext => {
|
||||
Position::ArgumentIs(_) => {
|
||||
span_err!(ccx.tcx.sess, attr.span, E0231,
|
||||
"only named substitution \
|
||||
parameters are allowed");
|
||||
|
|
|
@ -68,8 +68,10 @@ struct Context<'a, 'b:'a> {
|
|||
|
||||
name_positions: HashMap<String, usize>,
|
||||
|
||||
/// Updated as arguments are consumed
|
||||
next_arg: usize,
|
||||
/// Current position of the implicit positional arg pointer, as if it
|
||||
/// still existed in this phase of processing.
|
||||
/// Used only for `all_pieces_simple` tracking in `trans_piece`.
|
||||
curarg: usize,
|
||||
}
|
||||
|
||||
/// Parses the arguments from the given list of tokens, returning None
|
||||
|
@ -159,11 +161,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
// argument second, if it's an implicit positional parameter
|
||||
// it's written second, so it should come after width/precision.
|
||||
let pos = match arg.position {
|
||||
parse::ArgumentNext => {
|
||||
let i = self.next_arg;
|
||||
self.next_arg += 1;
|
||||
Exact(i)
|
||||
}
|
||||
parse::ArgumentIs(i) => Exact(i),
|
||||
parse::ArgumentNamed(s) => Named(s.to_string()),
|
||||
};
|
||||
|
@ -183,11 +180,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
parse::CountIsName(s) => {
|
||||
self.verify_arg_type(Named(s.to_string()), Unsigned);
|
||||
}
|
||||
parse::CountIsNextParam => {
|
||||
let next_arg = self.next_arg;
|
||||
self.verify_arg_type(Exact(next_arg), Unsigned);
|
||||
self.next_arg += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,7 +301,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
count("Param", Some(self.ecx.expr_usize(sp, i)))
|
||||
}
|
||||
parse::CountImplied => count("Implied", None),
|
||||
parse::CountIsNextParam => count("NextParam", None),
|
||||
parse::CountIsName(n) => {
|
||||
let i = match self.name_positions.get(n) {
|
||||
Some(&i) => i,
|
||||
|
@ -355,8 +346,6 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
}
|
||||
};
|
||||
match arg.position {
|
||||
// These two have a direct mapping
|
||||
parse::ArgumentNext => pos("Next", None),
|
||||
parse::ArgumentIs(i) => pos("At", Some(i)),
|
||||
|
||||
// Named arguments are converted to positional arguments
|
||||
|
@ -373,7 +362,13 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
};
|
||||
|
||||
let simple_arg = parse::Argument {
|
||||
position: parse::ArgumentNext,
|
||||
position: {
|
||||
// We don't have ArgumentNext any more, so we have to
|
||||
// track the current argument ourselves.
|
||||
let i = self.curarg;
|
||||
self.curarg += 1;
|
||||
parse::ArgumentIs(i)
|
||||
},
|
||||
format: parse::FormatSpec {
|
||||
fill: arg.format.fill,
|
||||
align: parse::AlignUnknown,
|
||||
|
@ -640,7 +635,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
|
|||
name_positions: HashMap::new(),
|
||||
name_types: HashMap::new(),
|
||||
name_ordering: name_ordering,
|
||||
next_arg: 0,
|
||||
curarg: 0,
|
||||
literal: String::new(),
|
||||
pieces: Vec::new(),
|
||||
str_pieces: Vec::new(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue