inf_wast/
token.rs

1//! Common tokens that implement the [`Parse`] trait which are otherwise not
2//! associated specifically with the wasm text format per se (useful in other
3//! contexts too perhaps).
4
5use crate::annotation;
6use crate::lexer::Float;
7use crate::parser::{Cursor, Parse, Parser, Peek, Result};
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::str;
11
12/// A position in the original source stream, used to render errors.
13#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
14pub struct Span {
15    pub(crate) offset: usize,
16}
17
18impl Span {
19    /// Construct a `Span` from a byte offset in the source file.
20    pub fn from_offset(offset: usize) -> Self {
21        Span { offset }
22    }
23
24    /// Returns the line/column information of this span within `text`.
25    /// Line and column numbers are 0-indexed. User presentation is typically
26    /// 1-indexed, but 0-indexing is appropriate for internal use with
27    /// iterators and slices.
28    pub fn linecol_in(&self, text: &str) -> (usize, usize) {
29        let mut cur = 0;
30        // Use split_terminator instead of lines so that if there is a `\r`,
31        // it is included in the offset calculation. The `+1` values below
32        // account for the `\n`.
33        for (i, line) in text.split_terminator('\n').enumerate() {
34            if cur + line.len() + 1 > self.offset {
35                return (i, self.offset - cur);
36            }
37            cur += line.len() + 1;
38        }
39        (text.lines().count(), 0)
40    }
41
42    /// Returns the byte offset of this span.
43    pub fn offset(&self) -> usize {
44        self.offset
45    }
46}
47
48/// An identifier in a WebAssembly module, prefixed by `$` in the textual
49/// format.
50///
51/// An identifier is used to symbolically refer to items in a a wasm module,
52/// typically via the [`Index`] type.
53#[derive(Copy, Clone)]
54pub struct Id<'a> {
55    name: &'a str,
56    generation: u32,
57    span: Span,
58}
59
60impl<'a> Id<'a> {
61    /// Construct a new identifier from given string.
62    ///
63    /// Note that `name` can be any arbitrary string according to the
64    /// WebAssembly/annotations proposal.
65    pub fn new(name: &'a str, span: Span) -> Id<'a> {
66        Id {
67            name,
68            generation: 0,
69            span,
70        }
71    }
72
73    #[cfg(feature = "wasm-module")]
74    pub(crate) fn gensym(span: Span, generation: u32) -> Id<'a> {
75        Id {
76            name: "gensym",
77            generation,
78            span,
79        }
80    }
81
82    /// Returns the underlying name of this identifier.
83    ///
84    /// The name returned does not contain the leading `$`.
85    pub fn name(&self) -> &'a str {
86        self.name
87    }
88
89    /// Returns span of this identifier in the original source
90    pub fn span(&self) -> Span {
91        self.span
92    }
93
94    #[cfg(feature = "wasm-module")]
95    pub(crate) fn is_gensym(&self) -> bool {
96        self.generation != 0
97    }
98}
99
100impl<'a> Hash for Id<'a> {
101    fn hash<H: Hasher>(&self, hasher: &mut H) {
102        self.name.hash(hasher);
103        self.generation.hash(hasher);
104    }
105}
106
107impl<'a> PartialEq for Id<'a> {
108    fn eq(&self, other: &Id<'a>) -> bool {
109        self.name == other.name && self.generation == other.generation
110    }
111}
112
113impl<'a> Eq for Id<'a> {}
114
115impl<'a> Parse<'a> for Id<'a> {
116    fn parse(parser: Parser<'a>) -> Result<Self> {
117        parser.step(|c| {
118            if let Some((name, rest)) = c.id()? {
119                return Ok((
120                    Id {
121                        name,
122                        generation: 0,
123                        span: c.cur_span(),
124                    },
125                    rest,
126                ));
127            }
128            Err(c.error("expected an identifier"))
129        })
130    }
131}
132
133impl fmt::Debug for Id<'_> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        if self.generation != 0 {
136            f.debug_struct("Id")
137                .field("generation", &self.generation)
138                .finish()
139        } else {
140            self.name.fmt(f)
141        }
142    }
143}
144
145impl Peek for Id<'_> {
146    fn peek(cursor: Cursor<'_>) -> Result<bool> {
147        cursor.peek_id()
148    }
149
150    fn display() -> &'static str {
151        "an identifier"
152    }
153}
154
155/// A reference to another item in a wasm module.
156///
157/// This type is used for items referring to other items (such as `call $foo`
158/// referencing function `$foo`). References can be either an index (u32) or an
159/// [`Id`] in the textual format.
160///
161/// The emission phase of a module will ensure that `Index::Id` is never used
162/// and switch them all to `Index::Num`.
163#[derive(Copy, Clone, Debug)]
164pub enum Index<'a> {
165    /// A numerical index that this references. The index space this is
166    /// referencing is implicit based on where this [`Index`] is stored.
167    Num(u32, Span),
168    /// A human-readable identifier this references. Like `Num`, the namespace
169    /// this references is based on where this is stored.
170    Id(Id<'a>),
171}
172
173impl Index<'_> {
174    /// Returns the source location where this `Index` was defined.
175    pub fn span(&self) -> Span {
176        match self {
177            Index::Num(_, span) => *span,
178            Index::Id(id) => id.span(),
179        }
180    }
181
182    #[cfg(feature = "wasm-module")]
183    pub(crate) fn is_resolved(&self) -> bool {
184        matches!(self, Index::Num(..))
185    }
186}
187
188impl<'a> Parse<'a> for Index<'a> {
189    fn parse(parser: Parser<'a>) -> Result<Self> {
190        if parser.peek::<Id>()? {
191            Ok(Index::Id(parser.parse()?))
192        } else if parser.peek::<u32>()? {
193            let (val, span) = parser.parse()?;
194            Ok(Index::Num(val, span))
195        } else {
196            Err(parser.error(format!(
197                "unexpected token, expected an index or an identifier"
198            )))
199        }
200    }
201}
202
203impl Peek for Index<'_> {
204    fn peek(cursor: Cursor<'_>) -> Result<bool> {
205        Ok(u32::peek(cursor)? || Id::peek(cursor)?)
206    }
207
208    fn display() -> &'static str {
209        "an index"
210    }
211}
212
213impl<'a> From<Id<'a>> for Index<'a> {
214    fn from(id: Id<'a>) -> Index<'a> {
215        Index::Id(id)
216    }
217}
218
219impl PartialEq for Index<'_> {
220    fn eq(&self, other: &Index<'_>) -> bool {
221        match (self, other) {
222            (Index::Num(a, _), Index::Num(b, _)) => a == b,
223            (Index::Id(a), Index::Id(b)) => a == b,
224            _ => false,
225        }
226    }
227}
228
229impl Eq for Index<'_> {}
230
231impl Hash for Index<'_> {
232    fn hash<H: Hasher>(&self, hasher: &mut H) {
233        match self {
234            Index::Num(a, _) => {
235                0u8.hash(hasher);
236                a.hash(hasher);
237            }
238            Index::Id(a) => {
239                1u8.hash(hasher);
240                a.hash(hasher);
241            }
242        }
243    }
244}
245
246/// Parses `(func $foo)`
247#[derive(Clone, Debug)]
248#[allow(missing_docs)]
249pub struct ItemRef<'a, K> {
250    pub kind: K,
251    pub idx: Index<'a>,
252}
253
254impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
255    fn parse(parser: Parser<'a>) -> Result<Self> {
256        parser.parens(|parser| {
257            let kind = parser.parse::<K>()?;
258            let idx = parser.parse()?;
259            Ok(ItemRef { kind, idx })
260        })
261    }
262}
263
264impl<'a, K: Peek> Peek for ItemRef<'a, K> {
265    fn peek(cursor: Cursor<'_>) -> Result<bool> {
266        match cursor.lparen()? {
267            Some(remaining) => K::peek(remaining),
268            None => Ok(false),
269        }
270    }
271
272    fn display() -> &'static str {
273        "an item reference"
274    }
275}
276
277/// An `@name` annotation in source, currently of the form `@name "foo"`
278#[derive(Copy, Clone, PartialEq, Eq, Debug)]
279pub struct NameAnnotation<'a> {
280    /// The name specified for the item
281    pub name: &'a str,
282}
283
284impl<'a> Parse<'a> for NameAnnotation<'a> {
285    fn parse(parser: Parser<'a>) -> Result<Self> {
286        parser.parse::<annotation::name>()?;
287        let name = parser.parse()?;
288        Ok(NameAnnotation { name })
289    }
290}
291
292impl<'a> Parse<'a> for Option<NameAnnotation<'a>> {
293    fn parse(parser: Parser<'a>) -> Result<Self> {
294        Ok(if parser.peek2::<annotation::name>()? {
295            Some(parser.parens(|p| p.parse())?)
296        } else {
297            None
298        })
299    }
300}
301
302macro_rules! integers {
303    ($($i:ident($u:ident))*) => ($(
304        impl<'a> Parse<'a> for $i {
305            fn parse(parser: Parser<'a>) -> Result<Self> {
306                Ok(parser.parse::<($i, Span)>()?.0)
307            }
308        }
309
310        impl<'a> Parse<'a> for ($i, Span) {
311            fn parse(parser: Parser<'a>) -> Result<Self> {
312                parser.step(|c| {
313                    if let Some((i, rest)) = c.integer()? {
314                        let (s, base) = i.val();
315                        let val = $i::from_str_radix(s, base)
316                            .or_else(|_| {
317                                $u::from_str_radix(s, base).map(|i| i as $i)
318                            });
319                        return match val {
320                            Ok(n) => Ok(((n, c.cur_span()), rest)),
321                            Err(_) => Err(c.error(concat!(
322                                "invalid ",
323                                stringify!($i),
324                                " number: constant out of range",
325                            ))),
326                        };
327                    }
328                    Err(c.error(concat!("expected a ", stringify!($i))))
329                })
330            }
331        }
332
333        impl Peek for $i {
334            fn peek(cursor: Cursor<'_>) -> Result<bool> {
335                cursor.peek_integer()
336            }
337
338            fn display() -> &'static str {
339                stringify!($i)
340            }
341        }
342    )*)
343}
344
345integers! {
346    u8(u8) u16(u16) u32(u32) u64(u64)
347    i8(u8) i16(u16) i32(u32) i64(u64)
348}
349
350impl<'a> Parse<'a> for &'a [u8] {
351    fn parse(parser: Parser<'a>) -> Result<Self> {
352        parser.step(|c| {
353            if let Some((i, rest)) = c.string()? {
354                return Ok((i, rest));
355            }
356            Err(c.error("expected a string"))
357        })
358    }
359}
360
361impl Peek for &'_ [u8] {
362    fn peek(cursor: Cursor<'_>) -> Result<bool> {
363        cursor.peek_string()
364    }
365
366    fn display() -> &'static str {
367        "string"
368    }
369}
370
371impl<'a> Parse<'a> for &'a str {
372    fn parse(parser: Parser<'a>) -> Result<Self> {
373        str::from_utf8(parser.parse()?)
374            .map_err(|_| parser.error_at(parser.prev_span(), "malformed UTF-8 encoding"))
375    }
376}
377
378impl Parse<'_> for String {
379    fn parse(parser: Parser<'_>) -> Result<Self> {
380        Ok(<&str>::parse(parser)?.to_string())
381    }
382}
383
384impl Peek for &'_ str {
385    fn peek(cursor: Cursor<'_>) -> Result<bool> {
386        <&[u8]>::peek(cursor)
387    }
388
389    fn display() -> &'static str {
390        <&[u8]>::display()
391    }
392}
393
394macro_rules! float {
395    ($($name:ident => {
396        bits: $int:ident,
397        float: $float:ident,
398        exponent_bits: $exp_bits:tt,
399        name: $parse:ident,
400    })*) => ($(
401        /// A parsed floating-point type
402        #[derive(Debug, Copy, Clone)]
403        pub struct $name {
404            /// The raw bits that this floating point number represents.
405            pub bits: $int,
406        }
407
408        impl<'a> Parse<'a> for $name {
409            fn parse(parser: Parser<'a>) -> Result<Self> {
410                parser.step(|c| {
411                    let (val, rest) = if let Some((f, rest)) = c.float()? {
412                        ($parse(&f), rest)
413                    } else if let Some((i, rest)) = c.integer()? {
414                        let (s, base) = i.val();
415                        (
416                            $parse(&Float::Val {
417                                hex: base == 16,
418                                integral: s.into(),
419                                fractional: None,
420                                exponent: None,
421                            }),
422                            rest,
423                        )
424                    } else {
425                        return Err(c.error("expected a float"));
426                    };
427                    match val {
428                        Some(bits) => Ok(($name { bits }, rest)),
429                        None => Err(c.error("invalid float value: constant out of range")),
430                    }
431                })
432            }
433        }
434
435        fn $parse(val: &Float<'_>) -> Option<$int> {
436            // Compute a few well-known constants about the float representation
437            // given the parameters to the macro here.
438            let width = std::mem::size_of::<$int>() * 8;
439            let neg_offset = width - 1;
440            let exp_offset = neg_offset - $exp_bits;
441            let signif_bits = width - 1 - $exp_bits;
442            let signif_mask = (1 << exp_offset) - 1;
443            let bias = (1 << ($exp_bits - 1)) - 1;
444            let msb = 1 << neg_offset;
445
446            let (hex, integral, fractional, exponent_str) = match val {
447                // Infinity is when the exponent bits are all set and
448                // the significand is zero.
449                Float::Inf { negative } => {
450                    let exp_bits = (1 << $exp_bits) - 1;
451                    let neg_bit = *negative as $int;
452                    return Some(
453                        (neg_bit << neg_offset) |
454                        (exp_bits << exp_offset)
455                    );
456                }
457
458                // NaN is when the exponent bits are all set and
459                // the significand is nonzero. The default of NaN is
460                // when only the highest bit of the significand is set.
461                Float::Nan { negative, val } => {
462                    let exp_bits = (1 << $exp_bits) - 1;
463                    let neg_bit = *negative as $int;
464                    let signif = match val {
465                        Some(val) => $int::from_str_radix(val,16).ok()?,
466                        None => 1 << (signif_bits - 1),
467                    };
468                    // If the significand is zero then this is actually infinity
469                    // so we fail to parse it.
470                    if signif & signif_mask == 0 {
471                        return None;
472                    }
473                    return Some(
474                        (neg_bit << neg_offset) |
475                        (exp_bits << exp_offset) |
476                        (signif & signif_mask)
477                    );
478                }
479
480                // This is trickier, handle this below
481                Float::Val { hex, integral, fractional, exponent } => {
482                    (hex, integral, fractional, exponent)
483                }
484            };
485
486            // Rely on Rust's standard library to parse base 10 floats
487            // correctly.
488            if !*hex {
489                let mut s = integral.to_string();
490                if let Some(fractional) = fractional {
491                    s.push_str(".");
492                    s.push_str(&fractional);
493                }
494                if let Some(exponent) = exponent_str {
495                    s.push_str("e");
496                    s.push_str(&exponent);
497                }
498                let float = s.parse::<$float>().ok()?;
499                // looks like the `*.wat` format considers infinite overflow to
500                // be invalid.
501                if float.is_infinite() {
502                    return None;
503                }
504                return Some(float.to_bits());
505            }
506
507            // Parse a hexadecimal floating-point value.
508            //
509            // The main loop here is simpler than for parsing decimal floats,
510            // because we can just parse hexadecimal digits and then shift
511            // their bits into place in the significand. But in addition to
512            // that, we also need to handle non-normalized representations,
513            // where the integral part is not "1", to convert them to
514            // normalized results, to round, in case we get more digits than
515            // the target format supports, and to handle overflow and subnormal
516            // cases.
517
518            // Get slices of digits for the integral and fractional parts. We
519            // can trivially skip any leading zeros in the integral part.
520            let is_negative = integral.starts_with('-');
521            let integral = integral.trim_start_matches('-').trim_start_matches('0');
522            let fractional = fractional.as_ref().map(|s| &**s).unwrap_or("");
523
524            // Locate the first non-zero digit to determine the initial exponent.
525            //
526            // If there's no integral part, skip past leading zeros so that
527            // something like "0x.0000000000000000000002" doesn't cause us to hit
528            // a shift overflow when we try to shift the value into place. We'll
529            // adjust the exponent below to account for these skipped zeros.
530            let fractional_no_leading = fractional.trim_start_matches('0');
531            let fractional_iter = if integral.is_empty() {
532                fractional_no_leading.chars()
533            } else {
534                fractional.chars()
535            };
536
537            // Create a unified iterator over the digits of the integral part
538            // followed by the digits of the fractional part. The boolean value
539            // indicates which of these parts we're in.
540            let mut digits = integral.chars()
541                .map(|c| (to_hex(c) as $int, false))
542                .chain(fractional_iter.map(|c| (to_hex(c) as $int, true)));
543
544            // Compute the number of leading zeros in the first non-zero digit,
545            // since if the first digit is not "1" we'll need to adjust for
546            // normalization.
547            let lead_nonzero_digit = match digits.next() {
548                Some((c, _)) => c,
549                // No non-zero digits? Must be `+0` or `-0`, being careful to
550                // handle the sign encoding here.
551                None if is_negative => return Some(msb),
552                None => return Some(0),
553            };
554            let lz = (lead_nonzero_digit as u8).leading_zeros() as i32 - 4;
555
556            // Prepare for the main parsing loop. Calculate the initial values
557            // of `exponent` and `significand` based on what we've seen so far.
558            let mut exponent = if !integral.is_empty() {
559                1
560            } else {
561                // Adjust the exponent digits to account for any leading zeros
562                // in the fractional part that we skipped above.
563                -((fractional.len() - fractional_no_leading.len() + 1) as i32) + 1
564            };
565            let mut significand_pos = (width - (4 - (lz as usize))) as isize;
566            let mut significand: $int = lead_nonzero_digit << significand_pos;
567            let mut discarded_extra_nonzero = false;
568
569            assert!(significand_pos >= 0, "$int should be at least 4 bits wide");
570
571            // Adjust for leading zeros in the first digit.
572            exponent = exponent.checked_mul(4)?.checked_sub(lz + 1)?;
573
574            // Now that we've got an anchor in the string we parse the remaining
575            // hexadecimal digits.
576            for (digit, in_fractional) in digits {
577                if !in_fractional {
578                    exponent += 4;
579                }
580                if significand_pos > -4 {
581                    significand_pos -= 4;
582                }
583
584                if significand_pos >= 0 {
585                    significand |= digit << significand_pos;
586                } else if significand_pos > -4 {
587                    significand |= digit >> (4 - significand_pos);
588                    discarded_extra_nonzero = (digit & !((!0) >> (4 - significand_pos))) != 0;
589                } else if digit != 0 {
590                    discarded_extra_nonzero = true;
591                }
592            }
593
594            debug_assert!(significand != 0, "The case of no non-zero digits should have been handled above");
595
596            // Parse the exponent string, which despite this being a hexadecimal
597            // syntax, is a decimal number, and add it the exponent we've
598            // computed from the potentially non-normalized significand.
599            exponent = exponent.checked_add(match exponent_str {
600                Some(s) => s.parse::<i32>().ok()?,
601                None => 0,
602            })?;
603
604            // Encode the exponent and significand. Also calculate the bits of
605            // the significand which are discarded, as we'll use them to
606            // determine if we need to round up.
607            let (encoded_exponent, encoded_significand, discarded_significand) =
608                if exponent <= -bias {
609                    // Underflow to subnormal or zero.
610                    let shift = exp_offset as i32 + exponent + bias;
611                    if shift == 0 {
612                        (0, 0, significand)
613                    } else if shift < 0 || shift >= width as i32 {
614                        (0, 0, 0)
615                    } else {
616                        (
617                            0,
618                            significand >> (width as i32 - shift),
619                            significand << shift,
620                        )
621                    }
622                } else if exponent <= bias {
623                    // Normal (non-zero). The significand's leading 1 is encoded
624                    // implicitly.
625                    (
626                        ((exponent + bias) as $int) << exp_offset,
627                        (significand >> (width - exp_offset - 1)) & signif_mask,
628                        significand << (exp_offset + 1),
629                    )
630                } else {
631                    // Overflow to infinity.
632                    (
633                        ((1 << $exp_bits) - 1) << exp_offset,
634                        0,
635                        0,
636                    )
637                };
638
639            // Combine the encoded exponent and encoded significand to produce
640            // the raw result, except for the sign bit, which we'll apply at
641            // the end.
642            let bits = encoded_exponent | encoded_significand;
643
644            // Apply rounding. Do an integer add of `0` or `1` on the raw
645            // result, depending on whether rounding is needed. Rounding can
646            // lead to a floating-point overflow, but we don't need to
647            // special-case that here because it turns out that IEEE 754 floats
648            // are encoded such that when an integer add of `1` carries into
649            // the bits of the exponent field, it produces the correct encoding
650            // for infinity.
651            let bits = bits
652                + (((discarded_significand & msb != 0)
653                    && ((discarded_significand & !msb != 0) ||
654                         discarded_extra_nonzero ||
655                         // ties to even
656                         (encoded_significand & 1 != 0))) as $int);
657
658            // Just before we return the bits, be sure to handle the sign bit we
659            // found at the beginning.
660            let bits = if is_negative {
661                bits | msb
662            } else {
663                bits
664            };
665            // looks like the `*.wat` format considers infinite overflow to
666            // be invalid.
667            if $float::from_bits(bits).is_infinite() {
668                return None;
669            }
670            Some(bits)
671        }
672
673    )*)
674}
675
676float! {
677    F32 => {
678        bits: u32,
679        float: f32,
680        exponent_bits: 8,
681        name: strtof,
682    }
683    F64 => {
684        bits: u64,
685        float: f64,
686        exponent_bits: 11,
687        name: strtod,
688    }
689}
690
691fn to_hex(c: char) -> u8 {
692    match c {
693        'a'..='f' => c as u8 - b'a' + 10,
694        'A'..='F' => c as u8 - b'A' + 10,
695        _ => c as u8 - b'0',
696    }
697}
698
699/// A convenience type to use with [`Parser::peek`](crate::parser::Parser::peek)
700/// to see if the next token is an s-expression.
701pub struct LParen {
702    _priv: (),
703}
704
705impl Peek for LParen {
706    fn peek(cursor: Cursor<'_>) -> Result<bool> {
707        cursor.peek_lparen()
708    }
709
710    fn display() -> &'static str {
711        "left paren"
712    }
713}
714
715/// A convenience type to use with [`Parser::peek`](crate::parser::Parser::peek)
716/// to see if the next token is the end of an s-expression.
717pub struct RParen {
718    _priv: (),
719}
720
721impl Peek for RParen {
722    fn peek(cursor: Cursor<'_>) -> Result<bool> {
723        cursor.peek_rparen()
724    }
725
726    fn display() -> &'static str {
727        "right paren"
728    }
729}
730
731#[cfg(test)]
732mod tests {
733    #[test]
734    fn hex_strtof() {
735        macro_rules! f {
736            ($a:tt) => (f!(@mk $a, None, None));
737            ($a:tt p $e:tt) => (f!(@mk $a, None, Some($e.into())));
738            ($a:tt . $b:tt) => (f!(@mk $a, Some($b.into()), None));
739            ($a:tt . $b:tt p $e:tt) => (f!(@mk $a, Some($b.into()), Some($e.into())));
740            (@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::Float::Val {
741                hex: true,
742                integral: $a.into(),
743                fractional: $b,
744                exponent: $e
745            });
746        }
747        assert_eq!(super::strtof(&f!("0")), Some(0));
748        assert_eq!(super::strtof(&f!("0" . "0")), Some(0));
749        assert_eq!(super::strtof(&f!("0" . "0" p "2354")), Some(0));
750        assert_eq!(super::strtof(&f!("-0")), Some(1 << 31));
751        assert_eq!(super::strtof(&f!("f32")), Some(0x45732000));
752        assert_eq!(super::strtof(&f!("0" . "f32")), Some(0x3f732000));
753        assert_eq!(super::strtof(&f!("1" . "2")), Some(0x3f900000));
754        assert_eq!(
755            super::strtof(&f!("0" . "00000100000000000" p "-126")),
756            Some(0)
757        );
758        assert_eq!(
759            super::strtof(&f!("1" . "fffff4" p "-106")),
760            Some(0x0afffffa)
761        );
762        assert_eq!(super::strtof(&f!("fffff98" p "-133")), Some(0x0afffffa));
763        assert_eq!(super::strtof(&f!("0" . "081" p "023")), Some(0x48810000));
764        assert_eq!(
765            super::strtof(&f!("1" . "00000100000000000" p "-50")),
766            Some(0x26800000)
767        );
768    }
769}