usecrate::front::wgsl::error::NumberError; usecrate::front::wgsl::parse::directive::enable_extension::ImplementedEnableExtension; usecrate::front::wgsl::parse::lexer::Token; use half::f16;
/// When using this type assume no Abstract Int/Float for now #[derive(Copy, Clone, Debug, PartialEq)] pubenum Number { /// Abstract Int (-2^63 ≤ i < 2^63)
AbstractInt(i64), /// Abstract Float (IEEE-754 binary64)
AbstractFloat(f64), /// Concrete i32
I32(i32), /// Concrete u32
U32(u32), /// Concrete i64
I64(i64), /// Concrete u64
U64(u64), /// Concrete f16
F16(f16), /// Concrete f32
F32(f32), /// Concrete f64
F64(f64),
}
// 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)
// 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 => { let (neg, mant, exp) = parse_hex_float_parts(input.as_bytes())?; let bits = convert_hex_float(neg, mant, exp, F64)?; let num = f64::from_bits(bits);
Ok(Number::AbstractFloat(num))
} // TODO: f16 is not supported
Some(FloatKind::F16) => Err(NumberError::NotRepresentable),
Some(FloatKind::F32) => { let (neg, mant, exp) = parse_hex_float_parts(input.as_bytes())?; let bits = convert_hex_float(neg, mant, exp, F32)?; let num = f32::from_bits(bits as u32);
Ok(Number::F32(num))
}
Some(FloatKind::F64) => { let (neg, mant, exp) = parse_hex_float_parts(input.as_bytes())?; let bits = convert_hex_float(neg, mant, exp, F64)?; let num = f64::from_bits(bits);
Ok(Number::F64(num))
}
}
}
// a config for representing a hexadecimal floating-point struct HexFloatFormat {
mant_bits: usize, // number of bits in the mantissa (excluding implicit leading 1)
precision: usize, // total precision in bits including implicit bit
bias: i32, // exponent bias
max_exp: i32, // max exponent before overflow
exp_bits: usize, // number of bits in exponent
min_norm_exp: i32, // smallest exponent for normalized numbers
}
// exponent digits: [0-9]+ letmut digit_seen = false; letmut exponent: i32 = 0; loop { let (rest, digit) = match s.split_first() {
Some((&c @ b'0'..=b'9', s)) => (s, c - b'0'),
None if digit_seen => break,
_ => return Err(NumberError::Invalid),
};
s = rest;
digit_seen = true;
// only update exponent if non‑zero mantissa if acc != 0 {
exponent = exponent
.checked_mul(10)
.and_then(|v| v.checked_add(digit as i32))
.ok_or(NumberError::NotRepresentable)?;
}
}
if negative_exponent {
exponent = -exponent;
}
if acc == 0 { return Ok((negative, 0, 0));
}
// adjust exponent by 4 per fractional digit let exp_adj = nfracs.checked_mul(4).ok_or(NumberError::NotRepresentable)?; let exponent = exponent
.checked_sub(exp_adj)
.ok_or(NumberError::NotRepresentable)?;
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.