use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
use parse::lexer::{Reader, TokenAndSpan};
use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax};
-use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
+use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString};
use parse::token::{keywords, special_idents, SpecialMacroVar};
use parse::{new_sub_parser_from_file, ParseSess};
use util::parser::{AssocOp, Fixity};
)
}
+ // 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>) -> PResult<'a, P<Expr>> {
let mut e = e0;
let lo = e.span.lo;
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;
}
// We have 2 alternatives here: `x..y` and `x..` The other two variants are
// handled with `parse_prefix_range_expr` call above.
let rhs = if self.is_at_start_of_range_notation_rhs() {
- self.parse_assoc_expr_with(op.precedence() + 1,
- LhsExpr::NotYetParsed).ok()
+ let rhs = self.parse_assoc_expr_with(op.precedence() + 1,
+ LhsExpr::NotYetParsed);
+ match rhs {
+ Ok(e) => Some(e),
+ Err(mut e) => {
+ e.cancel();
+ None
+ }
+ }
} else {
None
};
}
let rhs = try!(match op.fixity() {
- Fixity::Right => self.with_res(restrictions, |this|{
- this.parse_assoc_expr_with(op.precedence(), LhsExpr::NotYetParsed)
+ Fixity::Right => self.with_res(
+ restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+ |this| {
+ this.parse_assoc_expr_with(op.precedence(),
+ LhsExpr::NotYetParsed)
}),
- Fixity::Left => self.with_res(restrictions, |this|{
- this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed)
+ Fixity::Left => self.with_res(
+ restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+ |this| {
+ this.parse_assoc_expr_with(op.precedence() + 1,
+ LhsExpr::NotYetParsed)
}),
// We currently have no non-associative operators that are not handled above by
// the special cases. The code is here only for future convenience.
- Fixity::None => self.with_res(restrictions, |this|{
- this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed)
+ Fixity::None => self.with_res(
+ restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+ |this| {
+ this.parse_assoc_expr_with(op.precedence() + 1,
+ LhsExpr::NotYetParsed)
}),
});
let mut err = self.diagnostic().struct_span_err(self.span, &msg);
let span_hi = self.span.hi;
- let span_hi = if self.parse_ty().is_ok() {
- self.span.hi
- } else {
- span_hi
+ let span_hi = match self.parse_ty() {
+ Ok(..) => self.span.hi,
+ Err(ref mut err) => {
+ err.cancel();
+ span_hi
+ }
};
let msg = format!("did you mean a single argument type &'a Type, \
fn complain_if_pub_macro(&mut self, visa: Visibility, span: Span) {
match visa {
Public => {
- self.diagnostic().struct_span_err(span, "can't qualify macro invocation with `pub`")
- .fileline_help(span, "try adjusting the macro to put `pub` inside \
- the invocation")
- .emit();
+ let is_macro_rules: bool = match self.token {
+ token::Ident(sid, _) => sid.name == intern("macro_rules"),
+ _ => false,
+ };
+ if is_macro_rules {
+ self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
+ invocation with `pub`")
+ .fileline_help(span, "did you mean #[macro_export]?")
+ .emit();
+ } else {
+ self.diagnostic().struct_span_err(span, "can't qualify macro \
+ invocation with `pub`")
+ .fileline_help(span, "try adjusting the macro to put `pub` \
+ inside the invocation")
+ .emit();
+ }
}
Inherited => (),
}