| 1 | use crate::core::*; |
| 2 | use crate::kw; |
| 3 | use crate::parser::{Lookahead1, Parse, Parser, Peek, Result}; |
| 4 | use crate::token::*; |
| 5 | |
| 6 | /// A defined WebAssembly memory instance inside of a module. |
| 7 | #[derive (Debug)] |
| 8 | pub 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)] |
| 24 | pub 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 | |
| 46 | impl<'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)] |
| 104 | pub 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)] |
| 124 | pub 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 | |
| 140 | impl<'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)] |
| 217 | pub enum DataVal<'a> { |
| 218 | String(&'a [u8]), |
| 219 | Integral(Vec<u8>), |
| 220 | } |
| 221 | |
| 222 | impl 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 | |
| 241 | impl<'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 | |