1use crate::core::*;
2use crate::kw;
3use crate::parser::{Lookahead1, Parse, Parser, Peek, Result};
4use crate::token::*;
5
6/// A defined WebAssembly memory instance inside of a module.
7#[derive(Debug)]
8pub struct Memory<'a> {
9 /// Where this `memory` was defined
10 pub span: Span,
11 /// An optional name to refer to this memory 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 memory is defined in the module.
19 pub kind: MemoryKind<'a>,
20}
21
22/// Different syntactical ways a memory can be defined in a module.
23#[derive(Debug)]
24pub enum MemoryKind<'a> {
25 /// This memory is actually an inlined import definition.
26 #[allow(missing_docs)]
27 Import {
28 import: InlineImport<'a>,
29 ty: MemoryType,
30 },
31
32 /// A typical memory definition which simply says the limits of the memory
33 Normal(MemoryType),
34
35 /// The data of this memory, starting from 0, explicitly listed
36 Inline {
37 /// Whether or not this will be creating a 64-bit memory
38 is64: bool,
39 /// The inline data specified for this memory
40 data: Vec<DataVal<'a>>,
41 /// Optional page size for this inline memory.
42 page_size_log2: Option<u32>,
43 },
44}
45
46impl<'a> Parse<'a> for Memory<'a> {
47 fn parse(parser: Parser<'a>) -> Result<Self> {
48 let span = parser.parse::<kw::memory>()?.0;
49 let id = parser.parse()?;
50 let name = parser.parse()?;
51 let exports = parser.parse()?;
52
53 // Afterwards figure out which style this is, either:
54 //
55 // * `(import "a" "b") limits`
56 // * `(data ...)`
57 // * `limits`
58 let mut l = parser.lookahead1();
59 let kind = if let Some(import) = parser.parse()? {
60 MemoryKind::Import {
61 import,
62 ty: parser.parse()?,
63 }
64 } else if l.peek::<LParen>()?
65 || ((parser.peek::<kw::i32>()? || parser.peek::<kw::i64>()?)
66 && parser.peek2::<LParen>()?)
67 {
68 let is64 = if parser.parse::<Option<kw::i32>>()?.is_some() {
69 false
70 } else {
71 parser.parse::<Option<kw::i64>>()?.is_some()
72 };
73 let page_size_log2 = page_size(parser)?;
74 let data = parser.parens(|parser| {
75 parser.parse::<kw::data>()?;
76 let mut data = Vec::new();
77 while !parser.is_empty() {
78 data.push(parser.parse()?);
79 }
80 Ok(data)
81 })?;
82 MemoryKind::Inline {
83 data,
84 is64,
85 page_size_log2,
86 }
87 } else if l.peek::<u32>()? || l.peek::<kw::i32>()? || l.peek::<kw::i64>()? {
88 MemoryKind::Normal(parser.parse()?)
89 } else {
90 return Err(l.error());
91 };
92 Ok(Memory {
93 span,
94 id,
95 name,
96 exports,
97 kind,
98 })
99 }
100}
101
102/// A `data` directive in a WebAssembly module.
103#[derive(Debug)]
104pub struct Data<'a> {
105 /// Where this `data` was defined
106 pub span: Span,
107
108 /// The optional name of this data segment
109 pub id: Option<Id<'a>>,
110
111 /// An optional name for this data stored in the custom `name` section.
112 pub name: Option<NameAnnotation<'a>>,
113
114 /// Whether this data segment is passive or active
115 pub kind: DataKind<'a>,
116
117 /// Bytes for this `Data` segment, viewed as the concatenation of all the
118 /// contained slices.
119 pub data: Vec<DataVal<'a>>,
120}
121
122/// Different kinds of data segments, either passive or active.
123#[derive(Debug)]
124pub enum DataKind<'a> {
125 /// A passive data segment which isn't associated with a memory and is
126 /// referenced from various instructions.
127 Passive,
128
129 /// An active data segment which is associated and loaded into a particular
130 /// memory on module instantiation.
131 Active {
132 /// The memory that this `Data` will be associated with.
133 memory: Index<'a>,
134
135 /// Initial offset to load this data segment at
136 offset: Expression<'a>,
137 },
138}
139
140impl<'a> Parse<'a> for Data<'a> {
141 fn parse(parser: Parser<'a>) -> Result<Self> {
142 let span = parser.parse::<kw::data>()?.0;
143 let id = parser.parse()?;
144 let name = parser.parse()?;
145
146 let kind = if parser.peek::<&[u8]>()? || parser.peek::<RParen>()? {
147 DataKind::Passive
148
149 // ... and otherwise we must be attached to a particular memory as well
150 // as having an initialization offset.
151 } else {
152 let memory = if parser.peek::<u32>()? {
153 // FIXME: this is only here to accomodate
154 // proposals/threads/imports.wast at this current moment in
155 // time, this probably should get removed when the threads
156 // proposal is rebased on the current spec.
157 Index::Num(parser.parse()?, span)
158 } else if parser.peek2::<kw::memory>()? {
159 parser.parens(|p| {
160 p.parse::<kw::memory>()?;
161 p.parse()
162 })?
163 } else {
164 Index::Num(0, span)
165 };
166 let offset = parser.parens(|parser| {
167 if parser.peek::<kw::offset>()? {
168 parser.parse::<kw::offset>()?;
169 parser.parse()
170 } else {
171 // This is all that the spec allows, which is that if
172 // `offset` isn't present then this is "sugar" for a
173 // single-instruction expression.
174 let insn = parser.parse()?;
175 if parser.is_empty() {
176 return Ok(Expression::one(insn));
177 }
178
179 // This is support for what is currently invalid syntax
180 // according to the strict specification but is otherwise
181 // present in the spec test suite:
182 //
183 // (data (i32.add (i32.const 0) (i32.const 0)))
184 //
185 // Technically the spec says this should be:
186 //
187 // (data (offset ...))
188 //
189 // but alas
190 let mut expr: Expression = parser.parse()?;
191 let mut instrs = Vec::from(expr.instrs);
192 instrs.push(insn);
193 expr.instrs = instrs.into();
194 Ok(expr)
195 }
196 })?;
197 DataKind::Active { memory, offset }
198 };
199
200 let mut data = Vec::new();
201 while !parser.is_empty() {
202 data.push(parser.parse()?);
203 }
204 Ok(Data {
205 span,
206 id,
207 name,
208 kind,
209 data,
210 })
211 }
212}
213
214/// Differnet ways the value of a data segment can be defined.
215#[derive(Debug)]
216#[allow(missing_docs)]
217pub enum DataVal<'a> {
218 String(&'a [u8]),
219 Integral(Vec<u8>),
220}
221
222impl DataVal<'_> {
223 /// Returns the length, in bytes, of the memory used to represent this data
224 /// value.
225 pub fn len(&self) -> usize {
226 match self {
227 DataVal::String(s: &&[u8]) => s.len(),
228 DataVal::Integral(s: &Vec) => s.len(),
229 }
230 }
231
232 /// Pushes the value of this data value onto the provided list of bytes.
233 pub fn push_onto(&self, dst: &mut Vec<u8>) {
234 match self {
235 DataVal::String(s: &&[u8]) => dst.extend_from_slice(s),
236 DataVal::Integral(s: &Vec) => dst.extend_from_slice(s),
237 }
238 }
239}
240
241impl<'a> Parse<'a> for DataVal<'a> {
242 fn parse(parser: Parser<'a>) -> Result<Self> {
243 if !parser.peek::<LParen>()? {
244 return Ok(DataVal::String(parser.parse()?));
245 }
246
247 return parser.parens(|p| {
248 let mut result = Vec::new();
249 let mut lookahead = p.lookahead1();
250 let l = &mut lookahead;
251 let r = &mut result;
252 if consume::<kw::i8, i8, _>(p, l, r, |u, v| v.push(u as u8))?
253 || consume::<kw::i16, i16, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
254 || consume::<kw::i32, i32, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
255 || consume::<kw::i64, i64, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
256 || consume::<kw::f32, F32, _>(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))?
257 || consume::<kw::f64, F64, _>(p, l, r, |u, v| v.extend(&u.bits.to_le_bytes()))?
258 || consume::<kw::v128, V128Const, _>(p, l, r, |u, v| v.extend(&u.to_le_bytes()))?
259 {
260 Ok(DataVal::Integral(result))
261 } else {
262 Err(lookahead.error())
263 }
264 });
265
266 fn consume<'a, T: Peek + Parse<'a>, U: Parse<'a>, F>(
267 parser: Parser<'a>,
268 lookahead: &mut Lookahead1<'a>,
269 dst: &mut Vec<u8>,
270 push: F,
271 ) -> Result<bool>
272 where
273 F: Fn(U, &mut Vec<u8>),
274 {
275 if !lookahead.peek::<T>()? {
276 return Ok(false);
277 }
278 parser.parse::<T>()?;
279 while !parser.is_empty() {
280 let val = parser.parse::<U>()?;
281 push(val, dst);
282 }
283 Ok(true)
284 }
285 }
286}
287