diff options
Diffstat (limited to 'src/lit.rs')
-rw-r--r-- | src/lit.rs | 172 |
1 files changed, 98 insertions, 74 deletions
@@ -1,23 +1,18 @@ -use proc_macro2::{Literal, Span}; -use std::fmt::{self, Display}; -use std::str::{self, FromStr}; - +#[cfg(feature = "parsing")] +use crate::lookahead; +#[cfg(feature = "parsing")] +use crate::parse::{Parse, Parser}; +use crate::{Error, Result}; #[cfg(feature = "printing")] use proc_macro2::Ident; - #[cfg(feature = "parsing")] use proc_macro2::TokenStream; - use proc_macro2::TokenTree; - +use proc_macro2::{Literal, Span}; +use std::fmt::{self, Display}; #[cfg(feature = "extra-traits")] use std::hash::{Hash, Hasher}; - -#[cfg(feature = "parsing")] -use crate::lookahead; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, Parser}; -use crate::{Error, Result}; +use std::str::{self, FromStr}; ast_enum_of_structs! { /// A Rust literal such as a string or integer or boolean. @@ -108,7 +103,7 @@ struct LitIntRepr { ast_struct! { /// A floating point literal: `1f64` or `1.0e10f64`. /// - /// Must be finite. May not be infinte or NaN. + /// Must be finite. May not be infinite or NaN. pub struct LitFloat { repr: Box<LitFloatRepr>, } @@ -730,21 +725,19 @@ pub mod parsing { let mut repr = lit.to_string(); repr.insert(0, '-'); - if !(repr.ends_with("f32") || repr.ends_with("f64")) { - if let Some((digits, suffix)) = value::parse_lit_int(&repr) { - if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) { - token.set_span(span); - return Some(( - Lit::Int(LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), + if let Some((digits, suffix)) = value::parse_lit_int(&repr) { + if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) { + token.set_span(span); + return Some(( + Lit::Int(LitInt { + repr: Box::new(LitIntRepr { + token, + digits, + suffix, }), - rest, - )); - } + }), + rest, + )); } } @@ -766,8 +759,8 @@ pub mod parsing { impl Parse for LitStr { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Str(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Str(lit)) => Ok(lit), _ => Err(head.error("expected string literal")), } } @@ -776,8 +769,8 @@ pub mod parsing { impl Parse for LitByteStr { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::ByteStr(lit) => Ok(lit), + match input.parse() { + Ok(Lit::ByteStr(lit)) => Ok(lit), _ => Err(head.error("expected byte string literal")), } } @@ -786,8 +779,8 @@ pub mod parsing { impl Parse for LitByte { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Byte(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Byte(lit)) => Ok(lit), _ => Err(head.error("expected byte literal")), } } @@ -796,8 +789,8 @@ pub mod parsing { impl Parse for LitChar { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Char(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Char(lit)) => Ok(lit), _ => Err(head.error("expected character literal")), } } @@ -806,8 +799,8 @@ pub mod parsing { impl Parse for LitInt { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Int(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Int(lit)) => Ok(lit), _ => Err(head.error("expected integer literal")), } } @@ -816,8 +809,8 @@ pub mod parsing { impl Parse for LitFloat { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Float(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Float(lit)) => Ok(lit), _ => Err(head.error("expected floating point literal")), } } @@ -826,8 +819,8 @@ pub mod parsing { impl Parse for LitBool { fn parse(input: ParseStream) -> Result<Self> { let head = input.fork(); - match input.parse()? { - Lit::Bool(lit) => Ok(lit), + match input.parse() { + Ok(Lit::Bool(lit)) => Ok(lit), _ => Err(head.error("expected boolean literal")), } } @@ -925,16 +918,14 @@ mod value { }); } b'0'..=b'9' | b'-' => { - if !(repr.ends_with("f32") || repr.ends_with("f64")) { - if let Some((digits, suffix)) = parse_lit_int(&repr) { - return Lit::Int(LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), - }); - } + if let Some((digits, suffix)) = parse_lit_int(&repr) { + return Lit::Int(LitInt { + repr: Box::new(LitIntRepr { + token, + digits, + suffix, + }), + }); } if let Some((digits, suffix)) = parse_lit_float(&repr) { return Lit::Float(LitFloat { @@ -1294,27 +1285,28 @@ mod value { s = &s[1..]; let mut ch = 0; - for _ in 0..6 { + let mut digits = 0; + loop { let b = byte(s, 0); - match b { - b'0'..=b'9' => { - ch *= 0x10; - ch += u32::from(b - b'0'); - s = &s[1..]; - } - b'a'..=b'f' => { - ch *= 0x10; - ch += u32::from(10 + b - b'a'); - s = &s[1..]; - } - b'A'..=b'F' => { - ch *= 0x10; - ch += u32::from(10 + b - b'A'); + let digit = match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => 10 + b - b'a', + b'A'..=b'F' => 10 + b - b'A', + b'_' if digits > 0 => { s = &s[1..]; + continue; } + b'}' if digits == 0 => panic!("invalid empty unicode escape"), b'}' => break, _ => panic!("unexpected non-hex character after \\u"), + }; + if digits == 6 { + panic!("overlong unicode escape (must have at most 6 hex digits)"); } + ch *= 0x10; + ch += u32::from(digit); + digits += 1; + s = &s[1..]; } assert!(byte(s, 0) == b'}'); s = &s[1..]; @@ -1351,7 +1343,7 @@ mod value { }; let mut value = BigInt::new(); - loop { + 'outer: loop { let b = byte(s, 0); let digit = match b { b'0'..=b'9' => b - b'0', @@ -1361,10 +1353,32 @@ mod value { s = &s[1..]; continue; } - // NOTE: Looking at a floating point literal, we don't want to - // consider these integers. + // If looking at a floating point literal, we don't want to + // consider it an integer. b'.' if base == 10 => return None, - b'e' | b'E' if base == 10 => return None, + b'e' | b'E' if base == 10 => { + let mut has_exp = false; + for (i, b) in s[1..].bytes().enumerate() { + match b { + b'_' => {} + b'-' | b'+' => return None, + b'0'..=b'9' => has_exp = true, + _ => { + let suffix = &s[1 + i..]; + if has_exp && crate::ident::xid_ok(suffix) { + return None; + } else { + break 'outer; + } + } + } + } + if has_exp { + return None; + } else { + break; + } + } _ => break, }; @@ -1430,6 +1444,14 @@ mod value { bytes[write] = b'.'; } b'e' | b'E' => { + match bytes[read + 1..] + .iter() + .find(|b| **b != b'_') + .unwrap_or(&b'\0') + { + b'-' | b'+' | b'0'..=b'9' => {} + _ => break, + } if has_e { if has_exponent { break; @@ -1475,10 +1497,12 @@ mod value { pub fn to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal> { if repr.starts_with('-') { + let f64_parse_finite = || digits.parse().ok().filter(|x: &f64| x.is_finite()); + let f32_parse_finite = || digits.parse().ok().filter(|x: &f32| x.is_finite()); if suffix == "f64" { - digits.parse().ok().map(Literal::f64_suffixed) + f64_parse_finite().map(Literal::f64_suffixed) } else if suffix == "f32" { - digits.parse().ok().map(Literal::f32_suffixed) + f32_parse_finite().map(Literal::f32_suffixed) } else if suffix == "i64" { digits.parse().ok().map(Literal::i64_suffixed) } else if suffix == "i32" { @@ -1490,7 +1514,7 @@ mod value { } else if !suffix.is_empty() { None } else if digits.contains('.') { - digits.parse().ok().map(Literal::f64_unsuffixed) + f64_parse_finite().map(Literal::f64_unsuffixed) } else { digits.parse().ok().map(Literal::i64_unsuffixed) } |