Coverage Report

Created: 2024-09-10 12:50

/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
}