summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wast/src/core/types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wast/src/core/types.rs')
-rw-r--r--third_party/rust/wast/src/core/types.rs832
1 files changed, 832 insertions, 0 deletions
diff --git a/third_party/rust/wast/src/core/types.rs b/third_party/rust/wast/src/core/types.rs
new file mode 100644
index 0000000000..9abb906806
--- /dev/null
+++ b/third_party/rust/wast/src/core/types.rs
@@ -0,0 +1,832 @@
+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<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::i32>() {
+ parser.parse::<kw::i32>()?;
+ Ok(ValType::I32)
+ } else if l.peek::<kw::i64>() {
+ parser.parse::<kw::i64>()?;
+ Ok(ValType::I64)
+ } else if l.peek::<kw::f32>() {
+ parser.parse::<kw::f32>()?;
+ Ok(ValType::F32)
+ } else if l.peek::<kw::f64>() {
+ parser.parse::<kw::f64>()?;
+ Ok(ValType::F64)
+ } else if l.peek::<kw::v128>() {
+ parser.parse::<kw::v128>()?;
+ Ok(ValType::V128)
+ } else if l.peek::<RefType>() {
+ Ok(ValType::Ref(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl<'a> Peek for ValType<'a> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ 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 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 function, struct, or array: ref T. This is part of the
+ /// GC proposal.
+ Index(Index<'a>),
+}
+
+impl<'a> Parse<'a> for HeapType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::func>() {
+ parser.parse::<kw::func>()?;
+ Ok(HeapType::Func)
+ } else if l.peek::<kw::r#extern>() {
+ parser.parse::<kw::r#extern>()?;
+ Ok(HeapType::Extern)
+ } else if l.peek::<kw::r#any>() {
+ parser.parse::<kw::r#any>()?;
+ Ok(HeapType::Any)
+ } else if l.peek::<kw::eq>() {
+ parser.parse::<kw::eq>()?;
+ Ok(HeapType::Eq)
+ } else if l.peek::<kw::r#struct>() {
+ parser.parse::<kw::r#struct>()?;
+ Ok(HeapType::Struct)
+ } else if l.peek::<kw::array>() {
+ parser.parse::<kw::array>()?;
+ Ok(HeapType::Array)
+ } else if l.peek::<kw::i31>() {
+ parser.parse::<kw::i31>()?;
+ Ok(HeapType::I31)
+ } else if l.peek::<kw::nofunc>() {
+ parser.parse::<kw::nofunc>()?;
+ Ok(HeapType::NoFunc)
+ } else if l.peek::<kw::noextern>() {
+ parser.parse::<kw::noextern>()?;
+ Ok(HeapType::NoExtern)
+ } else if l.peek::<kw::none>() {
+ parser.parse::<kw::none>()?;
+ Ok(HeapType::None)
+ } else if l.peek::<Index>() {
+ Ok(HeapType::Index(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl<'a> Peek for HeapType<'a> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ kw::func::peek(cursor)
+ || kw::r#extern::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 `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<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::funcref>() {
+ parser.parse::<kw::funcref>()?;
+ Ok(RefType::func())
+ } else if l.peek::<kw::anyfunc>() {
+ parser.parse::<kw::anyfunc>()?;
+ Ok(RefType::func())
+ } else if l.peek::<kw::externref>() {
+ parser.parse::<kw::externref>()?;
+ Ok(RefType::r#extern())
+ } else if l.peek::<kw::anyref>() {
+ parser.parse::<kw::anyref>()?;
+ Ok(RefType::any())
+ } else if l.peek::<kw::eqref>() {
+ parser.parse::<kw::eqref>()?;
+ Ok(RefType::eq())
+ } else if l.peek::<kw::structref>() {
+ parser.parse::<kw::structref>()?;
+ Ok(RefType::r#struct())
+ } else if l.peek::<kw::arrayref>() {
+ parser.parse::<kw::arrayref>()?;
+ Ok(RefType::array())
+ } else if l.peek::<kw::i31ref>() {
+ parser.parse::<kw::i31ref>()?;
+ Ok(RefType::i31())
+ } else if l.peek::<kw::nullfuncref>() {
+ parser.parse::<kw::nullfuncref>()?;
+ Ok(RefType::nullfuncref())
+ } else if l.peek::<kw::nullexternref>() {
+ parser.parse::<kw::nullexternref>()?;
+ Ok(RefType::nullexternref())
+ } else if l.peek::<kw::nullref>() {
+ parser.parse::<kw::nullref>()?;
+ Ok(RefType::nullref())
+ } else if l.peek::<LParen>() {
+ parser.parens(|p| {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::r#ref>() {
+ p.parse::<kw::r#ref>()?;
+
+ let mut nullable = false;
+ if parser.peek::<kw::null>() {
+ parser.parse::<kw::null>()?;
+ 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<'_>) -> bool {
+ kw::funcref::peek(cursor)
+ || /* legacy */ kw::anyfunc::peek(cursor)
+ || kw::externref::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<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::i8>() {
+ parser.parse::<kw::i8>()?;
+ Ok(StorageType::I8)
+ } else if l.peek::<kw::i16>() {
+ parser.parse::<kw::i16>()?;
+ Ok(StorageType::I16)
+ } else if l.peek::<ValType>() {
+ 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<Self> {
+ if parser.peek2::<kw::r#mut>() {
+ parser.parens(|p| {
+ p.parse::<kw::r#mut>()?;
+ 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<u32>,
+}
+
+impl<'a> Parse<'a> for Limits {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let min = parser.parse()?;
+ let max = if parser.peek::<u32>() {
+ 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<u64>,
+}
+
+impl<'a> Parse<'a> for Limits64 {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let min = parser.parse()?;
+ let max = if parser.peek::<u64>() {
+ 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<Self> {
+ 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<Self> {
+ if parser.peek::<kw::i64>() {
+ parser.parse::<kw::i64>()?;
+ let limits = parser.parse()?;
+ let shared = parser.parse::<Option<kw::shared>>()?.is_some();
+ Ok(MemoryType::B64 { limits, shared })
+ } else {
+ parser.parse::<Option<kw::i32>>()?;
+ let limits = parser.parse()?;
+ let shared = parser.parse::<Option<kw::shared>>()?.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<Id<'a>>, Option<NameAnnotation<'a>>, 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::<kw::param>() || parser.peek2::<kw::result>() {
+ parser.parens(|p| {
+ let mut l = p.lookahead1();
+ if l.peek::<kw::param>() {
+ if results.len() > 0 {
+ return Err(p.error(
+ "result before parameter (or unexpected token): \
+ cannot list params after results",
+ ));
+ }
+ p.parse::<kw::param>()?;
+ if p.is_empty() {
+ return Ok(());
+ }
+ let (id, name) = if allow_names {
+ (p.parse::<Option<_>>()?, p.parse::<Option<_>>()?)
+ } 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::<kw::result>() {
+ p.parse::<kw::result>()?;
+ 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<Self> {
+ 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<'_>) -> bool {
+ if let Some(next) = cursor.lparen() {
+ match next.keyword() {
+ Some(("param", _)) | Some(("result", _)) => return true,
+ _ => {}
+ }
+ }
+
+ 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<Self> {
+ 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<'_>) -> bool {
+ FunctionType::peek(cursor)
+ }
+
+ fn display() -> &'static str {
+ FunctionType::display()
+ }
+}
+
+impl<'a> From<FunctionTypeNoNames<'a>> 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<StructField<'a>>,
+}
+
+impl<'a> Parse<'a> for StructType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut ret = StructType { fields: Vec::new() };
+ while !parser.is_empty() {
+ let field = if parser.peek2::<kw::field>() {
+ parser.parens(|parser| {
+ parser.parse::<kw::field>()?;
+ StructField::parse(parser, true)
+ })
+ } else {
+ StructField::parse(parser, false)
+ };
+ ret.fields.push(field?);
+ }
+ Ok(ret)
+ }
+}
+
+/// A field of a struct type.
+#[derive(Clone, Debug)]
+pub struct StructField<'a> {
+ /// An optional identifier for name resolution.
+ pub id: Option<Id<'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> StructField<'a> {
+ fn parse(parser: Parser<'a>, with_id: bool) -> Result<Self> {
+ let id = if with_id { parser.parse()? } else { None };
+ let (ty, mutable) = if parser.peek2::<kw::r#mut>() {
+ let ty = parser.parens(|parser| {
+ parser.parse::<kw::r#mut>()?;
+ parser.parse()
+ })?;
+ (ty, true)
+ } else {
+ (parser.parse::<StorageType<'a>>()?, 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<Self> {
+ let (ty, mutable) = if parser.peek2::<kw::r#mut>() {
+ let ty = parser.parens(|parser| {
+ parser.parse::<kw::r#mut>()?;
+ parser.parse()
+ })?;
+ (ty, true)
+ } else {
+ (parser.parse::<StorageType<'a>>()?, 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<Self> {
+ let span = parser.parse::<kw::export>()?.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<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::func>() {
+ parser.parse::<kw::func>()?;
+ Ok(TypeDef::Func(parser.parse()?))
+ } else if l.peek::<kw::r#struct>() {
+ parser.parse::<kw::r#struct>()?;
+ Ok(TypeDef::Struct(parser.parse()?))
+ } else if l.peek::<kw::array>() {
+ parser.parse::<kw::array>()?;
+ 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<Id<'a>>,
+ /// An optional name for this function stored in the custom `name` section.
+ pub name: Option<NameAnnotation<'a>>,
+ /// The type that we're declaring.
+ pub def: TypeDef<'a>,
+ /// The declared parent type of this definition.
+ pub parent: Option<Index<'a>>,
+}
+
+impl<'a> Peek for Type<'a> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ kw::r#type::peek(cursor)
+ }
+ fn display() -> &'static str {
+ "type"
+ }
+}
+
+impl<'a> Parse<'a> for Type<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::r#type>()?.0;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+
+ let (parent, def) = if parser.peek2::<kw::sub>() {
+ parser.parens(|parser| {
+ parser.parse::<kw::sub>()?;
+ let parent = if parser.peek::<Index<'a>>() {
+ parser.parse()?
+ } else {
+ None
+ };
+ let def = parser.parens(|parser| parser.parse())?;
+ Ok((parent, def))
+ })?
+ } else {
+ (None, parser.parens(|parser| parser.parse())?)
+ };
+
+ Ok(Type {
+ span,
+ id,
+ name,
+ def,
+ parent,
+ })
+ }
+}
+
+/// 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<Type<'a>>,
+}
+
+impl<'a> Parse<'a> for Rec<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::r#rec>()?.0;
+ let mut types = Vec::new();
+ while parser.peek2::<Type<'a>>() {
+ 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<Index<'a>>,
+ /// The inline type, if present.
+ pub inline: Option<T>,
+}
+
+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<Self> {
+ let index = if parser.peek2::<kw::r#type>() {
+ Some(parser.parens(|p| {
+ p.parse::<kw::r#type>()?;
+ p.parse()
+ })?)
+ } else {
+ None
+ };
+ let inline = parser.parse()?;
+
+ Ok(TypeUse { index, inline })
+ }
+}
+
+impl<'a> From<TypeUse<'a, FunctionTypeNoNames<'a>>> 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()),
+ }
+ }
+}