-> PResult<'a, P<Expr>> {
let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs));
+ let interp = if let token::Interpolated(..) = self.token {
+ true
+ } else {
+ false
+ };
let b = try!(self.parse_bottom_expr());
- self.parse_dot_or_call_expr_with(b, attrs)
+ let lo = if interp {
+ self.last_span.lo
+ } else {
+ b.span.lo
+ };
+ self.parse_dot_or_call_expr_with(b, lo, attrs)
}
pub fn parse_dot_or_call_expr_with(&mut self,
e0: P<Expr>,
+ lo: BytePos,
attrs: ThinAttributes)
-> PResult<'a, P<Expr>> {
// Stitch the list of outer attributes onto the return value.
// A little bit ugly, but the best way given the current code
// structure
- self.parse_dot_or_call_expr_with_(e0)
+ self.parse_dot_or_call_expr_with_(e0, lo)
.map(|expr|
expr.map(|mut expr| {
expr.attrs.update(|a| a.prepend(attrs));
)
}
- fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>) -> PResult<'a, P<Expr>> {
+ // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue
+ // parsing into an expression.
+ fn parse_dot_suffix(&mut self,
+ ident: Ident,
+ ident_span: Span,
+ self_value: P<Expr>)
+ -> PResult<'a, P<Expr>> {
+ let (_, tys, bindings) = if self.eat(&token::ModSep) {
+ try!(self.expect_lt());
+ try!(self.parse_generic_values_after_lt())
+ } else {
+ (Vec::new(), Vec::new(), Vec::new())
+ };
+
+ if !bindings.is_empty() {
+ let last_span = self.last_span;
+ self.span_err(last_span, "type bindings are only permitted on trait paths");
+ }
+
+ let lo = self_value.span.lo;
+
+ Ok(match self.token {
+ // expr.f() method call.
+ token::OpenDelim(token::Paren) => {
+ let mut es = try!(self.parse_unspanned_seq(
+ &token::OpenDelim(token::Paren),
+ &token::CloseDelim(token::Paren),
+ seq_sep_trailing_allowed(token::Comma),
+ |p| Ok(try!(p.parse_expr()))
+ ));
+ let hi = self.last_span.hi;
+
+ es.insert(0, self_value);
+ let id = spanned(ident_span.lo, ident_span.hi, ident);
+ let nd = self.mk_method_call(id, tys, es);
+ self.mk_expr(lo, hi, nd, None)
+ }
+ // Field access.
+ _ => {
+ if !tys.is_empty() {
+ let last_span = self.last_span;
+ self.span_err(last_span,
+ "field expressions may not \
+ have type parameters");
+ }
+
+ let id = spanned(ident_span.lo, ident_span.hi, ident);
+ let field = self.mk_field(self_value, id);
+ self.mk_expr(lo, ident_span.hi, field, None)
+ }
+ })
+ }
+
+ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<'a, P<Expr>> {
let mut e = e0;
- let lo = e.span.lo;
let mut hi;
loop {
// expr.f
if self.eat(&token::Dot) {
match self.token {
token::Ident(i, _) => {
- let dot = self.last_span.hi;
+ let dot_pos = self.last_span.hi;
hi = self.span.hi;
self.bump();
- let (_, tys, bindings) = if self.eat(&token::ModSep) {
- try!(self.expect_lt());
- try!(self.parse_generic_values_after_lt())
- } else {
- (Vec::new(), Vec::new(), Vec::new())
- };
- if !bindings.is_empty() {
- let last_span = self.last_span;
- self.span_err(last_span, "type bindings are only permitted on trait paths");
- }
-
- // expr.f() method call
- match self.token {
- token::OpenDelim(token::Paren) => {
- let mut es = try!(self.parse_unspanned_seq(
- &token::OpenDelim(token::Paren),
- &token::CloseDelim(token::Paren),
- seq_sep_trailing_allowed(token::Comma),
- |p| Ok(try!(p.parse_expr()))
- ));
- hi = self.last_span.hi;
-
- es.insert(0, e);
- let id = spanned(dot, hi, i);
- let nd = self.mk_method_call(id, tys, es);
- e = self.mk_expr(lo, hi, nd, None);
- }
- _ => {
- if !tys.is_empty() {
- let last_span = self.last_span;
- self.span_err(last_span,
- "field expressions may not \
- have type parameters");
- }
-
- let id = spanned(dot, hi, i);
- let field = self.mk_field(e, id);
- e = self.mk_expr(lo, hi, field, None);
- }
- }
+ e = try!(self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e));
}
token::Literal(token::Integer(n), suf) => {
let sp = self.span;
self.abort_if_errors();
}
- _ => return self.unexpected()
+ _ => {
+ // FIXME Could factor this out into non_fatal_unexpected or something.
+ let actual = self.this_token_to_string();
+ self.span_err(self.span, &format!("unexpected token: `{}`", actual));
+
+ let dot_pos = self.last_span.hi;
+ e = try!(self.parse_dot_suffix(special_idents::invalid,
+ mk_sp(dot_pos, dot_pos),
+ e));
+ }
}
continue;
}
let e = self.mk_mac_expr(span.lo, span.hi,
mac.and_then(|m| m.node),
None);
- let e = try!(self.parse_dot_or_call_expr_with(e, attrs));
+ let lo = e.span.lo;
+ let e = try!(self.parse_dot_or_call_expr_with(e, lo, attrs));
let e = try!(self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e)));
try!(self.handle_expression_like_statement(
e,