/rust/registry/src/github.com-1ecc6299db9ec823/wast-35.0.0/src/ast/token.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::ast::{annotation, kw}; |
2 | | use crate::lexer::FloatVal; |
3 | | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | | use std::fmt; |
5 | | use std::hash::{Hash, Hasher}; |
6 | | use std::str; |
7 | | |
8 | | /// A position in the original source stream, used to render errors. |
9 | 0 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] |
10 | | pub struct Span { |
11 | | pub(crate) offset: usize, |
12 | | } |
13 | | |
14 | | impl Span { |
15 | | /// Construct a `Span` from a byte offset in the source file. |
16 | 2.43M | pub fn from_offset(offset: usize) -> Self { |
17 | 2.43M | Span { offset } |
18 | 2.43M | } |
19 | | |
20 | | /// Returns the line/column information of this span within `text`. |
21 | | /// Line and column numbers are 0-indexed. User presentation is typically |
22 | | /// 1-indexed, but 0-indexing is appropriate for internal use with |
23 | | /// iterators and slices. |
24 | 19.5k | pub fn linecol_in(&self, text: &str) -> (usize, usize) { |
25 | 19.5k | let mut cur = 0; |
26 | | // Use split_terminator instead of lines so that if there is a `\r`, |
27 | | // it is included in the offset calculation. The `+1` values below |
28 | | // account for the `\n`. |
29 | 1.96M | for (i, line) in text.split_terminator('\n').enumerate() { |
30 | 1.96M | if cur + line.len() + 1 > self.offset { |
31 | 19.3k | return (i, self.offset - cur); |
32 | 1.94M | } |
33 | 1.94M | cur += line.len() + 1; |
34 | | } |
35 | 158 | (text.lines().count(), 0) |
36 | 19.5k | } |
37 | | } |
38 | | |
39 | | /// An identifier in a WebAssembly module, prefixed by `$` in the textual |
40 | | /// format. |
41 | | /// |
42 | | /// An identifier is used to symbolically refer to items in a a wasm module, |
43 | | /// typically via the [`Index`] type. |
44 | 1.48k | #[derive(Copy, Clone)] |
45 | | pub struct Id<'a> { |
46 | | name: &'a str, |
47 | | gen: u32, |
48 | | span: Span, |
49 | | } |
50 | | |
51 | | impl<'a> Id<'a> { |
52 | 616k | fn new(name: &'a str, span: Span) -> Id<'a> { |
53 | 616k | Id { name, gen: 0, span } |
54 | 616k | } |
55 | | |
56 | 331k | pub(crate) fn gensym(span: Span, gen: u32) -> Id<'a> { |
57 | 331k | Id { |
58 | 331k | name: "gensym", |
59 | 331k | gen, |
60 | 331k | span, |
61 | 331k | } |
62 | 331k | } |
63 | | |
64 | | /// Returns the underlying name of this identifier. |
65 | | /// |
66 | | /// The name returned does not contain the leading `$`. |
67 | 40.4k | pub fn name(&self) -> &'a str { |
68 | 40.4k | self.name |
69 | 40.4k | } |
70 | | |
71 | | /// Returns span of this identifier in the original source |
72 | 1.48M | pub fn span(&self) -> Span { |
73 | 1.48M | self.span |
74 | 1.48M | } |
75 | | |
76 | 86.2k | pub(crate) fn is_gensym(&self) -> bool { |
77 | 86.2k | self.gen != 0 |
78 | 86.2k | } |
79 | | } |
80 | | |
81 | | impl<'a> Hash for Id<'a> { |
82 | 2.60M | fn hash<H: Hasher>(&self, hasher: &mut H) { |
83 | 2.60M | self.name.hash(hasher); |
84 | 2.60M | self.gen.hash(hasher); |
85 | 2.60M | } |
86 | | } |
87 | | |
88 | | impl<'a> PartialEq for Id<'a> { |
89 | 1.79M | fn eq(&self, other: &Id<'a>) -> bool { |
90 | 1.79M | self.name == other.name && self.gen == other.gen |
91 | 1.79M | } |
92 | | } |
93 | | |
94 | | impl<'a> Eq for Id<'a> {} |
95 | | |
96 | | impl<'a> Parse<'a> for Id<'a> { |
97 | 616k | fn parse(parser: Parser<'a>) -> Result<Self> { |
98 | 616k | parser.step(|c| { |
99 | 616k | if let Some((name, rest)) = c.id() { |
100 | 616k | return Ok((Id::new(name, c.cur_span()), rest)); |
101 | 0 | } |
102 | 0 | Err(c.error("expected an identifier")) |
103 | 616k | }) |
104 | 616k | } |
105 | | } |
106 | | |
107 | | impl fmt::Debug for Id<'_> { |
108 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
109 | 0 | if self.gen != 0 { |
110 | 0 | f.debug_struct("Id").field("gen", &self.gen).finish() |
111 | | } else { |
112 | 0 | self.name.fmt(f) |
113 | | } |
114 | 0 | } |
115 | | } |
116 | | |
117 | | impl Peek for Id<'_> { |
118 | 3.72M | fn peek(cursor: Cursor<'_>) -> bool { |
119 | 3.72M | cursor.id().is_some() |
120 | 3.72M | } |
121 | | |
122 | 483k | fn display() -> &'static str { |
123 | 483k | "an identifier" |
124 | 483k | } |
125 | | } |
126 | | |
127 | | /// A reference to another item in a wasm module. |
128 | | /// |
129 | | /// This type is used for items referring to other items (such as `call $foo` |
130 | | /// referencing function `$foo`). References can be either an index (u32) or an |
131 | | /// [`Id`] in the textual format. |
132 | | /// |
133 | | /// The emission phase of a module will ensure that `Index::Id` is never used |
134 | | /// and switch them all to `Index::Num`. |
135 | 1.36M | #[derive(Copy, Clone, Debug)] |
136 | | pub enum Index<'a> { |
137 | | /// A numerical index that this references. The index space this is |
138 | | /// referencing is implicit based on where this [`Index`] is stored. |
139 | | Num(u32, Span), |
140 | | /// A human-readable identifier this references. Like `Num`, the namespace |
141 | | /// this references is based on where this is stored. |
142 | | Id(Id<'a>), |
143 | | } |
144 | | |
145 | | impl Index<'_> { |
146 | | /// Returns the source location where this `Index` was defined. |
147 | 17.7k | pub fn span(&self) -> Span { |
148 | 17.7k | match self { |
149 | 0 | Index::Num(_, span) => *span, |
150 | 17.7k | Index::Id(id) => id.span(), |
151 | | } |
152 | 17.7k | } |
153 | | |
154 | 3.41k | pub(crate) fn is_resolved(&self) -> bool { |
155 | 3.41k | match self { |
156 | 3.41k | Index::Num(..) => true, |
157 | 0 | _ => false, |
158 | | } |
159 | 3.41k | } |
160 | | } |
161 | | |
162 | | impl<'a> Parse<'a> for Index<'a> { |
163 | 551k | fn parse(parser: Parser<'a>) -> Result<Self> { |
164 | 551k | let mut l = parser.lookahead1(); |
165 | 551k | if l.peek::<Id>() { |
166 | 68.2k | Ok(Index::Id(parser.parse()?)) |
167 | 483k | } else if l.peek::<u32>() { |
168 | 483k | let (val, span) = parser.parse()?; |
169 | 482k | Ok(Index::Num(val, span)) |
170 | | } else { |
171 | 211 | Err(l.error()) |
172 | | } |
173 | 551k | } |
174 | | } |
175 | | |
176 | | impl Peek for Index<'_> { |
177 | 849k | fn peek(cursor: Cursor<'_>) -> bool { |
178 | 849k | u32::peek(cursor) || Id::peek(cursor) |
179 | 849k | } |
180 | | |
181 | 30 | fn display() -> &'static str { |
182 | 30 | "an index" |
183 | 30 | } |
184 | | } |
185 | | |
186 | | impl<'a> From<Id<'a>> for Index<'a> { |
187 | 100k | fn from(id: Id<'a>) -> Index<'a> { |
188 | 100k | Index::Id(id) |
189 | 100k | } |
190 | | } |
191 | | |
192 | | impl PartialEq for Index<'_> { |
193 | 1.61k | fn eq(&self, other: &Index<'_>) -> bool { |
194 | 1.61k | match (self, other) { |
195 | 0 | (Index::Num(a, _), Index::Num(b, _)) => a == b, |
196 | 1.61k | (Index::Id(a), Index::Id(b)) => a == b, |
197 | 0 | _ => false, |
198 | | } |
199 | 1.61k | } |
200 | | } |
201 | | |
202 | | impl Eq for Index<'_> {} |
203 | | |
204 | | impl Hash for Index<'_> { |
205 | 41.4k | fn hash<H: Hasher>(&self, hasher: &mut H) { |
206 | 41.4k | match self { |
207 | 0 | Index::Num(a, _) => { |
208 | 0 | 0u8.hash(hasher); |
209 | 0 | a.hash(hasher); |
210 | 0 | } |
211 | 41.4k | Index::Id(a) => { |
212 | 41.4k | 1u8.hash(hasher); |
213 | 41.4k | a.hash(hasher); |
214 | 41.4k | } |
215 | | } |
216 | 41.4k | } |
217 | | } |
218 | | |
219 | | /// Parses `(func $foo)` |
220 | | /// |
221 | | /// Optionally includes export strings for module-linking sugar syntax for alias |
222 | | /// injection. |
223 | 15.2k | #[derive(Clone, Debug)] |
224 | | #[allow(missing_docs)] |
225 | | pub enum ItemRef<'a, K> { |
226 | | Outer { |
227 | | kind: K, |
228 | | module: Index<'a>, |
229 | | idx: Index<'a>, |
230 | | }, |
231 | | Item { |
232 | | kind: K, |
233 | | idx: Index<'a>, |
234 | | exports: Vec<&'a str>, |
235 | | }, |
236 | | } |
237 | | |
238 | | impl<'a, K> ItemRef<'a, K> { |
239 | | /// Unwraps the underlying `Index` for `ItemRef::Item`. |
240 | | /// |
241 | | /// Panics if this is `ItemRef::Outer` or if exports haven't been expanded |
242 | | /// yet. |
243 | 0 | pub fn unwrap_index(&self) -> &Index<'a> { |
244 | 0 | match self { |
245 | 0 | ItemRef::Item { idx, exports, .. } => { |
246 | | debug_assert!(exports.len() == 0); |
247 | 0 | idx |
248 | | } |
249 | 0 | ItemRef::Outer { .. } => panic!("unwrap_index called on Parent"), |
250 | | } |
251 | 0 | } Unexecuted instantiation: <wast::ast::token::ItemRef<wast::ast::kw::type>>::unwrap_index Unexecuted instantiation: <wast::ast::token::ItemRef<wast::ast::kw::instance>>::unwrap_index |
252 | | } |
253 | | |
254 | | impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { |
255 | 34.6k | fn parse(parser: Parser<'a>) -> Result<Self> { |
256 | 34.5k | parser.parens(|parser| { |
257 | 34.5k | let kind = parser.parse::<K>()?; |
258 | 34.4k | if parser.peek::<kw::outer>() { |
259 | 2 | parser.parse::<kw::outer>()?; |
260 | 2 | let module = parser.parse()?; |
261 | 0 | let idx = parser.parse()?; |
262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) |
263 | | } else { |
264 | 34.4k | let idx = parser.parse()?; |
265 | 34.3k | let mut exports = Vec::new(); |
266 | 52.2k | while !parser.is_empty() { |
267 | 17.9k | exports.push(parser.parse()?); |
268 | | } |
269 | 34.3k | Ok(ItemRef::Item { kind, idx, exports }) |
270 | | } |
271 | 34.6k | }) <wast::ast::token::ItemRef<wast::ast::kw::type> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 211 | parser.parens(|parser| { | 257 | 211 | let kind = parser.parse::<K>()?; | 258 | 211 | if parser.peek::<kw::outer>() { | 259 | 1 | parser.parse::<kw::outer>()?; | 260 | 1 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 210 | let idx = parser.parse()?; | 265 | 198 | let mut exports = Vec::new(); | 266 | 239 | while !parser.is_empty() { | 267 | 53 | exports.push(parser.parse()?); | 268 | | } | 269 | 186 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 211 | }) |
<wast::ast::token::ItemRef<wast::ast::kw::func> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 314 | parser.parens(|parser| { | 257 | 314 | let kind = parser.parse::<K>()?; | 258 | 272 | if parser.peek::<kw::outer>() { | 259 | 0 | parser.parse::<kw::outer>()?; | 260 | 0 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 272 | let idx = parser.parse()?; | 265 | 261 | let mut exports = Vec::new(); | 266 | 18.0k | while !parser.is_empty() { | 267 | 17.8k | exports.push(parser.parse()?); | 268 | | } | 269 | 247 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 314 | }) |
<wast::ast::token::ItemRef<wast::ast::kw::memory> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 72 | parser.parens(|parser| { | 257 | 72 | let kind = parser.parse::<K>()?; | 258 | 58 | if parser.peek::<kw::outer>() { | 259 | 1 | parser.parse::<kw::outer>()?; | 260 | 1 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 57 | let idx = parser.parse()?; | 265 | 16 | let mut exports = Vec::new(); | 266 | 16 | while !parser.is_empty() { | 267 | 10 | exports.push(parser.parse()?); | 268 | | } | 269 | 6 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 72 | }) |
<wast::ast::token::ItemRef<wast::ast::kw::global> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 17 | parser.parens(|parser| { | 257 | 17 | let kind = parser.parse::<K>()?; | 258 | 3 | if parser.peek::<kw::outer>() { | 259 | 0 | parser.parse::<kw::outer>()?; | 260 | 0 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 3 | let idx = parser.parse()?; | 265 | 1 | let mut exports = Vec::new(); | 266 | 1 | while !parser.is_empty() { | 267 | 1 | exports.push(parser.parse()?); | 268 | | } | 269 | 0 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 17 | }) |
<wast::ast::token::ItemRef<wast::ast::export::ExportKind> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 33.9k | parser.parens(|parser| { | 257 | 33.9k | let kind = parser.parse::<K>()?; | 258 | 33.8k | if parser.peek::<kw::outer>() { | 259 | 0 | parser.parse::<kw::outer>()?; | 260 | 0 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 33.8k | let idx = parser.parse()?; | 265 | 33.8k | let mut exports = Vec::new(); | 266 | 33.8k | while !parser.is_empty() { | 267 | 6 | exports.push(parser.parse()?); | 268 | | } | 269 | 33.8k | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 33.9k | }) |
Unexecuted instantiation: <wast::ast::token::ItemRef<wast::ast::kw::module> as wast::parser::Parse>::parse::{closure#0}<wast::ast::token::ItemRef<wast::ast::kw::table> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 19 | parser.parens(|parser| { | 257 | 19 | let kind = parser.parse::<K>()?; | 258 | 10 | if parser.peek::<kw::outer>() { | 259 | 0 | parser.parse::<kw::outer>()?; | 260 | 0 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 10 | let idx = parser.parse()?; | 265 | 5 | let mut exports = Vec::new(); | 266 | 5 | while !parser.is_empty() { | 267 | 3 | exports.push(parser.parse()?); | 268 | | } | 269 | 2 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 19 | }) |
<wast::ast::token::ItemRef<wast::ast::kw::instance> as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 256 | 14 | parser.parens(|parser| { | 257 | 14 | let kind = parser.parse::<K>()?; | 258 | 0 | if parser.peek::<kw::outer>() { | 259 | 0 | parser.parse::<kw::outer>()?; | 260 | 0 | let module = parser.parse()?; | 261 | 0 | let idx = parser.parse()?; | 262 | 0 | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | 0 | let idx = parser.parse()?; | 265 | 0 | let mut exports = Vec::new(); | 266 | 0 | while !parser.is_empty() { | 267 | 0 | exports.push(parser.parse()?); | 268 | | } | 269 | 0 | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 14 | }) |
|
272 | 34.6k | } <wast::ast::token::ItemRef<wast::ast::kw::func> as wast::parser::Parse>::parse Line | Count | Source | 255 | 356 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 356 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 356 | }) | 272 | 356 | } |
<wast::ast::token::ItemRef<wast::ast::kw::table> as wast::parser::Parse>::parse Line | Count | Source | 255 | 32 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 32 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 32 | }) | 272 | 32 | } |
<wast::ast::token::ItemRef<wast::ast::export::ExportKind> as wast::parser::Parse>::parse Line | Count | Source | 255 | 33.9k | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 33.9k | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 33.9k | }) | 272 | 33.9k | } |
Unexecuted instantiation: <wast::ast::token::ItemRef<wast::ast::kw::module> as wast::parser::Parse>::parse <wast::ast::token::ItemRef<wast::ast::kw::instance> as wast::parser::Parse>::parse Line | Count | Source | 255 | 26 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 26 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 26 | }) | 272 | 26 | } |
<wast::ast::token::ItemRef<wast::ast::kw::type> as wast::parser::Parse>::parse Line | Count | Source | 255 | 225 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 225 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 225 | }) | 272 | 225 | } |
<wast::ast::token::ItemRef<wast::ast::kw::memory> as wast::parser::Parse>::parse Line | Count | Source | 255 | 81 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 81 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 81 | }) | 272 | 81 | } |
<wast::ast::token::ItemRef<wast::ast::kw::global> as wast::parser::Parse>::parse Line | Count | Source | 255 | 43 | fn parse(parser: Parser<'a>) -> Result<Self> { | 256 | 43 | parser.parens(|parser| { | 257 | | let kind = parser.parse::<K>()?; | 258 | | if parser.peek::<kw::outer>() { | 259 | | parser.parse::<kw::outer>()?; | 260 | | let module = parser.parse()?; | 261 | | let idx = parser.parse()?; | 262 | | Ok(ItemRef::Outer { kind, module, idx }) | 263 | | } else { | 264 | | let idx = parser.parse()?; | 265 | | let mut exports = Vec::new(); | 266 | | while !parser.is_empty() { | 267 | | exports.push(parser.parse()?); | 268 | | } | 269 | | Ok(ItemRef::Item { kind, idx, exports }) | 270 | | } | 271 | 43 | }) | 272 | 43 | } |
|
273 | | } |
274 | | |
275 | | impl<'a, K: Peek> Peek for ItemRef<'a, K> { |
276 | 856k | fn peek(cursor: Cursor<'_>) -> bool { |
277 | 856k | match cursor.lparen() { |
278 | 10.9k | Some(remaining) => K::peek(remaining), |
279 | 845k | None => false, |
280 | | } |
281 | 856k | } <wast::ast::token::ItemRef<wast::ast::kw::func> as wast::parser::Peek>::peek Line | Count | Source | 276 | 291k | fn peek(cursor: Cursor<'_>) -> bool { | 277 | 291k | match cursor.lparen() { | 278 | 35 | Some(remaining) => K::peek(remaining), | 279 | 291k | None => false, | 280 | | } | 281 | 291k | } |
<wast::ast::token::ItemRef<wast::ast::kw::table> as wast::parser::Peek>::peek Line | Count | Source | 276 | 29.7k | fn peek(cursor: Cursor<'_>) -> bool { | 277 | 29.7k | match cursor.lparen() { | 278 | 5.31k | Some(remaining) => K::peek(remaining), | 279 | 24.4k | None => false, | 280 | | } | 281 | 29.7k | } |
<wast::ast::token::ItemRef<wast::ast::kw::memory> as wast::parser::Peek>::peek Line | Count | Source | 276 | 535k | fn peek(cursor: Cursor<'_>) -> bool { | 277 | 535k | match cursor.lparen() { | 278 | 5.57k | Some(remaining) => K::peek(remaining), | 279 | 529k | None => false, | 280 | | } | 281 | 535k | } |
|
282 | | |
283 | 0 | fn display() -> &'static str { |
284 | 0 | "an item reference" |
285 | 0 | } |
286 | | } |
287 | | |
288 | | /// Convenience structure to parse `$f` or `(item $f)`. |
289 | 0 | #[derive(Clone, Debug)] |
290 | | pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); |
291 | | |
292 | | impl<'a, K> Parse<'a> for IndexOrRef<'a, K> |
293 | | where |
294 | | K: Parse<'a> + Default, |
295 | | { |
296 | 409k | fn parse(parser: Parser<'a>) -> Result<Self> { |
297 | 409k | if parser.peek::<Index<'_>>() { |
298 | | Ok(IndexOrRef(ItemRef::Item { |
299 | 409k | kind: K::default(), |
300 | 409k | idx: parser.parse()?, |
301 | 408k | exports: Vec::new(), |
302 | | })) |
303 | | } else { |
304 | 492 | Ok(IndexOrRef(parser.parse()?)) |
305 | | } |
306 | 409k | } <wast::ast::token::IndexOrRef<wast::ast::kw::instance> as wast::parser::Parse>::parse Line | Count | Source | 296 | 38 | fn parse(parser: Parser<'a>) -> Result<Self> { | 297 | 38 | if parser.peek::<Index<'_>>() { | 298 | | Ok(IndexOrRef(ItemRef::Item { | 299 | 12 | kind: K::default(), | 300 | 12 | idx: parser.parse()?, | 301 | 11 | exports: Vec::new(), | 302 | | })) | 303 | | } else { | 304 | 26 | Ok(IndexOrRef(parser.parse()?)) | 305 | | } | 306 | 38 | } |
Unexecuted instantiation: <wast::ast::token::IndexOrRef<wast::ast::kw::module> as wast::parser::Parse>::parse <wast::ast::token::IndexOrRef<wast::ast::kw::table> as wast::parser::Parse>::parse Line | Count | Source | 296 | 13.7k | fn parse(parser: Parser<'a>) -> Result<Self> { | 297 | 13.7k | if parser.peek::<Index<'_>>() { | 298 | | Ok(IndexOrRef(ItemRef::Item { | 299 | 13.6k | kind: K::default(), | 300 | 13.6k | idx: parser.parse()?, | 301 | 13.6k | exports: Vec::new(), | 302 | | })) | 303 | | } else { | 304 | 32 | Ok(IndexOrRef(parser.parse()?)) | 305 | | } | 306 | 13.7k | } |
<wast::ast::token::IndexOrRef<wast::ast::kw::func> as wast::parser::Parse>::parse Line | Count | Source | 296 | 389k | fn parse(parser: Parser<'a>) -> Result<Self> { | 297 | 389k | if parser.peek::<Index<'_>>() { | 298 | | Ok(IndexOrRef(ItemRef::Item { | 299 | 389k | kind: K::default(), | 300 | 389k | idx: parser.parse()?, | 301 | 389k | exports: Vec::new(), | 302 | | })) | 303 | | } else { | 304 | 356 | Ok(IndexOrRef(parser.parse()?)) | 305 | | } | 306 | 389k | } |
<wast::ast::token::IndexOrRef<wast::ast::kw::global> as wast::parser::Parse>::parse Line | Count | Source | 296 | 4.96k | fn parse(parser: Parser<'a>) -> Result<Self> { | 297 | 4.96k | if parser.peek::<Index<'_>>() { | 298 | | Ok(IndexOrRef(ItemRef::Item { | 299 | 4.92k | kind: K::default(), | 300 | 4.92k | idx: parser.parse()?, | 301 | 4.92k | exports: Vec::new(), | 302 | | })) | 303 | | } else { | 304 | 43 | Ok(IndexOrRef(parser.parse()?)) | 305 | | } | 306 | 4.96k | } |
<wast::ast::token::IndexOrRef<wast::ast::kw::memory> as wast::parser::Parse>::parse Line | Count | Source | 296 | 1.17k | fn parse(parser: Parser<'a>) -> Result<Self> { | 297 | 1.17k | if parser.peek::<Index<'_>>() { | 298 | | Ok(IndexOrRef(ItemRef::Item { | 299 | 1.13k | kind: K::default(), | 300 | 1.13k | idx: parser.parse()?, | 301 | 1.12k | exports: Vec::new(), | 302 | | })) | 303 | | } else { | 304 | 35 | Ok(IndexOrRef(parser.parse()?)) | 305 | | } | 306 | 1.17k | } |
|
307 | | } |
308 | | |
309 | | impl<'a, K: Peek> Peek for IndexOrRef<'a, K> { |
310 | 393k | fn peek(cursor: Cursor<'_>) -> bool { |
311 | 393k | Index::peek(cursor) || ItemRef::<K>::peek(cursor) |
312 | 393k | } <wast::ast::token::IndexOrRef<wast::ast::kw::table> as wast::parser::Peek>::peek Line | Count | Source | 310 | 34.6k | fn peek(cursor: Cursor<'_>) -> bool { | 311 | 34.6k | Index::peek(cursor) || ItemRef::<K>::peek(cursor) | 312 | 34.6k | } |
<wast::ast::token::IndexOrRef<wast::ast::kw::func> as wast::parser::Peek>::peek Line | Count | Source | 310 | 309k | fn peek(cursor: Cursor<'_>) -> bool { | 311 | 309k | Index::peek(cursor) || ItemRef::<K>::peek(cursor) | 312 | 309k | } |
<wast::ast::token::IndexOrRef<wast::ast::kw::memory> as wast::parser::Peek>::peek Line | Count | Source | 310 | 50.1k | fn peek(cursor: Cursor<'_>) -> bool { | 311 | 50.1k | Index::peek(cursor) || ItemRef::<K>::peek(cursor) | 312 | 50.1k | } |
|
313 | | |
314 | 0 | fn display() -> &'static str { |
315 | 0 | "an item reference" |
316 | 0 | } |
317 | | } |
318 | | |
319 | | /// An `@name` annotation in source, currently of the form `@name "foo"` |
320 | 0 | #[derive(Copy, Clone, PartialEq, Debug)] |
321 | | pub struct NameAnnotation<'a> { |
322 | | /// The name specified for the item |
323 | | pub name: &'a str, |
324 | | } |
325 | | |
326 | | impl<'a> Parse<'a> for NameAnnotation<'a> { |
327 | | fn parse(parser: Parser<'a>) -> Result<Self> { |
328 | 3 | parser.parse::<annotation::name>()?; |
329 | 3 | let name = parser.parse()?; |
330 | 0 | Ok(NameAnnotation { name }) |
331 | 3 | } |
332 | | } |
333 | | |
334 | | impl<'a> Parse<'a> for Option<NameAnnotation<'a>> { |
335 | 1.79M | fn parse(parser: Parser<'a>) -> Result<Self> { |
336 | 1.79M | let _r = parser.register_annotation("name"); |
337 | 1.79M | Ok(if parser.peek2::<annotation::name>() { |
338 | 3 | Some(parser.parens(|p| p.parse())?) |
339 | | } else { |
340 | 1.79M | None |
341 | | }) |
342 | 1.79M | } |
343 | | } |
344 | | |
345 | | macro_rules! integers { |
346 | | ($($i:ident($u:ident))*) => ($( |
347 | | impl<'a> Parse<'a> for $i { |
348 | 1.39M | fn parse(parser: Parser<'a>) -> Result<Self> { |
349 | 1.39M | Ok(parser.parse::<($i, Span)>()?.0) |
350 | 1.39M | } <i8 as wast::parser::Parse>::parse Line | Count | Source | 348 | 23 | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 23 | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 23 | } |
Unexecuted instantiation: <u16 as wast::parser::Parse>::parse <u64 as wast::parser::Parse>::parse Line | Count | Source | 348 | 22 | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 22 | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 22 | } |
<i16 as wast::parser::Parse>::parse Line | Count | Source | 348 | 1.67k | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 1.67k | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 1.67k | } |
<i64 as wast::parser::Parse>::parse Line | Count | Source | 348 | 824k | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 824k | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 824k | } |
<u8 as wast::parser::Parse>::parse Line | Count | Source | 348 | 320 | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 320 | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 320 | } |
<u32 as wast::parser::Parse>::parse Line | Count | Source | 348 | 18.2k | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 18.2k | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 18.2k | } |
<i32 as wast::parser::Parse>::parse Line | Count | Source | 348 | 553k | fn parse(parser: Parser<'a>) -> Result<Self> { | 349 | 553k | Ok(parser.parse::<($i, Span)>()?.0) | 350 | 553k | } |
|
351 | | } |
352 | | |
353 | | impl<'a> Parse<'a> for ($i, Span) { |
354 | 1.88M | fn parse(parser: Parser<'a>) -> Result<Self> { |
355 | 1.88M | parser.step(|c| { |
356 | 1.88M | if let Some((i, rest)) = c.integer() { |
357 | 1.88M | let (s, base) = i.val(); |
358 | 1.88M | let val = $i::from_str_radix(s, base) |
359 | 38.9k | .or_else(|_| { |
360 | 38.8k | $u::from_str_radix(s, base).map(|i| i as $i) <(i64, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}::{closure#0}Line | Count | Source | 360 | 7.74k | $u::from_str_radix(s, base).map(|i| i as $i) |
<(i16, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}::{closure#0}Line | Count | Source | 360 | 1 | $u::from_str_radix(s, base).map(|i| i as $i) |
<(i32, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}::{closure#0}Line | Count | Source | 360 | 31.1k | $u::from_str_radix(s, base).map(|i| i as $i) |
|
361 | 1.88M | }); <(i64, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 7.74k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 7.74k | }); |
<(i8, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 2 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 2 | }); |
<(i16, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 5 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 5 | }); |
Unexecuted instantiation: <(u16, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}<(u32, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 58 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 58 | }); |
<(u64, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 2 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 2 | }); |
<(u8, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 2 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 2 | }); |
<(i32, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}::{closure#0}Line | Count | Source | 359 | 31.1k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 31.1k | }); |
|
362 | 1.88M | return match val { |
363 | 1.88M | Ok(n) => Ok(((n, c.cur_span()), rest)), |
364 | 72 | Err(_) => Err(c.error(concat!( |
365 | 72 | "invalid ", |
366 | 72 | stringify!($i), |
367 | 72 | " number: constant out of range", |
368 | 72 | ))), |
369 | | }; |
370 | 193 | } |
371 | 193 | Err(c.error(concat!("expected a ", stringify!($i)))) |
372 | 1.88M | }) Unexecuted instantiation: <(u16, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}<(i32, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 553k | parser.step(|c| { | 356 | 553k | if let Some((i, rest)) = c.integer() { | 357 | 553k | let (s, base) = i.val(); | 358 | 553k | let val = $i::from_str_radix(s, base) | 359 | 553k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 553k | }); | 362 | 553k | return match val { | 363 | 553k | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 2 | Err(_) => Err(c.error(concat!( | 365 | 2 | "invalid ", | 366 | 2 | stringify!($i), | 367 | 2 | " number: constant out of range", | 368 | 2 | ))), | 369 | | }; | 370 | 43 | } | 371 | 43 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 553k | }) |
<(i16, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 1.67k | parser.step(|c| { | 356 | 1.67k | if let Some((i, rest)) = c.integer() { | 357 | 1.64k | let (s, base) = i.val(); | 358 | 1.64k | let val = $i::from_str_radix(s, base) | 359 | 1.64k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 1.64k | }); | 362 | 1.64k | return match val { | 363 | 1.64k | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 4 | Err(_) => Err(c.error(concat!( | 365 | 4 | "invalid ", | 366 | 4 | stringify!($i), | 367 | 4 | " number: constant out of range", | 368 | 4 | ))), | 369 | | }; | 370 | 27 | } | 371 | 27 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 1.67k | }) |
<(u32, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 501k | parser.step(|c| { | 356 | 501k | if let Some((i, rest)) = c.integer() { | 357 | 501k | let (s, base) = i.val(); | 358 | 501k | let val = $i::from_str_radix(s, base) | 359 | 501k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 501k | }); | 362 | 501k | return match val { | 363 | 501k | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 58 | Err(_) => Err(c.error(concat!( | 365 | 58 | "invalid ", | 366 | 58 | stringify!($i), | 367 | 58 | " number: constant out of range", | 368 | 58 | ))), | 369 | | }; | 370 | 19 | } | 371 | 19 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 501k | }) |
<(i64, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 824k | parser.step(|c| { | 356 | 824k | if let Some((i, rest)) = c.integer() { | 357 | 824k | let (s, base) = i.val(); | 358 | 824k | let val = $i::from_str_radix(s, base) | 359 | 824k | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 824k | }); | 362 | 824k | return match val { | 363 | 824k | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 2 | Err(_) => Err(c.error(concat!( | 365 | 2 | "invalid ", | 366 | 2 | stringify!($i), | 367 | 2 | " number: constant out of range", | 368 | 2 | ))), | 369 | | }; | 370 | 39 | } | 371 | 39 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 824k | }) |
<(u8, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 320 | parser.step(|c| { | 356 | 320 | if let Some((i, rest)) = c.integer() { | 357 | 280 | let (s, base) = i.val(); | 358 | 280 | let val = $i::from_str_radix(s, base) | 359 | 280 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 280 | }); | 362 | 280 | return match val { | 363 | 278 | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 2 | Err(_) => Err(c.error(concat!( | 365 | 2 | "invalid ", | 366 | 2 | stringify!($i), | 367 | 2 | " number: constant out of range", | 368 | 2 | ))), | 369 | | }; | 370 | 40 | } | 371 | 40 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 320 | }) |
<(u64, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 22 | parser.step(|c| { | 356 | 22 | if let Some((i, rest)) = c.integer() { | 357 | 13 | let (s, base) = i.val(); | 358 | 13 | let val = $i::from_str_radix(s, base) | 359 | 13 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 13 | }); | 362 | 13 | return match val { | 363 | 11 | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 2 | Err(_) => Err(c.error(concat!( | 365 | 2 | "invalid ", | 366 | 2 | stringify!($i), | 367 | 2 | " number: constant out of range", | 368 | 2 | ))), | 369 | | }; | 370 | 9 | } | 371 | 9 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 22 | }) |
<(i8, wast::ast::token::Span) as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 355 | 23 | parser.step(|c| { | 356 | 23 | if let Some((i, rest)) = c.integer() { | 357 | 7 | let (s, base) = i.val(); | 358 | 7 | let val = $i::from_str_radix(s, base) | 359 | 7 | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | 7 | }); | 362 | 7 | return match val { | 363 | 5 | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | 2 | Err(_) => Err(c.error(concat!( | 365 | 2 | "invalid ", | 366 | 2 | stringify!($i), | 367 | 2 | " number: constant out of range", | 368 | 2 | ))), | 369 | | }; | 370 | 16 | } | 371 | 16 | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | 23 | }) |
|
373 | 1.88M | } <(u8, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 320 | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 320 | } |
<(u32, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 501k | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 501k | } |
<(i16, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 1.67k | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 1.67k | } |
<(i64, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 824k | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 824k | } |
<(i32, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 553k | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 553k | } |
Unexecuted instantiation: <(u16, wast::ast::token::Span) as wast::parser::Parse>::parse <(u64, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 22 | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 22 | } |
<(i8, wast::ast::token::Span) as wast::parser::Parse>::parse Line | Count | Source | 354 | 23 | fn parse(parser: Parser<'a>) -> Result<Self> { | 355 | | parser.step(|c| { | 356 | | if let Some((i, rest)) = c.integer() { | 357 | | let (s, base) = i.val(); | 358 | | let val = $i::from_str_radix(s, base) | 359 | | .or_else(|_| { | 360 | | $u::from_str_radix(s, base).map(|i| i as $i) | 361 | | }); | 362 | | return match val { | 363 | | Ok(n) => Ok(((n, c.cur_span()), rest)), | 364 | | Err(_) => Err(c.error(concat!( | 365 | | "invalid ", | 366 | | stringify!($i), | 367 | | " number: constant out of range", | 368 | | ))), | 369 | | }; | 370 | | } | 371 | | Err(c.error(concat!("expected a ", stringify!($i)))) | 372 | | }) | 373 | 23 | } |
|
374 | | } |
375 | | |
376 | | impl Peek for $i { |
377 | 1.65M | fn peek(cursor: Cursor<'_>) -> bool {<u64 as wast::parser::Peek>::peek Line | Count | Source | 377 | 9 | fn peek(cursor: Cursor<'_>) -> bool { |
<u32 as wast::parser::Peek>::peek Line | Count | Source | 377 | 1.65M | fn peek(cursor: Cursor<'_>) -> bool { |
|
378 | | cursor.integer().is_some() |
379 | | } |
380 | | |
381 | 274 | fn display() -> &'static str { |
382 | | stringify!($i) |
383 | | } |
384 | | } |
385 | | )*) |
386 | | } |
387 | | |
388 | | integers! { |
389 | | u8(u8) u16(u16) u32(u32) u64(u64) |
390 | | i8(u8) i16(u16) i32(u32) i64(u64) |
391 | | } |
392 | | |
393 | | impl<'a> Parse<'a> for &'a [u8] { |
394 | 596k | fn parse(parser: Parser<'a>) -> Result<Self> { |
395 | 596k | parser.step(|c| { |
396 | 596k | if let Some((i, rest)) = c.string() { |
397 | 596k | return Ok((i, rest)); |
398 | 150 | } |
399 | 150 | Err(c.error("expected a string")) |
400 | 596k | }) |
401 | 596k | } |
402 | | } |
403 | | |
404 | | impl Peek for &'_ [u8] { |
405 | 49.6k | fn peek(cursor: Cursor<'_>) -> bool { |
406 | 49.6k | cursor.string().is_some() |
407 | 49.6k | } |
408 | | |
409 | | fn display() -> &'static str { |
410 | | "string" |
411 | | } |
412 | | } |
413 | | |
414 | | impl<'a> Parse<'a> for &'a str { |
415 | 190k | fn parse(parser: Parser<'a>) -> Result<Self> { |
416 | 190k | str::from_utf8(parser.parse()?).map_err(|_| parser.error("malformed UTF-8 encoding")) |
417 | 190k | } |
418 | | } |
419 | | |
420 | | impl Parse<'_> for String { |
421 | 0 | fn parse(parser: Parser<'_>) -> Result<Self> { |
422 | 0 | Ok(<&str>::parse(parser)?.to_string()) |
423 | 0 | } |
424 | | } |
425 | | |
426 | | impl Peek for &'_ str { |
427 | 10.3k | fn peek(cursor: Cursor<'_>) -> bool { |
428 | 10.3k | <&[u8]>::peek(cursor) |
429 | 10.3k | } |
430 | | |
431 | | fn display() -> &'static str { |
432 | | <&[u8]>::display() |
433 | | } |
434 | | } |
435 | | |
436 | | macro_rules! float { |
437 | | ($($name:ident => { |
438 | | bits: $int:ident, |
439 | | float: $float:ident, |
440 | | exponent_bits: $exp_bits:tt, |
441 | | name: $parse:ident, |
442 | | })*) => ($( |
443 | | /// A parsed floating-point type |
444 | | #[derive(Debug)] |
445 | | pub struct $name { |
446 | | /// The raw bits that this floating point number represents. |
447 | | pub bits: $int, |
448 | | } |
449 | | |
450 | | impl<'a> Parse<'a> for $name { |
451 | 2.24M | fn parse(parser: Parser<'a>) -> Result<Self> { |
452 | 2.24M | parser.step(|c| { |
453 | 2.24M | let (val, rest) = if let Some((f, rest)) = c.float() { |
454 | 148k | ($parse(f.val()), rest) |
455 | 2.09M | } else if let Some((i, rest)) = c.integer() { |
456 | 2.09M | let (s, base) = i.val(); |
457 | 2.09M | ( |
458 | 2.09M | $parse(&FloatVal::Val { |
459 | 2.09M | hex: base == 16, |
460 | 2.09M | integral: s.into(), |
461 | 2.09M | decimal: None, |
462 | 2.09M | exponent: None, |
463 | 2.09M | }), |
464 | 2.09M | rest, |
465 | 2.09M | ) |
466 | | } else { |
467 | 295 | return Err(c.error("expected a float")); |
468 | | }; |
469 | 2.24M | match val { |
470 | 2.24M | Some(bits) => Ok(($name { bits }, rest)), |
471 | 83 | None => Err(c.error("invalid float value: constant out of range")), |
472 | | } |
473 | 2.24M | }) <wast::ast::token::Float64 as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 452 | 1.92M | parser.step(|c| { | 453 | 1.92M | let (val, rest) = if let Some((f, rest)) = c.float() { | 454 | 68.6k | ($parse(f.val()), rest) | 455 | 1.85M | } else if let Some((i, rest)) = c.integer() { | 456 | 1.85M | let (s, base) = i.val(); | 457 | 1.85M | ( | 458 | 1.85M | $parse(&FloatVal::Val { | 459 | 1.85M | hex: base == 16, | 460 | 1.85M | integral: s.into(), | 461 | 1.85M | decimal: None, | 462 | 1.85M | exponent: None, | 463 | 1.85M | }), | 464 | 1.85M | rest, | 465 | 1.85M | ) | 466 | | } else { | 467 | 141 | return Err(c.error("expected a float")); | 468 | | }; | 469 | 1.92M | match val { | 470 | 1.92M | Some(bits) => Ok(($name { bits }, rest)), | 471 | 33 | None => Err(c.error("invalid float value: constant out of range")), | 472 | | } | 473 | 1.92M | }) |
<wast::ast::token::Float32 as wast::parser::Parse>::parse::{closure#0}Line | Count | Source | 452 | 314k | parser.step(|c| { | 453 | 314k | let (val, rest) = if let Some((f, rest)) = c.float() { | 454 | 79.8k | ($parse(f.val()), rest) | 455 | 234k | } else if let Some((i, rest)) = c.integer() { | 456 | 234k | let (s, base) = i.val(); | 457 | 234k | ( | 458 | 234k | $parse(&FloatVal::Val { | 459 | 234k | hex: base == 16, | 460 | 234k | integral: s.into(), | 461 | 234k | decimal: None, | 462 | 234k | exponent: None, | 463 | 234k | }), | 464 | 234k | rest, | 465 | 234k | ) | 466 | | } else { | 467 | 154 | return Err(c.error("expected a float")); | 468 | | }; | 469 | 314k | match val { | 470 | 313k | Some(bits) => Ok(($name { bits }, rest)), | 471 | 50 | None => Err(c.error("invalid float value: constant out of range")), | 472 | | } | 473 | 314k | }) |
|
474 | 2.24M | } <wast::ast::token::Float32 as wast::parser::Parse>::parse Line | Count | Source | 451 | 314k | fn parse(parser: Parser<'a>) -> Result<Self> { | 452 | | parser.step(|c| { | 453 | | let (val, rest) = if let Some((f, rest)) = c.float() { | 454 | | ($parse(f.val()), rest) | 455 | | } else if let Some((i, rest)) = c.integer() { | 456 | | let (s, base) = i.val(); | 457 | | ( | 458 | | $parse(&FloatVal::Val { | 459 | | hex: base == 16, | 460 | | integral: s.into(), | 461 | | decimal: None, | 462 | | exponent: None, | 463 | | }), | 464 | | rest, | 465 | | ) | 466 | | } else { | 467 | | return Err(c.error("expected a float")); | 468 | | }; | 469 | | match val { | 470 | | Some(bits) => Ok(($name { bits }, rest)), | 471 | | None => Err(c.error("invalid float value: constant out of range")), | 472 | | } | 473 | | }) | 474 | 314k | } |
<wast::ast::token::Float64 as wast::parser::Parse>::parse Line | Count | Source | 451 | 1.92M | fn parse(parser: Parser<'a>) -> Result<Self> { | 452 | | parser.step(|c| { | 453 | | let (val, rest) = if let Some((f, rest)) = c.float() { | 454 | | ($parse(f.val()), rest) | 455 | | } else if let Some((i, rest)) = c.integer() { | 456 | | let (s, base) = i.val(); | 457 | | ( | 458 | | $parse(&FloatVal::Val { | 459 | | hex: base == 16, | 460 | | integral: s.into(), | 461 | | decimal: None, | 462 | | exponent: None, | 463 | | }), | 464 | | rest, | 465 | | ) | 466 | | } else { | 467 | | return Err(c.error("expected a float")); | 468 | | }; | 469 | | match val { | 470 | | Some(bits) => Ok(($name { bits }, rest)), | 471 | | None => Err(c.error("invalid float value: constant out of range")), | 472 | | } | 473 | | }) | 474 | 1.92M | } |
|
475 | | } |
476 | | |
477 | 2.24M | fn $parse(val: &FloatVal<'_>) -> Option<$int> { |
478 | | // Compute a few well-known constants about the float representation |
479 | | // given the parameters to the macro here. |
480 | 2.24M | let width = std::mem::size_of::<$int>() * 8; |
481 | 2.24M | let neg_offset = width - 1; |
482 | 2.24M | let exp_offset = neg_offset - $exp_bits; |
483 | 2.24M | let signif_bits = width - 1 - $exp_bits; |
484 | 2.24M | let signif_mask = (1 << exp_offset) - 1; |
485 | 2.24M | let bias = (1 << ($exp_bits - 1)) - 1; |
486 | | |
487 | 2.24M | let (hex, integral, decimal, exponent_str) = match val { |
488 | | // Infinity is when the exponent bits are all set and |
489 | | // the significand is zero. |
490 | 1.78k | FloatVal::Inf { negative } => { |
491 | 1.78k | let exp_bits = (1 << $exp_bits) - 1; |
492 | 1.78k | let neg_bit = *negative as $int; |
493 | 1.78k | return Some( |
494 | 1.78k | (neg_bit << neg_offset) | |
495 | 1.78k | (exp_bits << exp_offset) |
496 | 1.78k | ); |
497 | | } |
498 | | |
499 | | // NaN is when the exponent bits are all set and |
500 | | // the significand is nonzero. The default of NaN is |
501 | | // when only the highest bit of the significand is set. |
502 | 3.74k | FloatVal::Nan { negative, val } => { |
503 | 3.74k | let exp_bits = (1 << $exp_bits) - 1; |
504 | 3.74k | let neg_bit = *negative as $int; |
505 | 3.74k | let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int; |
506 | 3.74k | // If the significand is zero then this is actually infinity |
507 | 3.74k | // so we fail to parse it. |
508 | 3.74k | if signif & signif_mask == 0 { |
509 | 5 | return None; |
510 | 3.73k | } |
511 | 3.73k | return Some( |
512 | 3.73k | (neg_bit << neg_offset) | |
513 | 3.73k | (exp_bits << exp_offset) | |
514 | 3.73k | (signif & signif_mask) |
515 | 3.73k | ); |
516 | | } |
517 | | |
518 | | // This is trickier, handle this below |
519 | 2.23M | FloatVal::Val { hex, integral, decimal, exponent } => { |
520 | 2.23M | (hex, integral, decimal, exponent) |
521 | 2.23M | } |
522 | 2.23M | }; |
523 | 2.23M | |
524 | 2.23M | // Rely on Rust's standard library to parse base 10 floats |
525 | 2.23M | // correctly. |
526 | 2.23M | if !*hex { |
527 | 2.16M | let mut s = integral.to_string(); |
528 | 2.16M | if let Some(decimal) = decimal { |
529 | 112k | s.push_str("."); |
530 | 112k | s.push_str(&decimal); |
531 | 2.05M | } |
532 | 2.16M | if let Some(exponent) = exponent_str { |
533 | 8.33k | s.push_str("e"); |
534 | 8.33k | s.push_str(&exponent); |
535 | 2.15M | } |
536 | 2.16M | let float = s.parse::<$float>().ok()?; |
537 | | // looks like the `*.wat` format considers infinite overflow to |
538 | | // be invalid. |
539 | 2.16M | if float.is_infinite() { |
540 | 38 | return None; |
541 | 2.16M | } |
542 | 2.16M | return Some(float.to_bits()); |
543 | 68.1k | } |
544 | 68.1k | |
545 | 68.1k | // Parsing hex floats is... hard! I don't really know what most of |
546 | 68.1k | // this below does. It was copied from Gecko's implementation in |
547 | 68.1k | // `WasmTextToBinary.cpp`. Would love comments on this if you have |
548 | 68.1k | // them! |
549 | 68.1k | let decimal = decimal.as_ref().map(|s| &**s).unwrap_or("");wast::ast::token::strtod::{closure#0}Line | Count | Source | 549 | 9.27k | let decimal = decimal.as_ref().map(|s| &**s).unwrap_or(""); |
wast::ast::token::strtof::{closure#0}Line | Count | Source | 549 | 11.1k | let decimal = decimal.as_ref().map(|s| &**s).unwrap_or(""); |
|
550 | 68.1k | let negative = integral.starts_with('-'); |
551 | 68.1k | let integral = integral.trim_start_matches('-').trim_start_matches('0'); |
552 | 68.1k | |
553 | 68.1k | // Do a bunch of work up front to locate the first non-zero digit |
554 | 68.1k | // to determine the initial exponent. There's a number of |
555 | 68.1k | // adjustments depending on where the digit was found, but the |
556 | 68.1k | // general idea here is that I'm not really sure why things are |
557 | 68.1k | // calculated the way they are but it should match Gecko. |
558 | 68.1k | let decimal_no_leading = decimal.trim_start_matches('0'); |
559 | 68.1k | let decimal_iter = if integral.is_empty() { |
560 | 14.6k | decimal_no_leading.chars() |
561 | | } else { |
562 | 53.5k | decimal.chars() |
563 | | }; |
564 | 68.1k | let mut digits = integral.chars() |
565 | 526k | .map(|c| (to_hex(c) as $int, false)) wast::ast::token::strtof::{closure#1}Line | Count | Source | 565 | 81.4k | .map(|c| (to_hex(c) as $int, false)) |
wast::ast::token::strtod::{closure#1}Line | Count | Source | 565 | 444k | .map(|c| (to_hex(c) as $int, false)) |
|
566 | 428k | .chain(decimal_iter.map(|c| (to_hex(c) as $int, true))); wast::ast::token::strtod::{closure#2}Line | Count | Source | 566 | 279k | .chain(decimal_iter.map(|c| (to_hex(c) as $int, true))); |
wast::ast::token::strtof::{closure#2}Line | Count | Source | 566 | 148k | .chain(decimal_iter.map(|c| (to_hex(c) as $int, true))); |
|
567 | 68.1k | let lead_nonzero_digit = match digits.next() { |
568 | 62.4k | Some((c, _)) => c, |
569 | | // No digits? Must be `+0` or `-0`, being careful to handle the |
570 | | // sign encoding here. |
571 | 740 | None if negative => return Some(1 << (width - 1)), |
572 | 4.93k | None => return Some(0), |
573 | | }; |
574 | 62.4k | let mut significand = 0 as $int; |
575 | 62.4k | let mut exponent = if !integral.is_empty() { |
576 | 53.5k | 1 |
577 | | } else { |
578 | 8.98k | -((decimal.len() - decimal_no_leading.len() + 1) as i32) + 1 |
579 | | }; |
580 | 62.4k | let lz = (lead_nonzero_digit as u8).leading_zeros() as i32 - 4; |
581 | 62.4k | exponent = exponent.checked_mul(4)?.checked_sub(lz + 1)?; |
582 | 62.4k | let mut significand_pos = (width - (4 - (lz as usize))) as isize; |
583 | 62.4k | assert!(significand_pos >= 0); |
584 | 62.4k | significand |= lead_nonzero_digit << significand_pos; |
585 | 62.4k | |
586 | 62.4k | // Now that we've got an anchor in the string we parse the remaining |
587 | 62.4k | // digits. Again, not entirely sure why everything is the way it is |
588 | 62.4k | // here! This is copied frmo gecko. |
589 | 62.4k | let mut discarded_extra_nonzero = false; |
590 | 954k | for (digit, decimal) in digits { |
591 | 892k | if !decimal { |
592 | 472k | exponent += 4; |
593 | 419k | } |
594 | 892k | if significand_pos > -4 { |
595 | 306k | significand_pos -= 4; |
596 | 585k | } |
597 | | |
598 | 892k | if significand_pos >= 0 { |
599 | 281k | significand |= digit << significand_pos; |
600 | 610k | } else if significand_pos > -4 { |
601 | 9.10k | significand |= digit >> (4 - significand_pos); |
602 | 9.10k | discarded_extra_nonzero = (digit & !((!0) >> (4 - significand_pos))) != 0; |
603 | 601k | } else if digit != 0 { |
604 | 174k | discarded_extra_nonzero = true; |
605 | 427k | } |
606 | | } |
607 | | |
608 | 62.4k | exponent = exponent.checked_add(match exponent_str { |
609 | 8.14k | Some(s) => s.parse::<i32>().ok()?, |
610 | 54.3k | None => 0, |
611 | 0 | })?; |
612 | | debug_assert!(significand != 0); |
613 | | |
614 | 62.4k | let (encoded_exponent, encoded_significand, discarded_significand) = |
615 | 62.4k | if exponent <= -bias { |
616 | | // Underflow to subnormal or zero. |
617 | 4.31k | let shift = exp_offset as i32 + exponent + bias; |
618 | 4.31k | if shift == 0 { |
619 | 415 | (0, 0, significand) |
620 | 3.90k | } else if shift < 0 || shift >= width as i32 { |
621 | 810 | (0, 0, 0) |
622 | | } else { |
623 | 3.09k | ( |
624 | 3.09k | 0, |
625 | 3.09k | significand >> (width as i32 - shift), |
626 | 3.09k | significand << shift, |
627 | 3.09k | ) |
628 | | } |
629 | 58.1k | } else if exponent <= bias { |
630 | | // Normal (non-zero). The significand's leading 1 is encoded |
631 | | // implicitly. |
632 | 58.1k | ( |
633 | 58.1k | ((exponent + bias) as $int) << exp_offset, |
634 | 58.1k | (significand >> (width - exp_offset - 1)) & signif_mask, |
635 | 58.1k | significand << (exp_offset + 1), |
636 | 58.1k | ) |
637 | | } else { |
638 | | // Overflow to infinity. |
639 | 27 | ( |
640 | 27 | ((1 << $exp_bits) - 1) << exp_offset, |
641 | 27 | 0, |
642 | 27 | 0, |
643 | 27 | ) |
644 | | }; |
645 | | |
646 | 62.4k | let bits = encoded_exponent | encoded_significand; |
647 | 62.4k | |
648 | 62.4k | // Apply rounding. If this overflows the significand, it carries |
649 | 62.4k | // into the exponent bit according to the magic of the IEEE 754 |
650 | 62.4k | // encoding. |
651 | 62.4k | // |
652 | 62.4k | // Or rather, the comment above is what Gecko says so it's copied |
653 | 62.4k | // here too. |
654 | 62.4k | let msb = 1 << (width - 1); |
655 | 62.4k | let bits = bits |
656 | 62.4k | + (((discarded_significand & msb != 0) |
657 | 7.35k | && ((discarded_significand & !msb != 0) || |
658 | 366 | discarded_extra_nonzero || |
659 | | // ties to even |
660 | 306 | (encoded_significand & 1 != 0))) as $int); |
661 | | |
662 | | // Just before we return the bits be sure to handle the sign bit we |
663 | | // found at the beginning. |
664 | 62.4k | let bits = if negative { |
665 | 4.73k | bits | (1 << (width - 1)) |
666 | | } else { |
667 | 57.7k | bits |
668 | | }; |
669 | | // looks like the `*.wat` format considers infinite overflow to |
670 | | // be invalid. |
671 | 62.4k | if $float::from_bits(bits).is_infinite() { |
672 | 27 | return None; |
673 | 62.4k | } |
674 | 62.4k | Some(bits) |
675 | 2.24M | } Line | Count | Source | 477 | 314k | fn $parse(val: &FloatVal<'_>) -> Option<$int> { | 478 | | // Compute a few well-known constants about the float representation | 479 | | // given the parameters to the macro here. | 480 | 314k | let width = std::mem::size_of::<$int>() * 8; | 481 | 314k | let neg_offset = width - 1; | 482 | 314k | let exp_offset = neg_offset - $exp_bits; | 483 | 314k | let signif_bits = width - 1 - $exp_bits; | 484 | 314k | let signif_mask = (1 << exp_offset) - 1; | 485 | 314k | let bias = (1 << ($exp_bits - 1)) - 1; | 486 | | | 487 | 314k | let (hex, integral, decimal, exponent_str) = match val { | 488 | | // Infinity is when the exponent bits are all set and | 489 | | // the significand is zero. | 490 | 11 | FloatVal::Inf { negative } => { | 491 | 11 | let exp_bits = (1 << $exp_bits) - 1; | 492 | 11 | let neg_bit = *negative as $int; | 493 | 11 | return Some( | 494 | 11 | (neg_bit << neg_offset) | | 495 | 11 | (exp_bits << exp_offset) | 496 | 11 | ); | 497 | | } | 498 | | | 499 | | // NaN is when the exponent bits are all set and | 500 | | // the significand is nonzero. The default of NaN is | 501 | | // when only the highest bit of the significand is set. | 502 | 101 | FloatVal::Nan { negative, val } => { | 503 | 101 | let exp_bits = (1 << $exp_bits) - 1; | 504 | 101 | let neg_bit = *negative as $int; | 505 | 101 | let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int; | 506 | 101 | // If the significand is zero then this is actually infinity | 507 | 101 | // so we fail to parse it. | 508 | 101 | if signif & signif_mask == 0 { | 509 | 2 | return None; | 510 | 99 | } | 511 | 99 | return Some( | 512 | 99 | (neg_bit << neg_offset) | | 513 | 99 | (exp_bits << exp_offset) | | 514 | 99 | (signif & signif_mask) | 515 | 99 | ); | 516 | | } | 517 | | | 518 | | // This is trickier, handle this below | 519 | 313k | FloatVal::Val { hex, integral, decimal, exponent } => { | 520 | 313k | (hex, integral, decimal, exponent) | 521 | 313k | } | 522 | 313k | }; | 523 | 313k | | 524 | 313k | // Rely on Rust's standard library to parse base 10 floats | 525 | 313k | // correctly. | 526 | 313k | if !*hex { | 527 | 298k | let mut s = integral.to_string(); | 528 | 298k | if let Some(decimal) = decimal { | 529 | 66.3k | s.push_str("."); | 530 | 66.3k | s.push_str(&decimal); | 531 | 232k | } | 532 | 298k | if let Some(exponent) = exponent_str { | 533 | 3.87k | s.push_str("e"); | 534 | 3.87k | s.push_str(&exponent); | 535 | 294k | } | 536 | 298k | let float = s.parse::<$float>().ok()?; | 537 | | // looks like the `*.wat` format considers infinite overflow to | 538 | | // be invalid. | 539 | 298k | if float.is_infinite() { | 540 | 22 | return None; | 541 | 298k | } | 542 | 298k | return Some(float.to_bits()); | 543 | 15.4k | } | 544 | 15.4k | | 545 | 15.4k | // Parsing hex floats is... hard! I don't really know what most of | 546 | 15.4k | // this below does. It was copied from Gecko's implementation in | 547 | 15.4k | // `WasmTextToBinary.cpp`. Would love comments on this if you have | 548 | 15.4k | // them! | 549 | 15.4k | let decimal = decimal.as_ref().map(|s| &**s).unwrap_or(""); | 550 | 15.4k | let negative = integral.starts_with('-'); | 551 | 15.4k | let integral = integral.trim_start_matches('-').trim_start_matches('0'); | 552 | 15.4k | | 553 | 15.4k | // Do a bunch of work up front to locate the first non-zero digit | 554 | 15.4k | // to determine the initial exponent. There's a number of | 555 | 15.4k | // adjustments depending on where the digit was found, but the | 556 | 15.4k | // general idea here is that I'm not really sure why things are | 557 | 15.4k | // calculated the way they are but it should match Gecko. | 558 | 15.4k | let decimal_no_leading = decimal.trim_start_matches('0'); | 559 | 15.4k | let decimal_iter = if integral.is_empty() { | 560 | 8.97k | decimal_no_leading.chars() | 561 | | } else { | 562 | 6.43k | decimal.chars() | 563 | | }; | 564 | 15.4k | let mut digits = integral.chars() | 565 | 15.4k | .map(|c| (to_hex(c) as $int, false)) | 566 | 15.4k | .chain(decimal_iter.map(|c| (to_hex(c) as $int, true))); | 567 | 15.4k | let lead_nonzero_digit = match digits.next() { | 568 | 12.7k | Some((c, _)) => c, | 569 | | // No digits? Must be `+0` or `-0`, being careful to handle the | 570 | | // sign encoding here. | 571 | 13 | None if negative => return Some(1 << (width - 1)), | 572 | 2.63k | None => return Some(0), | 573 | | }; | 574 | 12.7k | let mut significand = 0 as $int; | 575 | 12.7k | let mut exponent = if !integral.is_empty() { | 576 | 6.43k | 1 | 577 | | } else { | 578 | 6.33k | -((decimal.len() - decimal_no_leading.len() + 1) as i32) + 1 | 579 | | }; | 580 | 12.7k | let lz = (lead_nonzero_digit as u8).leading_zeros() as i32 - 4; | 581 | 12.7k | exponent = exponent.checked_mul(4)?.checked_sub(lz + 1)?; | 582 | 12.7k | let mut significand_pos = (width - (4 - (lz as usize))) as isize; | 583 | 12.7k | assert!(significand_pos >= 0); | 584 | 12.7k | significand |= lead_nonzero_digit << significand_pos; | 585 | 12.7k | | 586 | 12.7k | // Now that we've got an anchor in the string we parse the remaining | 587 | 12.7k | // digits. Again, not entirely sure why everything is the way it is | 588 | 12.7k | // here! This is copied frmo gecko. | 589 | 12.7k | let mut discarded_extra_nonzero = false; | 590 | 230k | for (digit, decimal) in digits { | 591 | 217k | if !decimal { | 592 | 75.0k | exponent += 4; | 593 | 142k | } | 594 | 217k | if significand_pos > -4 { | 595 | 88.3k | significand_pos -= 4; | 596 | 128k | } | 597 | | | 598 | 217k | if significand_pos >= 0 { | 599 | 73.1k | significand |= digit << significand_pos; | 600 | 144k | } else if significand_pos > -4 { | 601 | 7.24k | significand |= digit >> (4 - significand_pos); | 602 | 7.24k | discarded_extra_nonzero = (digit & !((!0) >> (4 - significand_pos))) != 0; | 603 | 136k | } else if digit != 0 { | 604 | 56.2k | discarded_extra_nonzero = true; | 605 | 80.6k | } | 606 | | } | 607 | | | 608 | 12.7k | exponent = exponent.checked_add(match exponent_str { | 609 | 151 | Some(s) => s.parse::<i32>().ok()?, | 610 | 12.6k | None => 0, | 611 | 0 | })?; | 612 | | debug_assert!(significand != 0); | 613 | | | 614 | 12.7k | let (encoded_exponent, encoded_significand, discarded_significand) = | 615 | 12.7k | if exponent <= -bias { | 616 | | // Underflow to subnormal or zero. | 617 | 2.84k | let shift = exp_offset as i32 + exponent + bias; | 618 | 2.84k | if shift == 0 { | 619 | 397 | (0, 0, significand) | 620 | 2.44k | } else if shift < 0 || shift >= width as i32 { | 621 | 716 | (0, 0, 0) | 622 | | } else { | 623 | 1.73k | ( | 624 | 1.73k | 0, | 625 | 1.73k | significand >> (width as i32 - shift), | 626 | 1.73k | significand << shift, | 627 | 1.73k | ) | 628 | | } | 629 | 9.92k | } else if exponent <= bias { | 630 | | // Normal (non-zero). The significand's leading 1 is encoded | 631 | | // implicitly. | 632 | 9.90k | ( | 633 | 9.90k | ((exponent + bias) as $int) << exp_offset, | 634 | 9.90k | (significand >> (width - exp_offset - 1)) & signif_mask, | 635 | 9.90k | significand << (exp_offset + 1), | 636 | 9.90k | ) | 637 | | } else { | 638 | | // Overflow to infinity. | 639 | 21 | ( | 640 | 21 | ((1 << $exp_bits) - 1) << exp_offset, | 641 | 21 | 0, | 642 | 21 | 0, | 643 | 21 | ) | 644 | | }; | 645 | | | 646 | 12.7k | let bits = encoded_exponent | encoded_significand; | 647 | 12.7k | | 648 | 12.7k | // Apply rounding. If this overflows the significand, it carries | 649 | 12.7k | // into the exponent bit according to the magic of the IEEE 754 | 650 | 12.7k | // encoding. | 651 | 12.7k | // | 652 | 12.7k | // Or rather, the comment above is what Gecko says so it's copied | 653 | 12.7k | // here too. | 654 | 12.7k | let msb = 1 << (width - 1); | 655 | 12.7k | let bits = bits | 656 | 12.7k | + (((discarded_significand & msb != 0) | 657 | 2.87k | && ((discarded_significand & !msb != 0) || | 658 | 335 | discarded_extra_nonzero || | 659 | | // ties to even | 660 | 279 | (encoded_significand & 1 != 0))) as $int); | 661 | | | 662 | | // Just before we return the bits be sure to handle the sign bit we | 663 | | // found at the beginning. | 664 | 12.7k | let bits = if negative { | 665 | 378 | bits | (1 << (width - 1)) | 666 | | } else { | 667 | 12.3k | bits | 668 | | }; | 669 | | // looks like the `*.wat` format considers infinite overflow to | 670 | | // be invalid. | 671 | 12.7k | if $float::from_bits(bits).is_infinite() { | 672 | 21 | return None; | 673 | 12.7k | } | 674 | 12.7k | Some(bits) | 675 | 314k | } |
Line | Count | Source | 477 | 1.92M | fn $parse(val: &FloatVal<'_>) -> Option<$int> { | 478 | | // Compute a few well-known constants about the float representation | 479 | | // given the parameters to the macro here. | 480 | 1.92M | let width = std::mem::size_of::<$int>() * 8; | 481 | 1.92M | let neg_offset = width - 1; | 482 | 1.92M | let exp_offset = neg_offset - $exp_bits; | 483 | 1.92M | let signif_bits = width - 1 - $exp_bits; | 484 | 1.92M | let signif_mask = (1 << exp_offset) - 1; | 485 | 1.92M | let bias = (1 << ($exp_bits - 1)) - 1; | 486 | | | 487 | 1.92M | let (hex, integral, decimal, exponent_str) = match val { | 488 | | // Infinity is when the exponent bits are all set and | 489 | | // the significand is zero. | 490 | 1.77k | FloatVal::Inf { negative } => { | 491 | 1.77k | let exp_bits = (1 << $exp_bits) - 1; | 492 | 1.77k | let neg_bit = *negative as $int; | 493 | 1.77k | return Some( | 494 | 1.77k | (neg_bit << neg_offset) | | 495 | 1.77k | (exp_bits << exp_offset) | 496 | 1.77k | ); | 497 | | } | 498 | | | 499 | | // NaN is when the exponent bits are all set and | 500 | | // the significand is nonzero. The default of NaN is | 501 | | // when only the highest bit of the significand is set. | 502 | 3.64k | FloatVal::Nan { negative, val } => { | 503 | 3.64k | let exp_bits = (1 << $exp_bits) - 1; | 504 | 3.64k | let neg_bit = *negative as $int; | 505 | 3.64k | let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int; | 506 | 3.64k | // If the significand is zero then this is actually infinity | 507 | 3.64k | // so we fail to parse it. | 508 | 3.64k | if signif & signif_mask == 0 { | 509 | 3 | return None; | 510 | 3.64k | } | 511 | 3.64k | return Some( | 512 | 3.64k | (neg_bit << neg_offset) | | 513 | 3.64k | (exp_bits << exp_offset) | | 514 | 3.64k | (signif & signif_mask) | 515 | 3.64k | ); | 516 | | } | 517 | | | 518 | | // This is trickier, handle this below | 519 | 1.92M | FloatVal::Val { hex, integral, decimal, exponent } => { | 520 | 1.92M | (hex, integral, decimal, exponent) | 521 | 1.92M | } | 522 | 1.92M | }; | 523 | 1.92M | | 524 | 1.92M | // Rely on Rust's standard library to parse base 10 floats | 525 | 1.92M | // correctly. | 526 | 1.92M | if !*hex { | 527 | 1.86M | let mut s = integral.to_string(); | 528 | 1.86M | if let Some(decimal) = decimal { | 529 | 45.9k | s.push_str("."); | 530 | 45.9k | s.push_str(&decimal); | 531 | 1.82M | } | 532 | 1.86M | if let Some(exponent) = exponent_str { | 533 | 4.45k | s.push_str("e"); | 534 | 4.45k | s.push_str(&exponent); | 535 | 1.86M | } | 536 | 1.86M | let float = s.parse::<$float>().ok()?; | 537 | | // looks like the `*.wat` format considers infinite overflow to | 538 | | // be invalid. | 539 | 1.86M | if float.is_infinite() { | 540 | 16 | return None; | 541 | 1.86M | } | 542 | 1.86M | return Some(float.to_bits()); | 543 | 52.7k | } | 544 | 52.7k | | 545 | 52.7k | // Parsing hex floats is... hard! I don't really know what most of | 546 | 52.7k | // this below does. It was copied from Gecko's implementation in | 547 | 52.7k | // `WasmTextToBinary.cpp`. Would love comments on this if you have | 548 | 52.7k | // them! | 549 | 52.7k | let decimal = decimal.as_ref().map(|s| &**s).unwrap_or(""); | 550 | 52.7k | let negative = integral.starts_with('-'); | 551 | 52.7k | let integral = integral.trim_start_matches('-').trim_start_matches('0'); | 552 | 52.7k | | 553 | 52.7k | // Do a bunch of work up front to locate the first non-zero digit | 554 | 52.7k | // to determine the initial exponent. There's a number of | 555 | 52.7k | // adjustments depending on where the digit was found, but the | 556 | 52.7k | // general idea here is that I'm not really sure why things are | 557 | 52.7k | // calculated the way they are but it should match Gecko. | 558 | 52.7k | let decimal_no_leading = decimal.trim_start_matches('0'); | 559 | 52.7k | let decimal_iter = if integral.is_empty() { | 560 | 5.68k | decimal_no_leading.chars() | 561 | | } else { | 562 | 47.0k | decimal.chars() | 563 | | }; | 564 | 52.7k | let mut digits = integral.chars() | 565 | 52.7k | .map(|c| (to_hex(c) as $int, false)) | 566 | 52.7k | .chain(decimal_iter.map(|c| (to_hex(c) as $int, true))); | 567 | 52.7k | let lead_nonzero_digit = match digits.next() { | 568 | 49.7k | Some((c, _)) => c, | 569 | | // No digits? Must be `+0` or `-0`, being careful to handle the | 570 | | // sign encoding here. | 571 | 727 | None if negative => return Some(1 << (width - 1)), | 572 | 2.30k | None => return Some(0), | 573 | | }; | 574 | 49.7k | let mut significand = 0 as $int; | 575 | 49.7k | let mut exponent = if !integral.is_empty() { | 576 | 47.0k | 1 | 577 | | } else { | 578 | 2.64k | -((decimal.len() - decimal_no_leading.len() + 1) as i32) + 1 | 579 | | }; | 580 | 49.7k | let lz = (lead_nonzero_digit as u8).leading_zeros() as i32 - 4; | 581 | 49.7k | exponent = exponent.checked_mul(4)?.checked_sub(lz + 1)?; | 582 | 49.7k | let mut significand_pos = (width - (4 - (lz as usize))) as isize; | 583 | 49.7k | assert!(significand_pos >= 0); | 584 | 49.7k | significand |= lead_nonzero_digit << significand_pos; | 585 | 49.7k | | 586 | 49.7k | // Now that we've got an anchor in the string we parse the remaining | 587 | 49.7k | // digits. Again, not entirely sure why everything is the way it is | 588 | 49.7k | // here! This is copied frmo gecko. | 589 | 49.7k | let mut discarded_extra_nonzero = false; | 590 | 724k | for (digit, decimal) in digits { | 591 | 674k | if !decimal { | 592 | 397k | exponent += 4; | 593 | 277k | } | 594 | 674k | if significand_pos > -4 { | 595 | 218k | significand_pos -= 4; | 596 | 456k | } | 597 | | | 598 | 674k | if significand_pos >= 0 { | 599 | 208k | significand |= digit << significand_pos; | 600 | 466k | } else if significand_pos > -4 { | 601 | 1.86k | significand |= digit >> (4 - significand_pos); | 602 | 1.86k | discarded_extra_nonzero = (digit & !((!0) >> (4 - significand_pos))) != 0; | 603 | 464k | } else if digit != 0 { | 604 | 118k | discarded_extra_nonzero = true; | 605 | 346k | } | 606 | | } | 607 | | | 608 | 49.7k | exponent = exponent.checked_add(match exponent_str { | 609 | 7.99k | Some(s) => s.parse::<i32>().ok()?, | 610 | 41.7k | None => 0, | 611 | 0 | })?; | 612 | | debug_assert!(significand != 0); | 613 | | | 614 | 49.7k | let (encoded_exponent, encoded_significand, discarded_significand) = | 615 | 49.7k | if exponent <= -bias { | 616 | | // Underflow to subnormal or zero. | 617 | 1.47k | let shift = exp_offset as i32 + exponent + bias; | 618 | 1.47k | if shift == 0 { | 619 | 18 | (0, 0, significand) | 620 | 1.45k | } else if shift < 0 || shift >= width as i32 { | 621 | 94 | (0, 0, 0) | 622 | | } else { | 623 | 1.36k | ( | 624 | 1.36k | 0, | 625 | 1.36k | significand >> (width as i32 - shift), | 626 | 1.36k | significand << shift, | 627 | 1.36k | ) | 628 | | } | 629 | 48.2k | } else if exponent <= bias { | 630 | | // Normal (non-zero). The significand's leading 1 is encoded | 631 | | // implicitly. | 632 | 48.2k | ( | 633 | 48.2k | ((exponent + bias) as $int) << exp_offset, | 634 | 48.2k | (significand >> (width - exp_offset - 1)) & signif_mask, | 635 | 48.2k | significand << (exp_offset + 1), | 636 | 48.2k | ) | 637 | | } else { | 638 | | // Overflow to infinity. | 639 | 6 | ( | 640 | 6 | ((1 << $exp_bits) - 1) << exp_offset, | 641 | 6 | 0, | 642 | 6 | 0, | 643 | 6 | ) | 644 | | }; | 645 | | | 646 | 49.7k | let bits = encoded_exponent | encoded_significand; | 647 | 49.7k | | 648 | 49.7k | // Apply rounding. If this overflows the significand, it carries | 649 | 49.7k | // into the exponent bit according to the magic of the IEEE 754 | 650 | 49.7k | // encoding. | 651 | 49.7k | // | 652 | 49.7k | // Or rather, the comment above is what Gecko says so it's copied | 653 | 49.7k | // here too. | 654 | 49.7k | let msb = 1 << (width - 1); | 655 | 49.7k | let bits = bits | 656 | 49.7k | + (((discarded_significand & msb != 0) | 657 | 4.47k | && ((discarded_significand & !msb != 0) || | 658 | 31 | discarded_extra_nonzero || | 659 | | // ties to even | 660 | 27 | (encoded_significand & 1 != 0))) as $int); | 661 | | | 662 | | // Just before we return the bits be sure to handle the sign bit we | 663 | | // found at the beginning. | 664 | 49.7k | let bits = if negative { | 665 | 4.35k | bits | (1 << (width - 1)) | 666 | | } else { | 667 | 45.3k | bits | 668 | | }; | 669 | | // looks like the `*.wat` format considers infinite overflow to | 670 | | // be invalid. | 671 | 49.7k | if $float::from_bits(bits).is_infinite() { | 672 | 6 | return None; | 673 | 49.7k | } | 674 | 49.7k | Some(bits) | 675 | 1.92M | } |
|
676 | | |
677 | | )*) |
678 | | } |
679 | | |
680 | | float! { |
681 | | Float32 => { |
682 | | bits: u32, |
683 | | float: f32, |
684 | | exponent_bits: 8, |
685 | | name: strtof, |
686 | | } |
687 | | Float64 => { |
688 | | bits: u64, |
689 | | float: f64, |
690 | | exponent_bits: 11, |
691 | | name: strtod, |
692 | | } |
693 | | } |
694 | | |
695 | 954k | fn to_hex(c: char) -> u8 { |
696 | 954k | match c { |
697 | 160k | 'a'..='f' => c as u8 - b'a' + 10, |
698 | 54.4k | 'A'..='F' => c as u8 - b'A' + 10, |
699 | 740k | _ => c as u8 - b'0', |
700 | | } |
701 | 954k | } |
702 | | |
703 | | /// A convenience type to use with [`Parser::peek`](crate::parser::Parser::peek) |
704 | | /// to see if the next token is an s-expression. |
705 | | pub struct LParen { |
706 | | _priv: (), |
707 | | } |
708 | | |
709 | | impl Peek for LParen { |
710 | 1.05M | fn peek(cursor: Cursor<'_>) -> bool { |
711 | 1.05M | cursor.lparen().is_some() |
712 | 1.05M | } |
713 | | |
714 | 2.82k | fn display() -> &'static str { |
715 | 2.82k | "left paren" |
716 | 2.82k | } |
717 | | } |
718 | | |
719 | | #[cfg(test)] |
720 | | mod tests { |
721 | | #[test] |
722 | | fn hex_strtof() { |
723 | | macro_rules! f { |
724 | | ($a:tt) => (f!(@mk $a, None, None)); |
725 | | ($a:tt p $e:tt) => (f!(@mk $a, None, Some($e.into()))); |
726 | | ($a:tt . $b:tt) => (f!(@mk $a, Some($b.into()), None)); |
727 | | ($a:tt . $b:tt p $e:tt) => (f!(@mk $a, Some($b.into()), Some($e.into()))); |
728 | | (@mk $a:tt, $b:expr, $e:expr) => (crate::lexer::FloatVal::Val { |
729 | | hex: true, |
730 | | integral: $a.into(), |
731 | | decimal: $b, |
732 | | exponent: $e |
733 | | }); |
734 | | } |
735 | | assert_eq!(super::strtof(&f!("0")), Some(0)); |
736 | | assert_eq!(super::strtof(&f!("0" . "0")), Some(0)); |
737 | | assert_eq!(super::strtof(&f!("0" . "0" p "2354")), Some(0)); |
738 | | assert_eq!(super::strtof(&f!("-0")), Some(1 << 31)); |
739 | | assert_eq!(super::strtof(&f!("f32")), Some(0x45732000)); |
740 | | assert_eq!(super::strtof(&f!("0" . "f32")), Some(0x3f732000)); |
741 | | assert_eq!(super::strtof(&f!("1" . "2")), Some(0x3f900000)); |
742 | | assert_eq!( |
743 | | super::strtof(&f!("0" . "00000100000000000" p "-126")), |
744 | | Some(0) |
745 | | ); |
746 | | assert_eq!( |
747 | | super::strtof(&f!("1" . "fffff4" p "-106")), |
748 | | Some(0x0afffffa) |
749 | | ); |
750 | | assert_eq!(super::strtof(&f!("fffff98" p "-133")), Some(0x0afffffa)); |
751 | | assert_eq!(super::strtof(&f!("0" . "081" p "023")), Some(0x48810000)); |
752 | | assert_eq!( |
753 | | super::strtof(&f!("1" . "00000100000000000" p "-50")), |
754 | | Some(0x26800000) |
755 | | ); |
756 | | } |
757 | | } |