use crate::core::*; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; use std::mem; /// The value types for a wasm module. #[allow(missing_docs)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum ValType<'a> { I32, I64, F32, F64, V128, Ref(RefType<'a>), } impl<'a> Parse<'a> for ValType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? { parser.parse::()?; Ok(ValType::I32) } else if l.peek::()? { parser.parse::()?; Ok(ValType::I64) } else if l.peek::()? { parser.parse::()?; Ok(ValType::F32) } else if l.peek::()? { parser.parse::()?; Ok(ValType::F64) } else if l.peek::()? { parser.parse::()?; Ok(ValType::V128) } else if l.peek::()? { Ok(ValType::Ref(parser.parse()?)) } else { Err(l.error()) } } } impl<'a> Peek for ValType<'a> { fn peek(cursor: Cursor<'_>) -> Result { Ok(kw::i32::peek(cursor)? || kw::i64::peek(cursor)? || kw::f32::peek(cursor)? || kw::f64::peek(cursor)? || kw::v128::peek(cursor)? || RefType::peek(cursor)?) } fn display() -> &'static str { "valtype" } } /// A heap type for a reference type #[allow(missing_docs)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum HeapType<'a> { /// An untyped function reference: funcref. This is part of the reference /// types proposal. Func, /// A reference to any host value: externref. This is part of the reference /// types proposal. Extern, /// A reference to a wasm exception. This is part of the exceptions proposal. Exn, /// A reference to any reference value: anyref. This is part of the GC /// proposal. Any, /// A reference that has an identity that can be compared: eqref. This is /// part of the GC proposal. Eq, /// A reference to a GC struct. This is part of the GC proposal. Struct, /// A reference to a GC array. This is part of the GC proposal. Array, /// An unboxed 31-bit integer: i31ref. Part of the GC proposal. I31, /// The bottom type of the funcref hierarchy. Part of the GC proposal. NoFunc, /// The bottom type of the externref hierarchy. Part of the GC proposal. NoExtern, /// The bottom type of the anyref hierarchy. Part of the GC proposal. None, /// A reference to a concrete function, struct, or array type defined by /// Wasm: `ref T`. This is part of the function references and GC proposals. Concrete(Index<'a>), } impl<'a> Parse<'a> for HeapType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? { parser.parse::()?; Ok(HeapType::Func) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Extern) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Exn) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Any) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Eq) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Struct) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::Array) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::I31) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::NoFunc) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::NoExtern) } else if l.peek::()? { parser.parse::()?; Ok(HeapType::None) } else if l.peek::()? { Ok(HeapType::Concrete(parser.parse()?)) } else { Err(l.error()) } } } impl<'a> Peek for HeapType<'a> { fn peek(cursor: Cursor<'_>) -> Result { Ok(kw::func::peek(cursor)? || kw::r#extern::peek(cursor)? || kw::exn::peek(cursor)? || kw::any::peek(cursor)? || kw::eq::peek(cursor)? || kw::r#struct::peek(cursor)? || kw::array::peek(cursor)? || kw::i31::peek(cursor)? || kw::nofunc::peek(cursor)? || kw::noextern::peek(cursor)? || kw::none::peek(cursor)? || (LParen::peek(cursor)? && kw::r#type::peek2(cursor)?)) } fn display() -> &'static str { "heaptype" } } /// A reference type in a wasm module. #[allow(missing_docs)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct RefType<'a> { pub nullable: bool, pub heap: HeapType<'a>, } impl<'a> RefType<'a> { /// A `funcref` as an abbreviation for `(ref null func)`. pub fn func() -> Self { RefType { nullable: true, heap: HeapType::Func, } } /// An `externref` as an abbreviation for `(ref null extern)`. pub fn r#extern() -> Self { RefType { nullable: true, heap: HeapType::Extern, } } /// An `exnrefr` as an abbreviation for `(ref null exn)`. pub fn exn() -> Self { RefType { nullable: true, heap: HeapType::Exn, } } /// An `anyref` as an abbreviation for `(ref null any)`. pub fn any() -> Self { RefType { nullable: true, heap: HeapType::Any, } } /// An `eqref` as an abbreviation for `(ref null eq)`. pub fn eq() -> Self { RefType { nullable: true, heap: HeapType::Eq, } } /// An `structref` as an abbreviation for `(ref null struct)`. pub fn r#struct() -> Self { RefType { nullable: true, heap: HeapType::Struct, } } /// An `arrayref` as an abbreviation for `(ref null array)`. pub fn array() -> Self { RefType { nullable: true, heap: HeapType::Array, } } /// An `i31ref` as an abbreviation for `(ref null i31)`. pub fn i31() -> Self { RefType { nullable: true, heap: HeapType::I31, } } /// A `nullfuncref` as an abbreviation for `(ref null nofunc)`. pub fn nullfuncref() -> Self { RefType { nullable: true, heap: HeapType::NoFunc, } } /// A `nullexternref` as an abbreviation for `(ref null noextern)`. pub fn nullexternref() -> Self { RefType { nullable: true, heap: HeapType::NoExtern, } } /// A `nullref` as an abbreviation for `(ref null none)`. pub fn nullref() -> Self { RefType { nullable: true, heap: HeapType::None, } } } impl<'a> Parse<'a> for RefType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? { parser.parse::()?; Ok(RefType::func()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::r#extern()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::exn()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::any()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::eq()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::r#struct()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::array()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::i31()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::nullfuncref()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::nullexternref()) } else if l.peek::()? { parser.parse::()?; Ok(RefType::nullref()) } else if l.peek::()? { parser.parens(|p| { let mut l = parser.lookahead1(); if l.peek::()? { p.parse::()?; let mut nullable = false; if parser.peek::()? { parser.parse::()?; nullable = true; } Ok(RefType { nullable, heap: parser.parse()?, }) } else { Err(l.error()) } }) } else { Err(l.error()) } } } impl<'a> Peek for RefType<'a> { fn peek(cursor: Cursor<'_>) -> Result { Ok(kw::funcref::peek(cursor)? || kw::externref::peek(cursor)? || kw::exnref::peek(cursor)? || kw::anyref::peek(cursor)? || kw::eqref::peek(cursor)? || kw::structref::peek(cursor)? || kw::arrayref::peek(cursor)? || kw::i31ref::peek(cursor)? || kw::nullfuncref::peek(cursor)? || kw::nullexternref::peek(cursor)? || kw::nullref::peek(cursor)? || (LParen::peek(cursor)? && kw::r#ref::peek2(cursor)?)) } fn display() -> &'static str { "reftype" } } /// The types of values that may be used in a struct or array. #[allow(missing_docs)] #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum StorageType<'a> { I8, I16, Val(ValType<'a>), } impl<'a> Parse<'a> for StorageType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? { parser.parse::()?; Ok(StorageType::I8) } else if l.peek::()? { parser.parse::()?; Ok(StorageType::I16) } else if l.peek::()? { Ok(StorageType::Val(parser.parse()?)) } else { Err(l.error()) } } } /// Type for a `global` in a wasm module #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct GlobalType<'a> { /// The element type of this `global` pub ty: ValType<'a>, /// Whether or not the global is mutable or not. pub mutable: bool, } impl<'a> Parse<'a> for GlobalType<'a> { fn parse(parser: Parser<'a>) -> Result { if parser.peek2::()? { parser.parens(|p| { p.parse::()?; Ok(GlobalType { ty: parser.parse()?, mutable: true, }) }) } else { Ok(GlobalType { ty: parser.parse()?, mutable: false, }) } } } /// Min/max limits used for tables/memories. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Limits { /// The minimum number of units for this type. pub min: u32, /// An optional maximum number of units for this type. pub max: Option, } impl<'a> Parse<'a> for Limits { fn parse(parser: Parser<'a>) -> Result { let min = parser.parse()?; let max = if parser.peek::()? { Some(parser.parse()?) } else { None }; Ok(Limits { min, max }) } } /// Min/max limits used for 64-bit memories #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Limits64 { /// The minimum number of units for this type. pub min: u64, /// An optional maximum number of units for this type. pub max: Option, } impl<'a> Parse<'a> for Limits64 { fn parse(parser: Parser<'a>) -> Result { let min = parser.parse()?; let max = if parser.peek::()? { Some(parser.parse()?) } else { None }; Ok(Limits64 { min, max }) } } /// Configuration for a table of a wasm mdoule #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct TableType<'a> { /// Limits on the element sizes of this table pub limits: Limits, /// The type of element stored in this table pub elem: RefType<'a>, } impl<'a> Parse<'a> for TableType<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(TableType { limits: parser.parse()?, elem: parser.parse()?, }) } } /// Configuration for a memory of a wasm module #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum MemoryType { /// A 32-bit memory B32 { /// Limits on the page sizes of this memory limits: Limits, /// Whether or not this is a shared (atomic) memory type shared: bool, }, /// A 64-bit memory B64 { /// Limits on the page sizes of this memory limits: Limits64, /// Whether or not this is a shared (atomic) memory type shared: bool, }, } impl<'a> Parse<'a> for MemoryType { fn parse(parser: Parser<'a>) -> Result { if parser.peek::()? { parser.parse::()?; let limits = parser.parse()?; let shared = parser.parse::>()?.is_some(); Ok(MemoryType::B64 { limits, shared }) } else { parser.parse::>()?; let limits = parser.parse()?; let shared = parser.parse::>()?.is_some(); Ok(MemoryType::B32 { limits, shared }) } } } /// A function type with parameters and results. #[derive(Clone, Debug, Default)] pub struct FunctionType<'a> { /// The parameters of a function, optionally each having an identifier for /// name resolution and a name for the custom `name` section. pub params: Box<[(Option>, Option>, ValType<'a>)]>, /// The results types of a function. pub results: Box<[ValType<'a>]>, } impl<'a> FunctionType<'a> { fn finish_parse(&mut self, allow_names: bool, parser: Parser<'a>) -> Result<()> { let mut params = Vec::from(mem::take(&mut self.params)); let mut results = Vec::from(mem::take(&mut self.results)); while parser.peek2::()? || parser.peek2::()? { parser.parens(|p| { let mut l = p.lookahead1(); if l.peek::()? { if results.len() > 0 { return Err(p.error( "result before parameter (or unexpected token): \ cannot list params after results", )); } p.parse::()?; if p.is_empty() { return Ok(()); } let (id, name) = if allow_names { (p.parse::>()?, p.parse::>()?) } else { (None, None) }; let parse_more = id.is_none() && name.is_none(); let ty = p.parse()?; params.push((id, name, ty)); while parse_more && !p.is_empty() { params.push((None, None, p.parse()?)); } } else if l.peek::()? { p.parse::()?; while !p.is_empty() { results.push(p.parse()?); } } else { return Err(l.error()); } Ok(()) })?; } self.params = params.into(); self.results = results.into(); Ok(()) } } impl<'a> Parse<'a> for FunctionType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut ret = FunctionType { params: Box::new([]), results: Box::new([]), }; ret.finish_parse(true, parser)?; Ok(ret) } } impl<'a> Peek for FunctionType<'a> { fn peek(cursor: Cursor<'_>) -> Result { if let Some(next) = cursor.lparen()? { match next.keyword()? { Some(("param", _)) | Some(("result", _)) => return Ok(true), _ => {} } } Ok(false) } fn display() -> &'static str { "function type" } } /// A function type with parameters and results. #[derive(Clone, Debug, Default)] pub struct FunctionTypeNoNames<'a>(pub FunctionType<'a>); impl<'a> Parse<'a> for FunctionTypeNoNames<'a> { fn parse(parser: Parser<'a>) -> Result { let mut ret = FunctionType { params: Box::new([]), results: Box::new([]), }; ret.finish_parse(false, parser)?; Ok(FunctionTypeNoNames(ret)) } } impl<'a> Peek for FunctionTypeNoNames<'a> { fn peek(cursor: Cursor<'_>) -> Result { FunctionType::peek(cursor) } fn display() -> &'static str { FunctionType::display() } } impl<'a> From> for FunctionType<'a> { fn from(ty: FunctionTypeNoNames<'a>) -> FunctionType<'a> { ty.0 } } /// A struct type with fields. #[derive(Clone, Debug)] pub struct StructType<'a> { /// The fields of the struct pub fields: Vec>, } impl<'a> Parse<'a> for StructType<'a> { fn parse(parser: Parser<'a>) -> Result { let mut ret = StructType { fields: Vec::new() }; while !parser.is_empty() { parser.parens(|parser| { parser.parse::()?; if parser.peek::()? { let field = StructField::parse(parser, true); ret.fields.push(field?); } else { while !parser.is_empty() { let field = StructField::parse(parser, false); ret.fields.push(field?); } } Ok(()) })?; } Ok(ret) } } /// A field of a struct type. #[derive(Clone, Debug)] pub struct StructField<'a> { /// An optional identifier for name resolution. pub id: Option>, /// Whether this field may be mutated or not. pub mutable: bool, /// The storage type stored in this field. pub ty: StorageType<'a>, } impl<'a> StructField<'a> { fn parse(parser: Parser<'a>, with_id: bool) -> Result { let id = if with_id { parser.parse()? } else { None }; let (ty, mutable) = if parser.peek2::()? { let ty = parser.parens(|parser| { parser.parse::()?; parser.parse() })?; (ty, true) } else { (parser.parse::>()?, false) }; Ok(StructField { id, mutable, ty }) } } /// An array type with fields. #[derive(Clone, Debug)] pub struct ArrayType<'a> { /// Whether this field may be mutated or not. pub mutable: bool, /// The storage type stored in this field. pub ty: StorageType<'a>, } impl<'a> Parse<'a> for ArrayType<'a> { fn parse(parser: Parser<'a>) -> Result { let (ty, mutable) = if parser.peek2::()? { let ty = parser.parens(|parser| { parser.parse::()?; parser.parse() })?; (ty, true) } else { (parser.parse::>()?, false) }; Ok(ArrayType { mutable, ty }) } } /// The type of an exported item from a module or instance. #[derive(Debug, Clone)] pub struct ExportType<'a> { /// Where this export was defined. pub span: Span, /// The name of this export. pub name: &'a str, /// The signature of the item that's exported. pub item: ItemSig<'a>, } impl<'a> Parse<'a> for ExportType<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let name = parser.parse()?; let item = parser.parens(|p| p.parse())?; Ok(ExportType { span, name, item }) } } /// A definition of a type. #[derive(Debug)] pub enum TypeDef<'a> { /// A function type definition. Func(FunctionType<'a>), /// A struct type definition. Struct(StructType<'a>), /// An array type definition. Array(ArrayType<'a>), } impl<'a> Parse<'a> for TypeDef<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? { parser.parse::()?; Ok(TypeDef::Func(parser.parse()?)) } else if l.peek::()? { parser.parse::()?; Ok(TypeDef::Struct(parser.parse()?)) } else if l.peek::()? { parser.parse::()?; Ok(TypeDef::Array(parser.parse()?)) } else { Err(l.error()) } } } /// A type declaration in a module #[derive(Debug)] pub struct Type<'a> { /// Where this type was defined. pub span: Span, /// An optional identifier to refer to this `type` by as part of name /// resolution. pub id: Option>, /// An optional name for this function stored in the custom `name` section. pub name: Option>, /// The type that we're declaring. pub def: TypeDef<'a>, /// The declared parent type of this definition. pub parent: Option>, /// Whether this type is final or not. By default types are final. pub final_type: Option, } impl<'a> Peek for Type<'a> { fn peek(cursor: Cursor<'_>) -> Result { kw::r#type::peek(cursor) } fn display() -> &'static str { "type" } } impl<'a> Parse<'a> for Type<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; let (parent, def, final_type) = if parser.peek2::()? { parser.parens(|parser| { parser.parse::()?; let final_type: Option = if parser.peek::()? { parser.parse::()?; Some(true) } else { Some(false) }; let parent = if parser.peek::>()? { parser.parse()? } else { None }; let def = parser.parens(|parser| parser.parse())?; Ok((parent, def, final_type)) })? } else { (None, parser.parens(|parser| parser.parse())?, None) }; Ok(Type { span, id, name, def, parent, final_type, }) } } /// A recursion group declaration in a module #[derive(Debug)] pub struct Rec<'a> { /// Where this recursion group was defined. pub span: Span, /// The types that we're defining in this group. pub types: Vec>, } impl<'a> Parse<'a> for Rec<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let mut types = Vec::new(); while parser.peek2::>()? { types.push(parser.parens(|p| p.parse())?); } Ok(Rec { span, types }) } } /// A reference to a type defined in this module. #[derive(Clone, Debug)] pub struct TypeUse<'a, T> { /// The type that we're referencing, if it was present. pub index: Option>, /// The inline type, if present. pub inline: Option, } impl<'a, T> TypeUse<'a, T> { /// Constructs a new instance of `TypeUse` without an inline definition but /// with an index specified. pub fn new_with_index(idx: Index<'a>) -> TypeUse<'a, T> { TypeUse { index: Some(idx), inline: None, } } } impl<'a, T: Peek + Parse<'a>> Parse<'a> for TypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { let index = if parser.peek2::()? { Some(parser.parens(|p| { p.parse::()?; p.parse() })?) } else { None }; let inline = parser.parse()?; Ok(TypeUse { index, inline }) } } impl<'a> From>> for TypeUse<'a, FunctionType<'a>> { fn from(src: TypeUse<'a, FunctionTypeNoNames<'a>>) -> TypeUse<'a, FunctionType<'a>> { TypeUse { index: src.index, inline: src.inline.map(|x| x.into()), } } }