aboutsummaryrefslogtreecommitdiffstats
path: root/src/lit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lit.rs')
-rw-r--r--src/lit.rs172
1 files changed, 98 insertions, 74 deletions
diff --git a/src/lit.rs b/src/lit.rs
index ee77e75b..e45b81ba 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -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)
}