| 1 | use crate::core::*; |
| 2 | use crate::kw; |
| 3 | use crate::parser::{Parse, Parser, Result}; |
| 4 | use crate::token::{Id, NameAnnotation, Span}; |
| 5 | |
| 6 | /// A WebAssembly function to be inserted into a module. |
| 7 | /// |
| 8 | /// This is a member of both the function and code sections. |
| 9 | #[derive (Debug)] |
| 10 | pub struct Func<'a> { |
| 11 | /// Where this `func` was defined. |
| 12 | pub span: Span, |
| 13 | /// An identifier that this function is resolved with (optionally) for name |
| 14 | /// resolution. |
| 15 | pub id: Option<Id<'a>>, |
| 16 | /// An optional name for this function stored in the custom `name` section. |
| 17 | pub name: Option<NameAnnotation<'a>>, |
| 18 | /// If present, inline export annotations which indicate names this |
| 19 | /// definition should be exported under. |
| 20 | pub exports: InlineExport<'a>, |
| 21 | /// What kind of function this is, be it an inline-defined or imported |
| 22 | /// function. |
| 23 | pub kind: FuncKind<'a>, |
| 24 | /// The type that this function will have. |
| 25 | pub ty: TypeUse<'a, FunctionType<'a>>, |
| 26 | } |
| 27 | |
| 28 | /// Possible ways to define a function in the text format. |
| 29 | #[derive (Debug)] |
| 30 | pub enum FuncKind<'a> { |
| 31 | /// A function which is actually defined as an import, such as: |
| 32 | /// |
| 33 | /// ```text |
| 34 | /// (func (type 3) (import "foo" "bar")) |
| 35 | /// ``` |
| 36 | Import(InlineImport<'a>), |
| 37 | |
| 38 | /// Almost all functions, those defined inline in a wasm module. |
| 39 | Inline { |
| 40 | /// The list of locals, if any, for this function. |
| 41 | locals: Box<[Local<'a>]>, |
| 42 | |
| 43 | /// The instructions of the function. |
| 44 | expression: Expression<'a>, |
| 45 | }, |
| 46 | } |
| 47 | |
| 48 | impl<'a> Parse<'a> for Func<'a> { |
| 49 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 50 | let span = parser.parse::<kw::func>()?.0; |
| 51 | let id = parser.parse()?; |
| 52 | let name = parser.parse()?; |
| 53 | let exports = parser.parse()?; |
| 54 | |
| 55 | let (ty, kind) = if let Some(import) = parser.parse()? { |
| 56 | (parser.parse()?, FuncKind::Import(import)) |
| 57 | } else { |
| 58 | let ty = parser.parse()?; |
| 59 | let locals = Local::parse_remainder(parser)?.into(); |
| 60 | ( |
| 61 | ty, |
| 62 | FuncKind::Inline { |
| 63 | locals, |
| 64 | expression: parser.parse()?, |
| 65 | }, |
| 66 | ) |
| 67 | }; |
| 68 | |
| 69 | Ok(Func { |
| 70 | span, |
| 71 | id, |
| 72 | name, |
| 73 | exports, |
| 74 | ty, |
| 75 | kind, |
| 76 | }) |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /// A local for a `func` or `let` instruction. |
| 81 | /// |
| 82 | /// Each local has an optional identifier for name resolution, an optional name |
| 83 | /// for the custom `name` section, and a value type. |
| 84 | #[derive (Debug, Clone)] |
| 85 | pub struct Local<'a> { |
| 86 | /// An identifier that this local is resolved with (optionally) for name |
| 87 | /// resolution. |
| 88 | pub id: Option<Id<'a>>, |
| 89 | /// An optional name for this local stored in the custom `name` section. |
| 90 | pub name: Option<NameAnnotation<'a>>, |
| 91 | /// The value type of this local. |
| 92 | pub ty: ValType<'a>, |
| 93 | } |
| 94 | |
| 95 | /// Parser for `local` instruction. |
| 96 | /// |
| 97 | /// A single `local` instruction can generate multiple locals, hence this parser |
| 98 | pub struct LocalParser<'a> { |
| 99 | /// All the locals associated with this `local` instruction. |
| 100 | pub locals: Vec<Local<'a>>, |
| 101 | } |
| 102 | |
| 103 | impl<'a> Parse<'a> for LocalParser<'a> { |
| 104 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 105 | let mut locals: Vec> = Vec::new(); |
| 106 | parser.parse::<kw::local>()?; |
| 107 | if !parser.is_empty() { |
| 108 | let id: Option<_> = parser.parse()?; |
| 109 | let name: Option<_> = parser.parse()?; |
| 110 | let ty: ValType<'_> = parser.parse()?; |
| 111 | let parse_more: bool = id.is_none() && name.is_none(); |
| 112 | locals.push(Local { id, name, ty }); |
| 113 | while parse_more && !parser.is_empty() { |
| 114 | locals.push(Local { |
| 115 | id: None, |
| 116 | name: None, |
| 117 | ty: parser.parse()?, |
| 118 | }); |
| 119 | } |
| 120 | } |
| 121 | Ok(LocalParser { locals }) |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | impl<'a> Local<'a> { |
| 126 | pub(crate) fn parse_remainder(parser: Parser<'a>) -> Result<Vec<Local<'a>>> { |
| 127 | let mut locals: Vec> = Vec::new(); |
| 128 | while parser.peek2::<kw::local>()? { |
| 129 | parser.parens(|p: Parser<'a>| { |
| 130 | locals.extend(iter:p.parse::<LocalParser>()?.locals); |
| 131 | Ok(()) |
| 132 | })?; |
| 133 | } |
| 134 | Ok(locals) |
| 135 | } |
| 136 | } |
| 137 | |