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