// 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]?))
// Leading signs are handled as unary operators.
fn parse(input: &str) -> (Result<Number, NumberError>, &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 {
($bytes:ident, $($pattern:pat),*) => { match $bytes {
&[$($pattern),*, ref rest @ ..] => { $bytes = rest; true },
_ => false,
}
};
}
/// consumes one byte from the given byte buffer /// if one of the given patterns are found at the start of the buffer /// returning the corresponding expr for the matched pattern
macro_rules! consume_map {
($bytes:ident, [$( $($pattern:pat_param),* => $to:expr),* $(,)?]) => { match $bytes {
$( &[ $($pattern),*, ref rest @ ..] => { $bytes = rest; Some($to) }, )*
_ => None,
}
};
}
/// consumes all consecutive bytes matched by the `0-9` pattern from the given byte buffer /// returning the number of consumed bytes
macro_rules! consume_dec_digits {
($bytes:ident) => {{ let start_len = $bytes.len(); whilelet &[b'0'..=b'9', ref rest @ ..] = $bytes {
$bytes = rest;
}
start_len - $bytes.len()
}};
}
/// consumes all consecutive bytes matched by the `0-9 | a-f | A-F` pattern from the given byte buffer /// returning the number of consumed bytes
macro_rules! consume_hex_digits {
($bytes:ident) => {{ let start_len = $bytes.len(); whilelet &[b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F', ref rest @ ..] = $bytes {
$bytes = rest;
}
start_len - $bytes.len()
}};
}
/// maps the given `&[u8]` (tail of the initial `input: &str`) to a `&str`
macro_rules! rest_to_str {
($bytes:ident) => {
&input[input.len() - $bytes.len()..]
};
}
struct ExtractSubStr<'a>(&'a str);
impl<'a> ExtractSubStr<'a> { /// given an `input` and a `start` (tail of the `input`) /// creates a new [`ExtractSubStr`](`Self`) fn start(input: &'a str, start: &'a [u8]) -> Self { let start = input.len() - start.len(); Self(&input[start..])
} /// given an `end` (tail of the initial `input`) /// returns a substring of `input` fn end(&self, end: &'a [u8]) -> &'a str { let end = self.0.len() - end.len();
&self.0[..end]
}
}
letmut bytes = input.as_bytes();
let general_extract = ExtractSubStr::start(input, bytes);
if consume!(bytes, b'0', b'x' | b'X') { let digits_extract = ExtractSubStr::start(input, bytes);
let consumed = consume_hex_digits!(bytes);
if consume!(bytes, b'.') { let consumed_after_period = consume_hex_digits!(bytes);
// The following chapters of IEEE 754-2019 are relevant: // // 7.4 Overflow (largest finite number is exceeded by what would have been // the rounded floating-point result were the exponent range unbounded) // // 7.5 Underflow (tiny non-zero result is detected; // for decimal formats tininess is detected before rounding when a non-zero result // computed as though both the exponent range and the precision were unbounded // would lie strictly between 2^−126) // // 7.6 Inexact (rounded result differs from what would have been computed // were both exponent range and precision unbounded)
// The WGSL spec requires us to error: // on overflow for decimal floating point literals // on overflow and inexact for hexadecimal floating point literals // (underflow is not mentioned)
// hexf_parse errors on overflow, underflow, inexact // rust std lib float from str handles overflow, underflow, inexact transparently (rounds and will not error)
// Therefore we only check for overflow manually for decimal floating point literals
// input format: 0[xX] ( [0-9a-fA-F]+\.[0-9a-fA-F]* | [0-9a-fA-F]*\.[0-9a-fA-F]+ ) [pP][+-]?[0-9]+ fn parse_hex_float(input: &str, kind: Option<FloatKind>) -> Result<Number, NumberError> { match kind {
None => match hexf_parse::parse_hexf64(input, false) {
Ok(num) => Ok(Number::AbstractFloat(num)), // can only be ParseHexfErrorKind::Inexact but we can't check since it's private
_ => Err(NumberError::NotRepresentable),
},
Some(FloatKind::F16) => Err(NumberError::UnimplementedF16),
Some(FloatKind::F32) => match hexf_parse::parse_hexf32(input, false) {
Ok(num) => Ok(Number::F32(num)), // can only be ParseHexfErrorKind::Inexact but we can't check since it's private
_ => Err(NumberError::NotRepresentable),
},
Some(FloatKind::F64) => match hexf_parse::parse_hexf64(input, false) {
Ok(num) => Ok(Number::F64(num)), // can only be ParseHexfErrorKind::Inexact but we can't check since it's private
_ => Err(NumberError::NotRepresentable),
},
}
}
// input format: ( [0-9]+\.[0-9]* | [0-9]*\.[0-9]+ ) ([eE][+-]?[0-9]+)? // | [0-9]+ [eE][+-]?[0-9]+ fn parse_dec_float(input: &str, kind: Option<FloatKind>) -> Result<Number, NumberError> { match kind {
None => { let num = input.parse::<f64>().unwrap(); // will never fail
num.is_finite()
.then_some(Number::AbstractFloat(num))
.ok_or(NumberError::NotRepresentable)
}
Some(FloatKind::F32) => { let num = input.parse::<f32>().unwrap(); // will never fail
num.is_finite()
.then_some(Number::F32(num))
.ok_or(NumberError::NotRepresentable)
}
Some(FloatKind::F64) => { let num = input.parse::<f64>().unwrap(); // will never fail
num.is_finite()
.then_some(Number::F64(num))
.ok_or(NumberError::NotRepresentable)
}
Some(FloatKind::F16) => Err(NumberError::UnimplementedF16),
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.