diff --git a/src/front/wgsl/number.rs b/src/front/wgsl/number.rs index 977b34d7c3..d7e8801b09 100644 --- a/src/front/wgsl/number.rs +++ b/src/front/wgsl/number.rs @@ -17,33 +17,40 @@ pub enum Number { F32(f32), } +impl Number { + /// Convert abstract numbers to a plausible concrete counterpart. + /// + /// Return concrete numbers unchanged. If the conversion would be + /// lossy, return an error. + fn abstract_to_concrete(self) -> Result { + match self { + Number::AbstractInt(num) => { + use std::convert::TryFrom; + i32::try_from(num) + .map(Number::I32) + .map_err(|_| NumberError::NotRepresentable) + } + Number::AbstractFloat(num) => { + let num = num as f32; + if num.is_finite() { + Ok(Number::F32(num)) + } else { + Err(NumberError::NotRepresentable) + } + } + num => Ok(num), + } + } +} + // TODO: when implementing Creation-Time Expressions, remove the ability to match the minus sign pub(super) fn consume_number(input: &str) -> (Token<'_>, &str) { - let res = if let Some((num, rest)) = parse(input) { - (num, rest) - } else { - (Err(NumberError::Invalid), input) - }; - - let num = match res.0 { - Ok(Number::AbstractInt(num)) => { - use std::convert::TryFrom; - i32::try_from(num) - .map(Number::I32) - .map_err(|_| NumberError::NotRepresentable) - } - Ok(Number::AbstractFloat(num)) => { - let num = num as f32; - if num.is_finite() { - Ok(Number::F32(num)) - } else { - Err(NumberError::NotRepresentable) - } - } - num => num, - }; - (Token::Number(num), res.1) + let (result, rest) = parse(input); + ( + Token::Number(result.and_then(Number::abstract_to_concrete)), + rest, + ) } enum Kind { @@ -83,7 +90,7 @@ enum FloatKind { // You could visualize the regex below via https://debuggex.com to get a rough idea what `parse` is doing // -?(?:0[xX](?:([0-9a-fA-F]+\.[0-9a-fA-F]*|[0-9a-fA-F]*\.[0-9a-fA-F]+)(?:([pP][+-]?[0-9]+)([fh]?))?|([0-9a-fA-F]+)([pP][+-]?[0-9]+)([fh]?)|([0-9a-fA-F]+)([iu]?))|((?:[0-9]+[eE][+-]?[0-9]+|(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?))([fh]?)|((?:[0-9]|[1-9][0-9]+))([iufh]?)) -fn parse(input: &str) -> Option<(Result, &str)> { +fn parse(input: &str) -> (Result, &str) { /// returns `true` and consumes `X` bytes from the given byte buffer /// if the given `X` nr of patterns are found at the start of the buffer macro_rules! consume { @@ -170,7 +177,7 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed_after_period = consume_hex_digits!(bytes); if consumed + consumed_after_period == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let significand = general_extract.end(bytes); @@ -180,23 +187,23 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed = consume_dec_digits!(bytes); if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let number = general_extract.end(bytes); let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]); - Some((parse_hex_float(number, kind), rest_to_str!(bytes))) + (parse_hex_float(number, kind), rest_to_str!(bytes)) } else { - Some(( + ( parse_hex_float_missing_exponent(significand, None), rest_to_str!(bytes), - )) + ) } } else { if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let significand = general_extract.end(bytes); @@ -209,24 +216,24 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed = consume_dec_digits!(bytes); if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let exponent = exp_extract.end(bytes); let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]); - Some(( + ( parse_hex_float_missing_period(significand, exponent, kind), rest_to_str!(bytes), - )) + ) } else { let kind = consume_map!(bytes, [b'i' => IntKind::I32, b'u' => IntKind::U32]); - Some(( + ( parse_hex_int(is_negative, digits, kind), rest_to_str!(bytes), - )) + ) } } } else { @@ -238,7 +245,7 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed_after_period = consume_dec_digits!(bytes); if consumed + consumed_after_period == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } if consume!(bytes, b'e' | b'E') { @@ -246,7 +253,7 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed = consume_dec_digits!(bytes); if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } } @@ -254,10 +261,10 @@ fn parse(input: &str) -> Option<(Result, &str)> { let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]); - Some((parse_dec_float(number, kind), rest_to_str!(bytes))) + (parse_dec_float(number, kind), rest_to_str!(bytes)) } else { if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } if consume!(bytes, b'e' | b'E') { @@ -265,18 +272,18 @@ fn parse(input: &str) -> Option<(Result, &str)> { let consumed = consume_dec_digits!(bytes); if consumed == 0 { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let number = general_extract.end(bytes); let kind = consume_map!(bytes, [b'f' => FloatKind::F32, b'h' => FloatKind::F16]); - Some((parse_dec_float(number, kind), rest_to_str!(bytes))) + (parse_dec_float(number, kind), rest_to_str!(bytes)) } else { // make sure the multi-digit numbers don't start with zero if consumed > 1 && is_first_zero { - return None; + return (Err(NumberError::Invalid), rest_to_str!(bytes)); } let digits_with_sign = general_extract.end(bytes); @@ -288,10 +295,10 @@ fn parse(input: &str) -> Option<(Result, &str)> { b'h' => Kind::Float(FloatKind::F16) ]); - Some(( + ( parse_dec(is_negative, digits_with_sign, kind), rest_to_str!(bytes), - )) + ) } } }