move parse_lit to expr.rs
This commit is contained in:
parent
52d0e86b9a
commit
79d02867b8
3 changed files with 170 additions and 177 deletions
|
@ -1,14 +1,10 @@
|
|||
//! Code related to parsing literals.
|
||||
|
||||
use crate::ast::{self, Lit, LitKind};
|
||||
use crate::parse::parser::Parser;
|
||||
use crate::parse::PResult;
|
||||
use crate::parse::token::{self, Token, TokenKind};
|
||||
use crate::print::pprust;
|
||||
use crate::parse::token::{self, Token};
|
||||
use crate::symbol::{kw, sym, Symbol};
|
||||
use crate::tokenstream::{TokenStream, TokenTree};
|
||||
|
||||
use errors::{Applicability, Handler};
|
||||
use log::debug;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax_pos::Span;
|
||||
|
@ -28,72 +24,6 @@ crate enum LitError {
|
|||
IntTooLarge,
|
||||
}
|
||||
|
||||
impl LitError {
|
||||
fn report(&self, diag: &Handler, lit: token::Lit, span: Span) {
|
||||
let token::Lit { kind, suffix, .. } = lit;
|
||||
match *self {
|
||||
// `NotLiteral` is not an error by itself, so we don't report
|
||||
// it and give the parser opportunity to try something else.
|
||||
LitError::NotLiteral => {}
|
||||
// `LexerError` *is* an error, but it was already reported
|
||||
// by lexer, so here we don't report it the second time.
|
||||
LitError::LexerError => {}
|
||||
LitError::InvalidSuffix => {
|
||||
expect_no_suffix(
|
||||
diag, span, &format!("{} {} literal", kind.article(), kind.descr()), suffix
|
||||
);
|
||||
}
|
||||
LitError::InvalidIntSuffix => {
|
||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
||||
if looks_like_width_suffix(&['i', 'u'], &suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
|
||||
diag.struct_span_err(span, &msg)
|
||||
.help("valid widths are 8, 16, 32, 64 and 128")
|
||||
.emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for integer literal", suf);
|
||||
diag.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
LitError::InvalidFloatSuffix => {
|
||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
||||
if looks_like_width_suffix(&['f'], &suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
let msg = format!("invalid width `{}` for float literal", &suf[1..]);
|
||||
diag.struct_span_err(span, &msg)
|
||||
.help("valid widths are 32 and 64")
|
||||
.emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for float literal", suf);
|
||||
diag.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.help("valid suffixes are `f32` and `f64`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
LitError::NonDecimalFloat(base) => {
|
||||
let descr = match base {
|
||||
16 => "hexadecimal",
|
||||
8 => "octal",
|
||||
2 => "binary",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
diag.struct_span_err(span, &format!("{} float literal is not supported", descr))
|
||||
.span_label(span, "not supported")
|
||||
.emit();
|
||||
}
|
||||
LitError::IntTooLarge => {
|
||||
diag.struct_span_err(span, "integer literal is too large")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LitKind {
|
||||
/// Converts literal token into a semantic literal.
|
||||
fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||
|
@ -254,7 +184,7 @@ impl LitKind {
|
|||
|
||||
impl Lit {
|
||||
/// Converts literal token into an AST literal.
|
||||
fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
|
||||
crate fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
|
||||
Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
|
||||
}
|
||||
|
||||
|
@ -296,99 +226,6 @@ impl Lit {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Matches `lit = true | false | token_lit`.
|
||||
crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
||||
let mut recovered = None;
|
||||
if self.token == token::Dot {
|
||||
// Attempt to recover `.4` as `0.4`.
|
||||
recovered = self.look_ahead(1, |next_token| {
|
||||
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
|
||||
= next_token.kind {
|
||||
if self.token.span.hi() == next_token.span.lo() {
|
||||
let s = String::from("0.") + &symbol.as_str();
|
||||
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
|
||||
return Some(Token::new(kind, self.token.span.to(next_token.span)));
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
if let Some(token) = &recovered {
|
||||
self.bump();
|
||||
self.diagnostic()
|
||||
.struct_span_err(token.span, "float literals must have an integer part")
|
||||
.span_suggestion(
|
||||
token.span,
|
||||
"must have an integer part",
|
||||
pprust::token_to_string(token),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let token = recovered.as_ref().unwrap_or(&self.token);
|
||||
match Lit::from_token(token) {
|
||||
Ok(lit) => {
|
||||
self.bump();
|
||||
Ok(lit)
|
||||
}
|
||||
Err(LitError::NotLiteral) => {
|
||||
let msg = format!("unexpected token: {}", self.this_token_descr());
|
||||
Err(self.span_fatal(token.span, &msg))
|
||||
}
|
||||
Err(err) => {
|
||||
let (lit, span) = (token.expect_lit(), token.span);
|
||||
self.bump();
|
||||
err.report(&self.sess.span_diagnostic, lit, span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
// the error literal's symbol so they can be pretty-printed faithfully.
|
||||
let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
|
||||
let symbol = Symbol::intern(&suffixless_lit.to_string());
|
||||
let lit = token::Lit::new(token::Err, symbol, lit.suffix);
|
||||
Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn expect_no_suffix(diag: &Handler, sp: Span, kind: &str, suffix: Option<Symbol>) {
|
||||
if let Some(suf) = suffix {
|
||||
let mut err = if kind == "a tuple index" &&
|
||||
[sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) {
|
||||
// #59553: warn instead of reject out of hand to allow the fix to percolate
|
||||
// through the ecosystem when people fix their macros
|
||||
let mut err = diag.struct_span_warn(
|
||||
sp,
|
||||
&format!("suffixes on {} are invalid", kind),
|
||||
);
|
||||
err.note(&format!(
|
||||
"`{}` is *temporarily* accepted on tuple index fields as it was \
|
||||
incorrectly accepted on stable for a few releases",
|
||||
suf,
|
||||
));
|
||||
err.help(
|
||||
"on proc macros, you'll want to use `syn::Index::from` or \
|
||||
`proc_macro::Literal::*_unsuffixed` for code that will desugar \
|
||||
to tuple field access",
|
||||
);
|
||||
err.note(
|
||||
"for more context, see https://github.com/rust-lang/rust/issues/60210",
|
||||
);
|
||||
err
|
||||
} else {
|
||||
diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
|
||||
};
|
||||
err.span_label(sp, format!("invalid suffix `{}`", suf));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if `s` looks like i32 or u1234 etc.
|
||||
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
|
||||
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
|
||||
}
|
||||
|
||||
fn strip_underscores(symbol: Symbol) -> Symbol {
|
||||
// Do not allocate a new string unless necessary.
|
||||
let s = symbol.as_str();
|
||||
|
|
|
@ -15,10 +15,10 @@ use crate::ast::{
|
|||
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
|
||||
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
|
||||
};
|
||||
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token};
|
||||
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep};
|
||||
use crate::parse::lexer::UnmatchedBrace;
|
||||
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||
use crate::parse::token::{Token, TokenKind, DelimToken};
|
||||
use crate::parse::token::{self, Token, TokenKind, DelimToken};
|
||||
use crate::print::pprust;
|
||||
use crate::ptr::P;
|
||||
use crate::source_map::respan;
|
||||
|
@ -637,10 +637,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
|
||||
literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix)
|
||||
}
|
||||
|
||||
/// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
|
||||
/// `<` and continue. If `<-` is seen, replaces it with a single `<`
|
||||
/// and continue. If a `<` is not seen, returns false.
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use super::{
|
||||
Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode, SemiColonMode,
|
||||
SeqSep, TokenExpectType,
|
||||
};
|
||||
use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode};
|
||||
use super::{SemiColonMode, SeqSep, TokenExpectType};
|
||||
use super::pat::{GateOr, PARAM_EXPECTED};
|
||||
|
||||
use crate::parse::literal::LitError;
|
||||
|
||||
use crate::ast::{
|
||||
self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
|
||||
Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
|
||||
FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field,
|
||||
FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit,
|
||||
};
|
||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use crate::parse::classify;
|
||||
use crate::parse::token::{self, Token};
|
||||
use crate::parse::token::{self, Token, TokenKind};
|
||||
use crate::parse::diagnostics::Error;
|
||||
use crate::print::pprust;
|
||||
use crate::ptr::P;
|
||||
|
@ -20,6 +20,7 @@ use crate::symbol::{kw, sym};
|
|||
use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
|
||||
|
||||
use errors::Applicability;
|
||||
use syntax_pos::Symbol;
|
||||
use std::mem;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
|
||||
|
@ -1072,6 +1073,165 @@ impl<'a> Parser<'a> {
|
|||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
}
|
||||
|
||||
/// Matches `lit = true | false | token_lit`.
|
||||
crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
||||
let mut recovered = None;
|
||||
if self.token == token::Dot {
|
||||
// Attempt to recover `.4` as `0.4`.
|
||||
recovered = self.look_ahead(1, |next_token| {
|
||||
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
|
||||
= next_token.kind {
|
||||
if self.token.span.hi() == next_token.span.lo() {
|
||||
let s = String::from("0.") + &symbol.as_str();
|
||||
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
|
||||
return Some(Token::new(kind, self.token.span.to(next_token.span)));
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
if let Some(token) = &recovered {
|
||||
self.bump();
|
||||
self.struct_span_err(token.span, "float literals must have an integer part")
|
||||
.span_suggestion(
|
||||
token.span,
|
||||
"must have an integer part",
|
||||
pprust::token_to_string(token),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let token = recovered.as_ref().unwrap_or(&self.token);
|
||||
match Lit::from_token(token) {
|
||||
Ok(lit) => {
|
||||
self.bump();
|
||||
Ok(lit)
|
||||
}
|
||||
Err(LitError::NotLiteral) => {
|
||||
let msg = format!("unexpected token: {}", self.this_token_descr());
|
||||
Err(self.span_fatal(token.span, &msg))
|
||||
}
|
||||
Err(err) => {
|
||||
let (lit, span) = (token.expect_lit(), token.span);
|
||||
self.bump();
|
||||
self.error_literal_from_token(err, lit, span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
// the error literal's symbol so they can be pretty-printed faithfully.
|
||||
let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
|
||||
let symbol = Symbol::intern(&suffixless_lit.to_string());
|
||||
let lit = token::Lit::new(token::Err, symbol, lit.suffix);
|
||||
Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) {
|
||||
// Checks if `s` looks like i32 or u1234 etc.
|
||||
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
|
||||
s.len() > 1
|
||||
&& s.starts_with(first_chars)
|
||||
&& s[1..].chars().all(|c| c.is_ascii_digit())
|
||||
}
|
||||
|
||||
let token::Lit { kind, suffix, .. } = lit;
|
||||
match err {
|
||||
// `NotLiteral` is not an error by itself, so we don't report
|
||||
// it and give the parser opportunity to try something else.
|
||||
LitError::NotLiteral => {}
|
||||
// `LexerError` *is* an error, but it was already reported
|
||||
// by lexer, so here we don't report it the second time.
|
||||
LitError::LexerError => {}
|
||||
LitError::InvalidSuffix => {
|
||||
self.expect_no_suffix(
|
||||
span,
|
||||
&format!("{} {} literal", kind.article(), kind.descr()),
|
||||
suffix,
|
||||
);
|
||||
}
|
||||
LitError::InvalidIntSuffix => {
|
||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
||||
if looks_like_width_suffix(&['i', 'u'], &suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
|
||||
self.struct_span_err(span, &msg)
|
||||
.help("valid widths are 8, 16, 32, 64 and 128")
|
||||
.emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for integer literal", suf);
|
||||
self.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
LitError::InvalidFloatSuffix => {
|
||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
||||
if looks_like_width_suffix(&['f'], &suf) {
|
||||
// If it looks like a width, try to be helpful.
|
||||
let msg = format!("invalid width `{}` for float literal", &suf[1..]);
|
||||
self.struct_span_err(span, &msg)
|
||||
.help("valid widths are 32 and 64")
|
||||
.emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for float literal", suf);
|
||||
self.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.help("valid suffixes are `f32` and `f64`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
LitError::NonDecimalFloat(base) => {
|
||||
let descr = match base {
|
||||
16 => "hexadecimal",
|
||||
8 => "octal",
|
||||
2 => "binary",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.struct_span_err(span, &format!("{} float literal is not supported", descr))
|
||||
.span_label(span, "not supported")
|
||||
.emit();
|
||||
}
|
||||
LitError::IntTooLarge => {
|
||||
self.struct_span_err(span, "integer literal is too large")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbol>) {
|
||||
if let Some(suf) = suffix {
|
||||
let mut err = if kind == "a tuple index"
|
||||
&& [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf)
|
||||
{
|
||||
// #59553: warn instead of reject out of hand to allow the fix to percolate
|
||||
// through the ecosystem when people fix their macros
|
||||
let mut err = self.sess.span_diagnostic.struct_span_warn(
|
||||
sp,
|
||||
&format!("suffixes on {} are invalid", kind),
|
||||
);
|
||||
err.note(&format!(
|
||||
"`{}` is *temporarily* accepted on tuple index fields as it was \
|
||||
incorrectly accepted on stable for a few releases",
|
||||
suf,
|
||||
));
|
||||
err.help(
|
||||
"on proc macros, you'll want to use `syn::Index::from` or \
|
||||
`proc_macro::Literal::*_unsuffixed` for code that will desugar \
|
||||
to tuple field access",
|
||||
);
|
||||
err.note(
|
||||
"for more context, see https://github.com/rust-lang/rust/issues/60210",
|
||||
);
|
||||
err
|
||||
} else {
|
||||
self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
|
||||
};
|
||||
err.span_label(sp, format!("invalid suffix `{}`", suf));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
|
||||
crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
|
||||
maybe_whole_expr!(self);
|
||||
|
|
Loading…
Add table
Reference in a new issue