diff --git a/lang-pp/Cargo.toml b/lang-pp/Cargo.toml index a237f4a5c..5a297de05 100644 --- a/lang-pp/Cargo.toml +++ b/lang-pp/Cargo.toml @@ -18,7 +18,6 @@ lang-util = "0.5.0" string_cache = "0.8" thiserror = "1.0" -lexical = "6.1" arrayvec = "0.7" derive_more = "0.99" diff --git a/lang-pp/src/processor/expr.rs b/lang-pp/src/processor/expr.rs index 1b249d4f3..f3120fdd5 100644 --- a/lang-pp/src/processor/expr.rs +++ b/lang-pp/src/processor/expr.rs @@ -2,6 +2,7 @@ use std::iter::Peekable; use crate::{ parser::SyntaxKind::{self, *}, + types::Token, util::Unescaped, }; @@ -66,8 +67,12 @@ impl<'i, I: Iterator> ExprEvaluator<'i, I> { DIGITS => { // Try to parse the value before bumping. If parsing fails, we'll return the DIGITS // token unparsed - if let Ok(value) = lexical::parse(Unescaped::new(token.text()).to_string().as_ref()) - { + let value = match Token::parse_digits(&Unescaped::new(token.text()).to_string()) { + Token::UINT_CONST(value) if value <= i32::MAX as u32 => Some(value as i32), + Token::INT_CONST(value) => Some(value), + _ => None, + }; + if let Some(value) = value { self.bump(); return Some(Ok(value)); } diff --git a/lang-pp/src/processor/nodes.rs b/lang-pp/src/processor/nodes.rs index 189d15433..a0de6d548 100644 --- a/lang-pp/src/processor/nodes.rs +++ b/lang-pp/src/processor/nodes.rs @@ -10,7 +10,10 @@ use crate::{ exts::names::ExtNameAtom, parser::{SyntaxKind::*, SyntaxNode, SyntaxToken}, processor::expr::{EvalResult, ExprEvaluator}, - types::path::{ParsedPath, PathType}, + types::{ + path::{ParsedPath, PathType}, + Token, + }, util::Unescaped, }; @@ -123,7 +126,7 @@ pub enum VersionError { #[error("missing version number in #version directive")] MissingVersionNumber, #[error("invalid version number in #version directive")] - InvalidVersionNumber(#[from] lexical::Error), + InvalidVersionNumber { version_number: String }, #[error("unsupported version number in #version directive")] UnsupportedVersionNumber, #[error("invalid version profile")] @@ -143,7 +146,17 @@ impl TryFrom<(FileId, SyntaxNode)> for Version { fn try_from((_file_id, value): (FileId, SyntaxNode)) -> Result { // Parse version number - // TODO: Replace use of lexical with glsl parser + // The GLSL spec refers to the ISO/IEC 14882:1998 (C++) standard for preprocessor + // directives, and mentions that #version, due to it "following the same convention" + // as __VERSION__, is "a decimal integer". The cited standard, section 2.9 + // "Preprocessing numbers", says that such numbers "lexically include all integral + // literal tokens". These correspond to the "integer-constant" (for the GLSL grammar) + // or "integer-literal" (for the C++ grammar) grammar symbols. But, because #version + // is a decimal integer, it is understood that the only "integer-constant" production + // rule we have to accept is the one for decimal constants, which are sequences of + // decimal digits beginning with a nonzero digit and followed by an optional + // "integer-suffix" (u or U character). This is a subset of what we can parse as + // (U)INT_CONST tokens, but other implementations are likely to observe Postel's law let version_number: u16 = value .children() .find_map(|token| { @@ -155,8 +168,20 @@ impl TryFrom<(FileId, SyntaxNode)> for Version { }) .ok_or(Self::Error::MissingVersionNumber) .and_then(|token| { - lexical::parse(Unescaped::new(token.text()).to_string().as_ref()) - .map_err(Into::into) + let token_string = Unescaped::new(token.text()).to_string(); + match Token::parse_digits(&token_string) { + Token::INT_CONST(version_number) + if version_number >= 0 && version_number <= u16::MAX as i32 => + { + Ok(version_number as u16) + } + Token::UINT_CONST(version_number) if version_number <= u16::MAX as u32 => { + Ok(version_number as u16) + } + _ => Err(Self::Error::InvalidVersionNumber { + version_number: token_string.into_owned(), + }), + } })?; // Check the version number is supported diff --git a/lang-pp/src/types/token.rs b/lang-pp/src/types/token.rs index abcc59c8d..840b1cd8c 100644 --- a/lang-pp/src/types/token.rs +++ b/lang-pp/src/types/token.rs @@ -1983,7 +1983,7 @@ impl Token { } fn strip_suffix(text: &str) -> (bool, &str) { - if let Some(stripped) = text.strip_suffix('u').or_else(|| text.strip_suffix('U')) { + if let Some(stripped) = text.strip_suffix(&['u', 'U']) { (true, stripped) } else { (false, text) @@ -2025,14 +2025,13 @@ impl Token { // Floating-point constant if let Some(double) = text.strip_suffix("lf").or_else(|| text.strip_suffix("LF")) { - lexical::parse(double) + double + .parse() .map(DOUBLE_CONST) .map_err(|_| ErrorKind::InvalidDoubleLiteral) - } else if let Some(float) = text - .strip_suffix('f') - .or_else(|| text.strip_suffix('F').or(Some(text))) - { - lexical::parse(float) + } else if let Some(float) = text.strip_suffix(&['f', 'F']).or(Some(text)) { + float + .parse() .map(FLOAT_CONST) .map_err(|_| ErrorKind::InvalidFloatLiteral) } else {