/build/cargo-vendor-dir/wast-200.0.0/src/core/table.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::core::*; |
2 | | use crate::kw; |
3 | | use crate::parser::{Parse, Parser, Peek, Result}; |
4 | | use crate::token::{Id, Index, LParen, NameAnnotation, Span}; |
5 | | |
6 | | /// A WebAssembly `table` directive in a module. |
7 | | #[derive(Debug)] |
8 | | pub struct Table<'a> { |
9 | | /// Where this table was defined. |
10 | | pub span: Span, |
11 | | /// An optional name to refer to this table by. |
12 | | pub id: Option<Id<'a>>, |
13 | | /// An optional name for this function stored in the custom `name` section. |
14 | | pub name: Option<NameAnnotation<'a>>, |
15 | | /// If present, inline export annotations which indicate names this |
16 | | /// definition should be exported under. |
17 | | pub exports: InlineExport<'a>, |
18 | | /// How this table is textually defined in the module. |
19 | | pub kind: TableKind<'a>, |
20 | | } |
21 | | |
22 | | /// Different ways to textually define a table. |
23 | | #[derive(Debug)] |
24 | | pub enum TableKind<'a> { |
25 | | /// This table is actually an inlined import definition. |
26 | | #[allow(missing_docs)] |
27 | | Import { |
28 | | import: InlineImport<'a>, |
29 | | ty: TableType<'a>, |
30 | | }, |
31 | | |
32 | | /// A typical memory definition which simply says the limits of the table |
33 | | Normal { |
34 | | /// Table type. |
35 | | ty: TableType<'a>, |
36 | | /// Optional items initializer expression. |
37 | | init_expr: Option<Expression<'a>>, |
38 | | }, |
39 | | |
40 | | /// The elem segments of this table, starting from 0, explicitly listed |
41 | | Inline { |
42 | | /// The element type of this table. |
43 | | elem: RefType<'a>, |
44 | | /// The element table entries to have, and the length of this list is |
45 | | /// the limits of the table as well. |
46 | | payload: ElemPayload<'a>, |
47 | | }, |
48 | | } |
49 | | |
50 | | impl<'a> Parse<'a> for Table<'a> { |
51 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
52 | 0 | let span = parser.parse::<kw::table>()?.0; |
53 | 0 | let id = parser.parse()?; |
54 | 0 | let name = parser.parse()?; |
55 | 0 | let exports = parser.parse()?; |
56 | | |
57 | | // Afterwards figure out which style this is, either: |
58 | | // |
59 | | // * `elemtype (elem ...)` |
60 | | // * `(import "a" "b") limits` |
61 | | // * `limits` |
62 | 0 | let mut l = parser.lookahead1(); |
63 | 0 | let kind = if l.peek::<RefType>()? { |
64 | 0 | let elem = parser.parse()?; |
65 | 0 | let payload = parser.parens(|p| { |
66 | 0 | p.parse::<kw::elem>()?; |
67 | 0 | if p.peek::<LParen>()? { |
68 | 0 | ElemPayload::parse_exprs(p, elem) |
69 | | } else { |
70 | 0 | ElemPayload::parse_indices(p, Some(elem)) |
71 | | } |
72 | 0 | })?; |
73 | 0 | TableKind::Inline { elem, payload } |
74 | 0 | } else if l.peek::<u32>()? { |
75 | | TableKind::Normal { |
76 | 0 | ty: parser.parse()?, |
77 | 0 | init_expr: if !parser.is_empty() { |
78 | 0 | Some(parser.parse::<Expression>()?) |
79 | | } else { |
80 | 0 | None |
81 | | }, |
82 | | } |
83 | 0 | } else if let Some(import) = parser.parse()? { |
84 | | TableKind::Import { |
85 | 0 | import, |
86 | 0 | ty: parser.parse()?, |
87 | | } |
88 | | } else { |
89 | 0 | return Err(l.error()); |
90 | | }; |
91 | 0 | Ok(Table { |
92 | 0 | span, |
93 | 0 | id, |
94 | 0 | name, |
95 | 0 | exports, |
96 | 0 | kind, |
97 | 0 | }) |
98 | 0 | } |
99 | | } |
100 | | |
101 | | /// An `elem` segment in a WebAssembly module. |
102 | | #[derive(Debug)] |
103 | | pub struct Elem<'a> { |
104 | | /// Where this `elem` was defined. |
105 | | pub span: Span, |
106 | | /// An optional name by which to refer to this segment. |
107 | | pub id: Option<Id<'a>>, |
108 | | /// An optional name for this element stored in the custom `name` section. |
109 | | pub name: Option<NameAnnotation<'a>>, |
110 | | /// The way this segment was defined in the module. |
111 | | pub kind: ElemKind<'a>, |
112 | | /// The payload of this element segment, typically a list of functions. |
113 | | pub payload: ElemPayload<'a>, |
114 | | } |
115 | | |
116 | | /// Different ways to define an element segment in an mdoule. |
117 | | #[derive(Debug)] |
118 | | pub enum ElemKind<'a> { |
119 | | /// A passive segment that isn't associated with a table and can be used in |
120 | | /// various bulk-memory instructions. |
121 | | Passive, |
122 | | |
123 | | /// A declared element segment that is purely used to declare function |
124 | | /// references. |
125 | | Declared, |
126 | | |
127 | | /// An active segment associated with a table. |
128 | | Active { |
129 | | /// The table this `elem` is initializing. |
130 | | table: Index<'a>, |
131 | | /// The offset within `table` that we'll initialize at. |
132 | | offset: Expression<'a>, |
133 | | }, |
134 | | } |
135 | | |
136 | | /// Different ways to define the element segment payload in a module. |
137 | | #[derive(Debug)] |
138 | | pub enum ElemPayload<'a> { |
139 | | /// This element segment has a contiguous list of function indices |
140 | | Indices(Vec<Index<'a>>), |
141 | | |
142 | | /// This element segment has a list of optional function indices, |
143 | | /// represented as expressions using `ref.func` and `ref.null`. |
144 | | Exprs { |
145 | | /// The desired type of each expression below. |
146 | | ty: RefType<'a>, |
147 | | /// The expressions in this segment. |
148 | | exprs: Vec<Expression<'a>>, |
149 | | }, |
150 | | } |
151 | | |
152 | | impl<'a> Parse<'a> for Elem<'a> { |
153 | 0 | fn parse(parser: Parser<'a>) -> Result<Self> { |
154 | 0 | let span = parser.parse::<kw::elem>()?.0; |
155 | 0 | let id = parser.parse()?; |
156 | 0 | let name = parser.parse()?; |
157 | | |
158 | | // Element segments can start in a number of different ways: |
159 | | // |
160 | | // * `(elem ...` |
161 | | // * `(elem declare ...` |
162 | | // * `(elem (table ...` |
163 | | // * `(elem (offset ...` |
164 | | // * `(elem (<instr> ...` (omitted `offset`) |
165 | 0 | let mut table_omitted = false; |
166 | 0 | let kind = if parser.peek::<kw::declare>()? { |
167 | 0 | parser.parse::<kw::declare>()?; |
168 | 0 | ElemKind::Declared |
169 | 0 | } else if parser.peek::<u32>()? |
170 | 0 | || (parser.peek::<LParen>()? && !parser.peek::<RefType>()?) |
171 | | { |
172 | 0 | let table = if parser.peek::<u32>()? { |
173 | | // FIXME: this is only here to accomodate |
174 | | // proposals/threads/imports.wast at this current moment in |
175 | | // time, this probably should get removed when the threads |
176 | | // proposal is rebased on the current spec. |
177 | 0 | table_omitted = true; |
178 | 0 | Index::Num(parser.parse()?, span) |
179 | 0 | } else if parser.peek2::<kw::table>()? { |
180 | 0 | parser.parens(|p| { |
181 | 0 | p.parse::<kw::table>()?; |
182 | 0 | p.parse() |
183 | 0 | })? |
184 | | } else { |
185 | 0 | table_omitted = true; |
186 | 0 | Index::Num(0, span) |
187 | | }; |
188 | | |
189 | 0 | let offset = parse_expr_or_single_instr::<kw::offset>(parser)?; |
190 | 0 | ElemKind::Active { table, offset } |
191 | | } else { |
192 | 0 | ElemKind::Passive |
193 | | }; |
194 | | |
195 | | // Element segments can have a number of ways to specify their element |
196 | | // lists: |
197 | | // |
198 | | // * `func 0 1 ...` - list of indices |
199 | | // * `<reftype> (ref.null func) ...` - list of expressions |
200 | | // * `0 1 ...` - list of indices, only if the table was omitted for the |
201 | | // legacy way tables were printed. |
202 | 0 | let indices = if parser.peek::<kw::func>()? { |
203 | 0 | parser.parse::<kw::func>()?; |
204 | 0 | true |
205 | 0 | } else if parser.peek::<RefType>()? { |
206 | 0 | false |
207 | 0 | } else if table_omitted { |
208 | 0 | true |
209 | | } else { |
210 | 0 | false // this will fall through to failing to parse a `RefType` |
211 | | }; |
212 | 0 | let payload = if indices { |
213 | 0 | ElemPayload::parse_indices(parser, None)? |
214 | | } else { |
215 | 0 | let ty = parser.parse()?; |
216 | 0 | ElemPayload::parse_exprs(parser, ty)? |
217 | | }; |
218 | | |
219 | 0 | Ok(Elem { |
220 | 0 | span, |
221 | 0 | id, |
222 | 0 | name, |
223 | 0 | kind, |
224 | 0 | payload, |
225 | 0 | }) |
226 | 0 | } |
227 | | } |
228 | | |
229 | | impl<'a> ElemPayload<'a> { |
230 | 0 | fn parse_indices(parser: Parser<'a>, ty: Option<RefType<'a>>) -> Result<Self> { |
231 | 0 | let mut ret = match ty { |
232 | | // If there is no requested type, then it's ok to parse a list of |
233 | | // indices. |
234 | 0 | None => ElemPayload::Indices(Vec::new()), |
235 | | |
236 | | // If the requested type is a `funcref` type then a list of indices |
237 | | // can be parsed. This is because the list-of-indices encoding in |
238 | | // the binary format can only accomodate the `funcref` type. |
239 | 0 | Some(ty) if ty == RefType::func() => ElemPayload::Indices(Vec::new()), |
240 | | |
241 | | // Otherwise silently translate this list-of-indices into a |
242 | | // list-of-expressions because that's the only way to accomodate a |
243 | | // non-funcref type. |
244 | 0 | Some(ty) => ElemPayload::Exprs { |
245 | 0 | ty, |
246 | 0 | exprs: Vec::new(), |
247 | 0 | }, |
248 | | }; |
249 | 0 | while !parser.is_empty() { |
250 | 0 | let func = parser.parse()?; |
251 | 0 | match &mut ret { |
252 | 0 | ElemPayload::Indices(list) => list.push(func), |
253 | 0 | ElemPayload::Exprs { exprs, .. } => { |
254 | 0 | let expr = Expression { |
255 | 0 | instrs: [Instruction::RefFunc(func)].into(), |
256 | 0 | branch_hints: Vec::new(), |
257 | 0 | }; |
258 | 0 | exprs.push(expr); |
259 | 0 | } |
260 | | } |
261 | | } |
262 | 0 | Ok(ret) |
263 | 0 | } |
264 | | |
265 | 0 | fn parse_exprs(parser: Parser<'a>, ty: RefType<'a>) -> Result<Self> { |
266 | 0 | let mut exprs = Vec::new(); |
267 | 0 | while !parser.is_empty() { |
268 | 0 | let expr = parse_expr_or_single_instr::<kw::item>(parser)?; |
269 | 0 | exprs.push(expr); |
270 | | } |
271 | 0 | Ok(ElemPayload::Exprs { exprs, ty }) |
272 | 0 | } |
273 | | } |
274 | | |
275 | | // Parses either `(T expr)` or `(instr)`, returning the resulting expression. |
276 | 0 | fn parse_expr_or_single_instr<'a, T>(parser: Parser<'a>) -> Result<Expression<'a>> |
277 | 0 | where |
278 | 0 | T: Parse<'a> + Peek, |
279 | 0 | { |
280 | 0 | if parser.peek2::<T>()? { |
281 | 0 | parser.parens(|parser| { |
282 | 0 | parser.parse::<T>()?; |
283 | 0 | parser.parse() |
284 | 0 | }) |
285 | | } else { |
286 | | // Without `T` this is "sugar" for a single instruction (still possibly folded). |
287 | 0 | Ok(Expression::parse_folded_instruction(parser)?) |
288 | | } |
289 | 0 | } |