summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast/src/token.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ast/src/token.rs')
-rw-r--r--compiler/rustc_ast/src/token.rs88
1 files changed, 67 insertions, 21 deletions
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 83b10d906..c0cc4e79a 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -5,6 +5,7 @@ pub use TokenKind::*;
use crate::ast;
use crate::ptr::P;
+use crate::util::case::Case;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
@@ -58,13 +59,17 @@ pub enum Delimiter {
Invisible,
}
+// Note that the suffix is *not* considered when deciding the `LitKind` in this
+// type. This means that float literals like `1f32` are classified by this type
+// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
+// given the `Float` kind.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum LitKind {
Bool, // AST only, must never appear in a `Token`
Byte,
Char,
- Integer,
- Float,
+ Integer, // e.g. `1`, `1u8`, `1f32`
+ Float, // e.g. `1.`, `1.0`, `1e3f32`
Str,
StrRaw(u8), // raw string delimited by `n` hash symbols
ByteStr,
@@ -80,6 +85,42 @@ pub struct Lit {
pub suffix: Option<Symbol>,
}
+impl Lit {
+ pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
+ Lit { kind, symbol, suffix }
+ }
+
+ /// Returns `true` if this is semantically a float literal. This includes
+ /// ones like `1f32` that have an `Integer` kind but a float suffix.
+ pub fn is_semantic_float(&self) -> bool {
+ match self.kind {
+ LitKind::Float => true,
+ LitKind::Integer => match self.suffix {
+ Some(sym) => sym == sym::f32 || sym == sym::f64,
+ None => false,
+ },
+ _ => false,
+ }
+ }
+
+ /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
+ pub fn from_token(token: &Token) -> Option<Lit> {
+ match token.uninterpolate().kind {
+ Ident(name, false) if name.is_bool_lit() => {
+ Some(Lit::new(Bool, name, None))
+ }
+ Literal(token_lit) => Some(token_lit),
+ Interpolated(ref nt)
+ if let NtExpr(expr) | NtLiteral(expr) = &**nt
+ && let ast::ExprKind::Lit(token_lit) = expr.kind =>
+ {
+ Some(token_lit.clone())
+ }
+ _ => None,
+ }
+ }
+}
+
impl fmt::Display for Lit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Lit { kind, symbol, suffix } = *self;
@@ -138,12 +179,6 @@ impl LitKind {
}
}
-impl Lit {
- pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
- Lit { kind, symbol, suffix }
- }
-}
-
pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
let ident_token = Token::new(Ident(name, is_raw), span);
@@ -267,9 +302,9 @@ impl TokenKind {
Literal(Lit::new(kind, symbol, suffix))
}
- // An approximation to proc-macro-style single-character operators used by rustc parser.
- // If the operator token can be broken into two tokens, the first of which is single-character,
- // then this function performs that operation, otherwise it returns `None`.
+ /// An approximation to proc-macro-style single-character operators used by rustc parser.
+ /// If the operator token can be broken into two tokens, the first of which is single-character,
+ /// then this function performs that operation, otherwise it returns `None`.
pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
Some(match *self {
Le => (Lt, Eq),
@@ -503,10 +538,10 @@ impl Token {
}
}
- // A convenience function for matching on identifiers during parsing.
- // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
- // into the regular identifier or lifetime token it refers to,
- // otherwise returns the original token.
+ /// A convenience function for matching on identifiers during parsing.
+ /// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
+ /// into the regular identifier or lifetime token it refers to,
+ /// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
Interpolated(nt) => match **nt {
@@ -566,9 +601,10 @@ impl Token {
/// Returns `true` if the token is an interpolated path.
fn is_path(&self) -> bool {
- if let Interpolated(ref nt) = self.kind && let NtPath(..) = **nt {
+ if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt {
return true;
}
+
false
}
@@ -576,7 +612,7 @@ impl Token {
/// That is, is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
- if let Interpolated(ref nt) = self.kind
+ if let Interpolated(nt) = &self.kind
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
{
return true;
@@ -585,11 +621,12 @@ impl Token {
false
}
- // Is the token an interpolated block (`$b:block`)?
+ /// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool {
- if let Interpolated(ref nt) = self.kind && let NtBlock(..) = **nt {
+ if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt {
return true;
}
+
false
}
@@ -615,12 +652,21 @@ impl Token {
self.is_non_raw_ident_where(|id| id.name == kw)
}
+ /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
+ pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
+ self.is_keyword(kw)
+ || (case == Case::Insensitive
+ && self.is_non_raw_ident_where(|id| {
+ id.name.as_str().to_lowercase() == kw.as_str().to_lowercase()
+ }))
+ }
+
pub fn is_path_segment_keyword(&self) -> bool {
self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
}
- // Returns true for reserved identifiers used internally for elided lifetimes,
- // unnamed method parameters, crate root module, error recovery etc.
+ /// Returns true for reserved identifiers used internally for elided lifetimes,
+ /// unnamed method parameters, crate root module, error recovery etc.
pub fn is_special_ident(&self) -> bool {
self.is_non_raw_ident_where(Ident::is_special)
}