summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wast/src/component
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/wast/src/component
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/wast/src/component')
-rw-r--r--third_party/rust/wast/src/component/alias.rs253
-rw-r--r--third_party/rust/wast/src/component/binary.rs972
-rw-r--r--third_party/rust/wast/src/component/component.rs313
-rw-r--r--third_party/rust/wast/src/component/custom.rs28
-rw-r--r--third_party/rust/wast/src/component/expand.rs859
-rw-r--r--third_party/rust/wast/src/component/export.rs221
-rw-r--r--third_party/rust/wast/src/component/func.rs372
-rw-r--r--third_party/rust/wast/src/component/import.rs176
-rw-r--r--third_party/rust/wast/src/component/instance.rs296
-rw-r--r--third_party/rust/wast/src/component/item_ref.rs154
-rw-r--r--third_party/rust/wast/src/component/module.rs75
-rw-r--r--third_party/rust/wast/src/component/resolve.rs973
-rw-r--r--third_party/rust/wast/src/component/types.rs965
-rw-r--r--third_party/rust/wast/src/component/wast.rs166
14 files changed, 5823 insertions, 0 deletions
diff --git a/third_party/rust/wast/src/component/alias.rs b/third_party/rust/wast/src/component/alias.rs
new file mode 100644
index 0000000000..3c70a2d371
--- /dev/null
+++ b/third_party/rust/wast/src/component/alias.rs
@@ -0,0 +1,253 @@
+use crate::core::ExportKind;
+use crate::kw;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::{Id, Index, NameAnnotation, Span};
+
+/// A inline alias for component exported items.
+#[derive(Debug)]
+pub struct InlineExportAlias<'a> {
+ /// The instance to alias the export from.
+ pub instance: Index<'a>,
+ /// The name of the export to alias.
+ pub name: &'a str,
+}
+
+impl<'a> Parse<'a> for InlineExportAlias<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::alias>()?;
+ parser.parse::<kw::export>()?;
+ let instance = parser.parse()?;
+ let name = parser.parse()?;
+ Ok(Self { instance, name })
+ }
+}
+
+/// An alias to a component item.
+#[derive(Debug)]
+pub struct Alias<'a> {
+ /// Where this `alias` was defined.
+ pub span: Span,
+ /// An identifier that this alias is resolved with (optionally) for name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this alias stored in the custom `name` section.
+ pub name: Option<NameAnnotation<'a>>,
+ /// The target of this alias.
+ pub target: AliasTarget<'a>,
+}
+
+impl<'a> Alias<'a> {
+ /// Parses only an outer type alias.
+ pub fn parse_outer_core_type_alias(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::alias>()?.0;
+ parser.parse::<kw::outer>()?;
+ let outer = parser.parse()?;
+ let index = parser.parse()?;
+
+ let (kind, id, name) = parser.parens(|parser| {
+ let mut kind: ComponentOuterAliasKind = parser.parse()?;
+ match kind {
+ ComponentOuterAliasKind::CoreType => {
+ return Err(parser.error("expected type for outer alias"))
+ }
+ ComponentOuterAliasKind::Type => {
+ kind = ComponentOuterAliasKind::CoreType;
+ }
+ _ => return Err(parser.error("expected core type or type for outer alias")),
+ }
+
+ Ok((kind, parser.parse()?, parser.parse()?))
+ })?;
+
+ Ok(Self {
+ span,
+ target: AliasTarget::Outer { outer, index, kind },
+ id,
+ name,
+ })
+ }
+}
+
+impl<'a> Parse<'a> for Alias<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::alias>()?.0;
+
+ let mut l = parser.lookahead1();
+
+ let (target, id, name) = if l.peek::<kw::outer>() {
+ parser.parse::<kw::outer>()?;
+ let outer = parser.parse()?;
+ let index = parser.parse()?;
+ let (kind, id, name) =
+ parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?;
+
+ (AliasTarget::Outer { outer, index, kind }, id, name)
+ } else if l.peek::<kw::export>() {
+ parser.parse::<kw::export>()?;
+ let instance = parser.parse()?;
+ let export_name = parser.parse()?;
+ let (kind, id, name) =
+ parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?;
+
+ (
+ AliasTarget::Export {
+ instance,
+ name: export_name,
+ kind,
+ },
+ id,
+ name,
+ )
+ } else if l.peek::<kw::core>() {
+ parser.parse::<kw::core>()?;
+ parser.parse::<kw::export>()?;
+ let instance = parser.parse()?;
+ let export_name = parser.parse()?;
+ let (kind, id, name) = parser.parens(|parser| {
+ parser.parse::<kw::core>()?;
+ Ok((parser.parse()?, parser.parse()?, parser.parse()?))
+ })?;
+
+ (
+ AliasTarget::CoreExport {
+ instance,
+ name: export_name,
+ kind,
+ },
+ id,
+ name,
+ )
+ } else {
+ return Err(l.error());
+ };
+
+ Ok(Self {
+ span,
+ target,
+ id,
+ name,
+ })
+ }
+}
+
+/// Represents the kind of instance export alias.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ComponentExportAliasKind {
+ /// The alias is to a core module export.
+ CoreModule,
+ /// The alias is to a function export.
+ Func,
+ /// The alias is to a value export.
+ Value,
+ /// The alias is to a type export.
+ Type,
+ /// The alias is to a component export.
+ Component,
+ /// The alias is to an instance export.
+ Instance,
+}
+
+impl<'a> Parse<'a> for ComponentExportAliasKind {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::core>() {
+ parser.parse::<kw::core>()?;
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::module>() {
+ parser.parse::<kw::module>()?;
+ Ok(Self::CoreModule)
+ } else {
+ Err(l.error())
+ }
+ } else if l.peek::<kw::func>() {
+ parser.parse::<kw::func>()?;
+ Ok(Self::Func)
+ } else if l.peek::<kw::value>() {
+ parser.parse::<kw::value>()?;
+ Ok(Self::Value)
+ } else if l.peek::<kw::r#type>() {
+ parser.parse::<kw::r#type>()?;
+ Ok(Self::Type)
+ } else if l.peek::<kw::component>() {
+ parser.parse::<kw::component>()?;
+ Ok(Self::Component)
+ } else if l.peek::<kw::instance>() {
+ parser.parse::<kw::instance>()?;
+ Ok(Self::Instance)
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+/// Represents the kind of outer alias.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ComponentOuterAliasKind {
+ /// The alias is to an outer core module.
+ CoreModule,
+ /// The alias is to an outer core type.
+ CoreType,
+ /// The alias is to an outer type.
+ Type,
+ /// The alias is to an outer component.
+ Component,
+}
+
+impl<'a> Parse<'a> for ComponentOuterAliasKind {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::core>() {
+ parser.parse::<kw::core>()?;
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::module>() {
+ parser.parse::<kw::module>()?;
+ Ok(Self::CoreModule)
+ } else if l.peek::<kw::r#type>() {
+ parser.parse::<kw::r#type>()?;
+ Ok(Self::CoreType)
+ } else {
+ Err(l.error())
+ }
+ } else if l.peek::<kw::r#type>() {
+ parser.parse::<kw::r#type>()?;
+ Ok(Self::Type)
+ } else if l.peek::<kw::component>() {
+ parser.parse::<kw::component>()?;
+ Ok(Self::Component)
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+/// The target of a component alias.
+#[derive(Debug)]
+pub enum AliasTarget<'a> {
+ /// The alias is to an export of a component instance.
+ Export {
+ /// The component instance exporting the item.
+ instance: Index<'a>,
+ /// The name of the exported item to alias.
+ name: &'a str,
+ /// The export kind of the alias.
+ kind: ComponentExportAliasKind,
+ },
+ /// The alias is to an export of a module instance.
+ CoreExport {
+ /// The module instance exporting the item.
+ instance: Index<'a>,
+ /// The name of the exported item to alias.
+ name: &'a str,
+ /// The export kind of the alias.
+ kind: ExportKind,
+ },
+ /// The alias is to an item from an outer component.
+ Outer {
+ /// The number of enclosing components to skip.
+ outer: Index<'a>,
+ /// The index of the item being aliased.
+ index: Index<'a>,
+ /// The outer alias kind.
+ kind: ComponentOuterAliasKind,
+ },
+}
diff --git a/third_party/rust/wast/src/component/binary.rs b/third_party/rust/wast/src/component/binary.rs
new file mode 100644
index 0000000000..6d57ed4380
--- /dev/null
+++ b/third_party/rust/wast/src/component/binary.rs
@@ -0,0 +1,972 @@
+use crate::component::*;
+use crate::core;
+use crate::token::{Id, Index, NameAnnotation};
+use wasm_encoder::{
+ CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder,
+ ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentNameSection,
+ ComponentSection, ComponentSectionId, ComponentStartSection, ComponentTypeEncoder,
+ ComponentTypeSection, CoreTypeEncoder, CoreTypeSection, InstanceSection, NameMap,
+ NestedComponentSection, RawSection, SectionId,
+};
+
+pub fn encode(component: &Component<'_>) -> Vec<u8> {
+ match &component.kind {
+ ComponentKind::Text(fields) => {
+ encode_fields(&component.id, &component.name, fields).finish()
+ }
+ ComponentKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().copied()).collect(),
+ }
+}
+
+fn encode_fields(
+ // TODO: use the id and name for a future names section
+ component_id: &Option<Id<'_>>,
+ component_name: &Option<NameAnnotation<'_>>,
+ fields: &[ComponentField<'_>],
+) -> wasm_encoder::Component {
+ let mut e = Encoder::default();
+
+ for field in fields {
+ match field {
+ ComponentField::CoreModule(m) => e.encode_core_module(m),
+ ComponentField::CoreInstance(i) => e.encode_core_instance(i),
+ ComponentField::CoreType(t) => e.encode_core_type(t),
+ ComponentField::Component(c) => e.encode_component(c),
+ ComponentField::Instance(i) => e.encode_instance(i),
+ ComponentField::Alias(a) => e.encode_alias(a),
+ ComponentField::Type(t) => e.encode_type(t),
+ ComponentField::CanonicalFunc(f) => e.encode_canonical_func(f),
+ ComponentField::CoreFunc(_) | ComponentField::Func(_) => {
+ unreachable!("should be expanded already")
+ }
+ ComponentField::Start(s) => e.encode_start(s),
+ ComponentField::Import(i) => e.encode_import(i),
+ ComponentField::Export(ex) => e.encode_export(ex),
+ ComponentField::Custom(c) => e.encode_custom(c),
+ }
+ }
+
+ e.flush(None);
+ e.encode_names(component_id, component_name);
+
+ e.component
+}
+
+fn encode_core_type(encoder: CoreTypeEncoder, ty: &CoreTypeDef) {
+ match ty {
+ CoreTypeDef::Def(core::TypeDef::Func(f)) => {
+ encoder.function(
+ f.params.iter().map(|(_, _, ty)| (*ty).into()),
+ f.results.iter().copied().map(Into::into),
+ );
+ }
+ CoreTypeDef::Def(core::TypeDef::Struct(_)) | CoreTypeDef::Def(core::TypeDef::Array(_)) => {
+ todo!("encoding of GC proposal types not yet implemented")
+ }
+ CoreTypeDef::Module(t) => {
+ encoder.module(&t.into());
+ }
+ }
+}
+
+fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) {
+ match ty {
+ TypeDef::Defined(t) => {
+ encode_defined_type(encoder.defined_type(), t);
+ }
+ TypeDef::Func(f) => {
+ let mut encoder = encoder.function();
+ encoder.params(f.params.iter().map(|p| (p.name, &p.ty)));
+
+ if f.results.len() == 1 && f.results[0].name.is_none() {
+ encoder.result(&f.results[0].ty);
+ } else {
+ encoder.results(f.results.iter().map(|r| (r.name.unwrap_or(""), &r.ty)));
+ }
+ }
+ TypeDef::Component(c) => {
+ encoder.component(&c.into());
+ }
+ TypeDef::Instance(i) => {
+ encoder.instance(&i.into());
+ }
+ }
+}
+
+fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefinedType) {
+ match ty {
+ ComponentDefinedType::Primitive(p) => encoder.primitive((*p).into()),
+ ComponentDefinedType::Record(r) => {
+ encoder.record(r.fields.iter().map(|f| (f.name, &f.ty)));
+ }
+ ComponentDefinedType::Variant(v) => {
+ encoder.variant(v.cases.iter().map(|c| {
+ (
+ c.name,
+ c.ty.as_ref().map(Into::into),
+ c.refines.as_ref().map(Into::into),
+ )
+ }));
+ }
+ ComponentDefinedType::List(l) => {
+ encoder.list(l.element.as_ref());
+ }
+ ComponentDefinedType::Tuple(t) => {
+ encoder.tuple(t.fields.iter());
+ }
+ ComponentDefinedType::Flags(f) => {
+ encoder.flags(f.names.iter().copied());
+ }
+ ComponentDefinedType::Enum(e) => {
+ encoder.enum_type(e.names.iter().copied());
+ }
+ ComponentDefinedType::Union(u) => encoder.union(u.types.iter()),
+ ComponentDefinedType::Option(o) => {
+ encoder.option(o.element.as_ref());
+ }
+ ComponentDefinedType::Result(e) => {
+ encoder.result(
+ e.ok.as_deref().map(Into::into),
+ e.err.as_deref().map(Into::into),
+ );
+ }
+ }
+}
+
+#[derive(Default)]
+struct Encoder<'a> {
+ component: wasm_encoder::Component,
+ current_section_id: Option<u8>,
+
+ // Core sections
+ // Note: module sections are written immediately
+ core_instances: InstanceSection,
+ core_types: CoreTypeSection,
+
+ // Component sections
+ // Note: custom, component, start sections are written immediately
+ instances: ComponentInstanceSection,
+ aliases: ComponentAliasSection,
+ types: ComponentTypeSection,
+ funcs: CanonicalFunctionSection,
+ imports: ComponentImportSection,
+ exports: ComponentExportSection,
+
+ core_func_names: Vec<Option<&'a str>>,
+ core_table_names: Vec<Option<&'a str>>,
+ core_memory_names: Vec<Option<&'a str>>,
+ core_global_names: Vec<Option<&'a str>>,
+ core_type_names: Vec<Option<&'a str>>,
+ core_module_names: Vec<Option<&'a str>>,
+ core_instance_names: Vec<Option<&'a str>>,
+ func_names: Vec<Option<&'a str>>,
+ value_names: Vec<Option<&'a str>>,
+ type_names: Vec<Option<&'a str>>,
+ component_names: Vec<Option<&'a str>>,
+ instance_names: Vec<Option<&'a str>>,
+}
+
+impl<'a> Encoder<'a> {
+ fn encode_custom(&mut self, custom: &Custom) {
+ // Flush any in-progress section before encoding the customs section
+ self.flush(None);
+ self.component.section(custom);
+ }
+
+ fn encode_core_module(&mut self, module: &CoreModule<'a>) {
+ // Flush any in-progress section before encoding the module
+ self.flush(None);
+
+ self.core_module_names
+ .push(get_name(&module.id, &module.name));
+
+ match &module.kind {
+ CoreModuleKind::Import { .. } => unreachable!("should be expanded already"),
+ CoreModuleKind::Inline { fields } => {
+ // TODO: replace this with a wasm-encoder based encoding (should return `wasm_encoder::Module`)
+ let data = crate::core::binary::encode(&module.id, &module.name, fields);
+ self.component.section(&RawSection {
+ id: ComponentSectionId::CoreModule.into(),
+ data: &data,
+ });
+ }
+ }
+ }
+
+ fn encode_core_instance(&mut self, instance: &CoreInstance<'a>) {
+ self.core_instance_names
+ .push(get_name(&instance.id, &instance.name));
+ match &instance.kind {
+ CoreInstanceKind::Instantiate { module, args } => {
+ self.core_instances.instantiate(
+ module.into(),
+ args.iter().map(|arg| (arg.name, (&arg.kind).into())),
+ );
+ }
+ CoreInstanceKind::BundleOfExports(exports) => {
+ self.core_instances.export_items(exports.iter().map(|e| {
+ let (kind, index) = (&e.item).into();
+ (e.name, kind, index)
+ }));
+ }
+ }
+
+ self.flush(Some(self.core_instances.id()));
+ }
+
+ fn encode_core_type(&mut self, ty: &CoreType<'a>) {
+ self.core_type_names.push(get_name(&ty.id, &ty.name));
+ encode_core_type(self.core_types.ty(), &ty.def);
+ self.flush(Some(self.core_types.id()));
+ }
+
+ fn encode_component(&mut self, component: &NestedComponent<'a>) {
+ self.component_names
+ .push(get_name(&component.id, &component.name));
+ // Flush any in-progress section before encoding the component
+ self.flush(None);
+
+ match &component.kind {
+ NestedComponentKind::Import { .. } => unreachable!("should be expanded already"),
+ NestedComponentKind::Inline(fields) => {
+ self.component
+ .section(&NestedComponentSection(&encode_fields(
+ &component.id,
+ &component.name,
+ fields,
+ )));
+ }
+ }
+ }
+
+ fn encode_instance(&mut self, instance: &Instance<'a>) {
+ self.instance_names
+ .push(get_name(&instance.id, &instance.name));
+ match &instance.kind {
+ InstanceKind::Import { .. } => unreachable!("should be expanded already"),
+ InstanceKind::Instantiate { component, args } => {
+ self.instances.instantiate(
+ component.into(),
+ args.iter().map(|arg| {
+ let (kind, index) = (&arg.kind).into();
+ (arg.name, kind, index)
+ }),
+ );
+ }
+ InstanceKind::BundleOfExports(exports) => {
+ self.instances.export_items(exports.iter().map(|e| {
+ let (kind, index) = (&e.kind).into();
+ (e.name, kind, index)
+ }));
+ }
+ }
+
+ self.flush(Some(self.instances.id()));
+ }
+
+ fn encode_alias(&mut self, alias: &Alias<'a>) {
+ let name = get_name(&alias.id, &alias.name);
+ self.aliases.alias((&alias.target).into());
+ match &alias.target {
+ AliasTarget::Export { kind, .. } => {
+ self.names_for_component_export_alias(*kind).push(name);
+ }
+ AliasTarget::CoreExport { kind, .. } => {
+ self.names_for_core_export_alias(*kind).push(name);
+ }
+ AliasTarget::Outer { kind, .. } => {
+ self.names_for_component_outer_alias(*kind).push(name);
+ }
+ }
+
+ self.flush(Some(self.aliases.id()));
+ }
+
+ fn encode_start(&mut self, start: &Start) {
+ // Flush any in-progress section before encoding the start section
+ self.flush(None);
+
+ self.component.section(&ComponentStartSection {
+ function_index: start.func.into(),
+ args: start.args.iter().map(|a| a.idx.into()).collect::<Vec<_>>(),
+ results: start.results.len() as u32,
+ });
+ }
+
+ fn encode_type(&mut self, ty: &Type<'a>) {
+ self.type_names.push(get_name(&ty.id, &ty.name));
+ encode_type(self.types.ty(), &ty.def);
+ self.flush(Some(self.types.id()));
+ }
+
+ fn encode_canonical_func(&mut self, func: &CanonicalFunc<'a>) {
+ let name = get_name(&func.id, &func.name);
+ match &func.kind {
+ CanonicalFuncKind::Lift { ty, info } => {
+ self.func_names.push(name);
+ self.funcs.lift(
+ info.func.idx.into(),
+ ty.into(),
+ info.opts.iter().map(Into::into),
+ );
+ }
+ CanonicalFuncKind::Lower(info) => {
+ self.core_func_names.push(name);
+ self.funcs
+ .lower(info.func.idx.into(), info.opts.iter().map(Into::into));
+ }
+ }
+
+ self.flush(Some(self.funcs.id()));
+ }
+
+ fn encode_import(&mut self, import: &ComponentImport<'a>) {
+ let name = get_name(&import.item.id, &import.item.name);
+ self.names_for_item_kind(&import.item.kind).push(name);
+ self.imports.import(
+ import.name,
+ import.url.unwrap_or(""),
+ (&import.item.kind).into(),
+ );
+ self.flush(Some(self.imports.id()));
+ }
+
+ fn encode_export(&mut self, export: &ComponentExport<'a>) {
+ let name = get_name(&export.id, &export.debug_name);
+ let (kind, index) = (&export.kind).into();
+ self.exports.export(
+ export.name,
+ export.url.unwrap_or(""),
+ kind,
+ index,
+ export.ty.as_ref().map(|ty| (&ty.0.kind).into()),
+ );
+ match &export.kind {
+ ComponentExportKind::CoreModule(_) => self.core_module_names.push(name),
+ ComponentExportKind::Func(_) => self.func_names.push(name),
+ ComponentExportKind::Instance(_) => self.instance_names.push(name),
+ ComponentExportKind::Value(_) => self.value_names.push(name),
+ ComponentExportKind::Component(_) => self.component_names.push(name),
+ ComponentExportKind::Type(_) => self.type_names.push(name),
+ }
+ self.flush(Some(self.exports.id()));
+ }
+
+ fn flush(&mut self, section_id: Option<u8>) {
+ if self.current_section_id == section_id {
+ return;
+ }
+
+ if let Some(id) = self.current_section_id {
+ match id {
+ // 0 => custom sections are written immediately
+ // 1 => core modules sections are written immediately
+ 2 => {
+ assert_eq!(id, self.core_instances.id());
+ self.component.section(&self.core_instances);
+ self.core_instances = Default::default();
+ }
+ 3 => {
+ assert_eq!(id, self.core_types.id());
+ self.component.section(&self.core_types);
+ self.core_types = Default::default();
+ }
+ // 4 => components sections are written immediately
+ 5 => {
+ assert_eq!(id, self.instances.id());
+ self.component.section(&self.instances);
+ self.instances = Default::default();
+ }
+ 6 => {
+ assert_eq!(id, self.aliases.id());
+ self.component.section(&self.aliases);
+ self.aliases = Default::default();
+ }
+ 7 => {
+ assert_eq!(id, self.types.id());
+ self.component.section(&self.types);
+ self.types = Default::default();
+ }
+ 8 => {
+ assert_eq!(id, self.funcs.id());
+ self.component.section(&self.funcs);
+ self.funcs = Default::default();
+ }
+ // 9 => start sections are written immediately
+ 10 => {
+ assert_eq!(id, self.imports.id());
+ self.component.section(&self.imports);
+ self.imports = Default::default();
+ }
+ 11 => {
+ assert_eq!(id, self.exports.id());
+ self.component.section(&self.exports);
+ self.exports = Default::default();
+ }
+ _ => unreachable!("unknown incremental component section id: {}", id),
+ }
+ }
+
+ self.current_section_id = section_id
+ }
+
+ fn encode_names(
+ &mut self,
+ component_id: &Option<Id<'_>>,
+ component_name: &Option<NameAnnotation<'_>>,
+ ) {
+ let mut names = ComponentNameSection::new();
+ if let Some(name) = get_name(component_id, component_name) {
+ names.component(name);
+ }
+
+ let mut funcs = |list: &[Option<&str>], append: fn(&mut ComponentNameSection, &NameMap)| {
+ let mut map = NameMap::new();
+ for (i, entry) in list.iter().enumerate() {
+ if let Some(name) = entry {
+ map.append(i as u32, name);
+ }
+ }
+ if !map.is_empty() {
+ append(&mut names, &map);
+ }
+ };
+
+ funcs(&self.core_func_names, ComponentNameSection::core_funcs);
+ funcs(&self.core_table_names, ComponentNameSection::core_tables);
+ funcs(&self.core_memory_names, ComponentNameSection::core_memories);
+ funcs(&self.core_global_names, ComponentNameSection::core_globals);
+ funcs(&self.core_type_names, ComponentNameSection::core_types);
+ funcs(&self.core_module_names, ComponentNameSection::core_modules);
+ funcs(
+ &self.core_instance_names,
+ ComponentNameSection::core_instances,
+ );
+ funcs(&self.func_names, ComponentNameSection::funcs);
+ funcs(&self.value_names, ComponentNameSection::values);
+ funcs(&self.type_names, ComponentNameSection::types);
+ funcs(&self.component_names, ComponentNameSection::components);
+ funcs(&self.instance_names, ComponentNameSection::instances);
+
+ if !names.is_empty() {
+ self.component.section(&names);
+ }
+ }
+
+ fn names_for_component_export_alias(
+ &mut self,
+ kind: ComponentExportAliasKind,
+ ) -> &mut Vec<Option<&'a str>> {
+ match kind {
+ ComponentExportAliasKind::Func => &mut self.func_names,
+ ComponentExportAliasKind::CoreModule => &mut self.core_module_names,
+ ComponentExportAliasKind::Value => &mut self.value_names,
+ ComponentExportAliasKind::Type => &mut self.type_names,
+ ComponentExportAliasKind::Component => &mut self.component_names,
+ ComponentExportAliasKind::Instance => &mut self.instance_names,
+ }
+ }
+
+ fn names_for_component_outer_alias(
+ &mut self,
+ kind: ComponentOuterAliasKind,
+ ) -> &mut Vec<Option<&'a str>> {
+ match kind {
+ ComponentOuterAliasKind::CoreModule => &mut self.core_module_names,
+ ComponentOuterAliasKind::CoreType => &mut self.core_type_names,
+ ComponentOuterAliasKind::Component => &mut self.component_names,
+ ComponentOuterAliasKind::Type => &mut self.type_names,
+ }
+ }
+
+ fn names_for_core_export_alias(&mut self, kind: core::ExportKind) -> &mut Vec<Option<&'a str>> {
+ match kind {
+ core::ExportKind::Func => &mut self.core_func_names,
+ core::ExportKind::Global => &mut self.core_global_names,
+ core::ExportKind::Table => &mut self.core_table_names,
+ core::ExportKind::Memory => &mut self.core_memory_names,
+ core::ExportKind::Tag => unimplemented!(),
+ }
+ }
+
+ fn names_for_item_kind(&mut self, kind: &ItemSigKind) -> &mut Vec<Option<&'a str>> {
+ match kind {
+ ItemSigKind::CoreModule(_) => &mut self.core_module_names,
+ ItemSigKind::Func(_) => &mut self.func_names,
+ ItemSigKind::Component(_) => &mut self.component_names,
+ ItemSigKind::Instance(_) => &mut self.instance_names,
+ ItemSigKind::Value(_) => &mut self.value_names,
+ ItemSigKind::Type(_) => &mut self.type_names,
+ }
+ }
+}
+
+fn get_name<'a>(id: &Option<Id<'a>>, name: &Option<NameAnnotation<'a>>) -> Option<&'a str> {
+ name.as_ref().map(|n| n.name).or_else(|| {
+ id.and_then(|id| {
+ if id.is_gensym() {
+ None
+ } else {
+ Some(id.name())
+ }
+ })
+ })
+}
+
+// This implementation is much like `wasm_encoder::CustomSection`, except
+// that it extends via a list of slices instead of a single slice.
+impl wasm_encoder::Encode for Custom<'_> {
+ fn encode(&self, sink: &mut Vec<u8>) {
+ let mut buf = [0u8; 5];
+ let encoded_name_len =
+ leb128::write::unsigned(&mut &mut buf[..], u64::try_from(self.name.len()).unwrap())
+ .unwrap();
+ let data_len = self.data.iter().fold(0, |acc, s| acc + s.len());
+
+ // name length
+ (encoded_name_len + self.name.len() + data_len).encode(sink);
+
+ // name
+ self.name.encode(sink);
+
+ // data
+ for s in &self.data {
+ sink.extend(*s);
+ }
+ }
+}
+
+impl wasm_encoder::ComponentSection for Custom<'_> {
+ fn id(&self) -> u8 {
+ SectionId::Custom.into()
+ }
+}
+
+// TODO: move these core conversion functions to the core module
+// once we update core encoding to use wasm-encoder.
+impl From<core::ValType<'_>> for wasm_encoder::ValType {
+ fn from(ty: core::ValType) -> Self {
+ match ty {
+ core::ValType::I32 => Self::I32,
+ core::ValType::I64 => Self::I64,
+ core::ValType::F32 => Self::F32,
+ core::ValType::F64 => Self::F64,
+ core::ValType::V128 => Self::V128,
+ core::ValType::Ref(r) => Self::Ref(r.into()),
+ }
+ }
+}
+
+impl From<core::RefType<'_>> for wasm_encoder::RefType {
+ fn from(r: core::RefType<'_>) -> Self {
+ wasm_encoder::RefType {
+ nullable: r.nullable,
+ heap_type: r.heap.into(),
+ }
+ }
+}
+
+impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
+ fn from(r: core::HeapType<'_>) -> Self {
+ match r {
+ core::HeapType::Func => Self::Func,
+ core::HeapType::Extern => Self::Extern,
+ core::HeapType::Index(Index::Num(i, _)) => Self::TypedFunc(i),
+ core::HeapType::Index(_) => panic!("unresolved index"),
+ core::HeapType::Any
+ | core::HeapType::Eq
+ | core::HeapType::Struct
+ | core::HeapType::Array
+ | core::HeapType::NoFunc
+ | core::HeapType::NoExtern
+ | core::HeapType::None
+ | core::HeapType::I31 => {
+ todo!("encoding of GC proposal types not yet implemented")
+ }
+ }
+ }
+}
+
+impl From<&core::ItemKind<'_>> for wasm_encoder::EntityType {
+ fn from(kind: &core::ItemKind) -> Self {
+ match kind {
+ core::ItemKind::Func(t) => Self::Function(t.into()),
+ core::ItemKind::Table(t) => Self::Table((*t).into()),
+ core::ItemKind::Memory(t) => Self::Memory((*t).into()),
+ core::ItemKind::Global(t) => Self::Global((*t).into()),
+ core::ItemKind::Tag(t) => Self::Tag(t.into()),
+ }
+ }
+}
+
+impl From<core::TableType<'_>> for wasm_encoder::TableType {
+ fn from(ty: core::TableType) -> Self {
+ Self {
+ element_type: ty.elem.into(),
+ minimum: ty.limits.min,
+ maximum: ty.limits.max,
+ }
+ }
+}
+
+impl From<core::MemoryType> for wasm_encoder::MemoryType {
+ fn from(ty: core::MemoryType) -> Self {
+ let (minimum, maximum, memory64, shared) = match ty {
+ core::MemoryType::B32 { limits, shared } => {
+ (limits.min.into(), limits.max.map(Into::into), false, shared)
+ }
+ core::MemoryType::B64 { limits, shared } => (limits.min, limits.max, true, shared),
+ };
+
+ Self {
+ minimum,
+ maximum,
+ memory64,
+ shared,
+ }
+ }
+}
+
+impl From<core::GlobalType<'_>> for wasm_encoder::GlobalType {
+ fn from(ty: core::GlobalType) -> Self {
+ Self {
+ val_type: ty.ty.into(),
+ mutable: ty.mutable,
+ }
+ }
+}
+
+impl From<&core::TagType<'_>> for wasm_encoder::TagType {
+ fn from(ty: &core::TagType) -> Self {
+ match ty {
+ core::TagType::Exception(r) => Self {
+ kind: wasm_encoder::TagKind::Exception,
+ func_type_idx: r.into(),
+ },
+ }
+ }
+}
+
+impl<T: std::fmt::Debug> From<&core::TypeUse<'_, T>> for u32 {
+ fn from(u: &core::TypeUse<'_, T>) -> Self {
+ match &u.index {
+ Some(i) => (*i).into(),
+ None => unreachable!("unresolved type use in encoding: {:?}", u),
+ }
+ }
+}
+
+impl From<&CoreInstantiationArgKind<'_>> for wasm_encoder::ModuleArg {
+ fn from(kind: &CoreInstantiationArgKind) -> Self {
+ match kind {
+ CoreInstantiationArgKind::Instance(i) => {
+ wasm_encoder::ModuleArg::Instance(i.idx.into())
+ }
+ CoreInstantiationArgKind::BundleOfExports(..) => {
+ unreachable!("should be expanded already")
+ }
+ }
+ }
+}
+
+impl From<&CoreItemRef<'_, core::ExportKind>> for (wasm_encoder::ExportKind, u32) {
+ fn from(item: &CoreItemRef<'_, core::ExportKind>) -> Self {
+ match &item.kind {
+ core::ExportKind::Func => (wasm_encoder::ExportKind::Func, item.idx.into()),
+ core::ExportKind::Table => (wasm_encoder::ExportKind::Table, item.idx.into()),
+ core::ExportKind::Memory => (wasm_encoder::ExportKind::Memory, item.idx.into()),
+ core::ExportKind::Global => (wasm_encoder::ExportKind::Global, item.idx.into()),
+ core::ExportKind::Tag => (wasm_encoder::ExportKind::Tag, item.idx.into()),
+ }
+ }
+}
+
+impl From<core::ExportKind> for wasm_encoder::ExportKind {
+ fn from(kind: core::ExportKind) -> Self {
+ match kind {
+ core::ExportKind::Func => Self::Func,
+ core::ExportKind::Table => Self::Table,
+ core::ExportKind::Memory => Self::Memory,
+ core::ExportKind::Global => Self::Global,
+ core::ExportKind::Tag => Self::Tag,
+ }
+ }
+}
+
+impl From<Index<'_>> for u32 {
+ fn from(i: Index<'_>) -> Self {
+ match i {
+ Index::Num(i, _) => i,
+ Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i),
+ }
+ }
+}
+
+impl<T> From<&ItemRef<'_, T>> for u32 {
+ fn from(i: &ItemRef<'_, T>) -> Self {
+ assert!(i.export_names.is_empty());
+ i.idx.into()
+ }
+}
+
+impl<T> From<&CoreTypeUse<'_, T>> for u32 {
+ fn from(u: &CoreTypeUse<'_, T>) -> Self {
+ match u {
+ CoreTypeUse::Inline(_) => unreachable!("should be expanded already"),
+ CoreTypeUse::Ref(r) => r.idx.into(),
+ }
+ }
+}
+
+impl<T> From<&ComponentTypeUse<'_, T>> for u32 {
+ fn from(u: &ComponentTypeUse<'_, T>) -> Self {
+ match u {
+ ComponentTypeUse::Inline(_) => unreachable!("should be expanded already"),
+ ComponentTypeUse::Ref(r) => r.idx.into(),
+ }
+ }
+}
+
+impl From<&ComponentValType<'_>> for wasm_encoder::ComponentValType {
+ fn from(r: &ComponentValType) -> Self {
+ match r {
+ ComponentValType::Inline(ComponentDefinedType::Primitive(p)) => {
+ Self::Primitive((*p).into())
+ }
+ ComponentValType::Ref(i) => Self::Type(u32::from(*i)),
+ ComponentValType::Inline(_) => unreachable!("should be expanded by now"),
+ }
+ }
+}
+
+impl From<PrimitiveValType> for wasm_encoder::PrimitiveValType {
+ fn from(p: PrimitiveValType) -> Self {
+ match p {
+ PrimitiveValType::Bool => Self::Bool,
+ PrimitiveValType::S8 => Self::S8,
+ PrimitiveValType::U8 => Self::U8,
+ PrimitiveValType::S16 => Self::S16,
+ PrimitiveValType::U16 => Self::U16,
+ PrimitiveValType::S32 => Self::S32,
+ PrimitiveValType::U32 => Self::U32,
+ PrimitiveValType::S64 => Self::S64,
+ PrimitiveValType::U64 => Self::U64,
+ PrimitiveValType::Float32 => Self::Float32,
+ PrimitiveValType::Float64 => Self::Float64,
+ PrimitiveValType::Char => Self::Char,
+ PrimitiveValType::String => Self::String,
+ }
+ }
+}
+
+impl From<&Refinement<'_>> for u32 {
+ fn from(r: &Refinement) -> Self {
+ match r {
+ Refinement::Index(..) => unreachable!("should be resolved by now"),
+ Refinement::Resolved(i) => *i,
+ }
+ }
+}
+
+impl From<&ItemSigKind<'_>> for wasm_encoder::ComponentTypeRef {
+ fn from(k: &ItemSigKind) -> Self {
+ match k {
+ ItemSigKind::Component(c) => Self::Component(c.into()),
+ ItemSigKind::CoreModule(m) => Self::Module(m.into()),
+ ItemSigKind::Instance(i) => Self::Instance(i.into()),
+ ItemSigKind::Value(v) => Self::Value((&v.0).into()),
+ ItemSigKind::Func(f) => Self::Func(f.into()),
+ ItemSigKind::Type(TypeBounds::Eq(t)) => {
+ Self::Type(wasm_encoder::TypeBounds::Eq, (*t).into())
+ }
+ }
+ }
+}
+
+impl From<&ComponentType<'_>> for wasm_encoder::ComponentType {
+ fn from(ty: &ComponentType) -> Self {
+ let mut encoded = wasm_encoder::ComponentType::new();
+
+ for decl in &ty.decls {
+ match decl {
+ ComponentTypeDecl::CoreType(t) => {
+ encode_core_type(encoded.core_type(), &t.def);
+ }
+ ComponentTypeDecl::Type(t) => {
+ encode_type(encoded.ty(), &t.def);
+ }
+ ComponentTypeDecl::Alias(a) => {
+ encoded.alias((&a.target).into());
+ }
+ ComponentTypeDecl::Import(i) => {
+ encoded.import(i.name, i.url.unwrap_or(""), (&i.item.kind).into());
+ }
+ ComponentTypeDecl::Export(e) => {
+ encoded.export(e.name, e.url.unwrap_or(""), (&e.item.kind).into());
+ }
+ }
+ }
+
+ encoded
+ }
+}
+
+impl From<&InstanceType<'_>> for wasm_encoder::InstanceType {
+ fn from(ty: &InstanceType) -> Self {
+ let mut encoded = wasm_encoder::InstanceType::new();
+
+ for decl in &ty.decls {
+ match decl {
+ InstanceTypeDecl::CoreType(t) => {
+ encode_core_type(encoded.core_type(), &t.def);
+ }
+ InstanceTypeDecl::Type(t) => {
+ encode_type(encoded.ty(), &t.def);
+ }
+ InstanceTypeDecl::Alias(a) => {
+ encoded.alias((&a.target).into());
+ }
+ InstanceTypeDecl::Export(e) => {
+ encoded.export(e.name, e.url.unwrap_or(""), (&e.item.kind).into());
+ }
+ }
+ }
+
+ encoded
+ }
+}
+
+impl From<&ModuleType<'_>> for wasm_encoder::ModuleType {
+ fn from(ty: &ModuleType) -> Self {
+ let mut encoded = wasm_encoder::ModuleType::new();
+
+ for decl in &ty.decls {
+ match decl {
+ ModuleTypeDecl::Type(t) => match &t.def {
+ core::TypeDef::Func(f) => encoded.ty().function(
+ f.params.iter().map(|(_, _, ty)| (*ty).into()),
+ f.results.iter().copied().map(Into::into),
+ ),
+ core::TypeDef::Struct(_) | core::TypeDef::Array(_) => {
+ todo!("encoding of GC proposal types not yet implemented")
+ }
+ },
+ ModuleTypeDecl::Alias(a) => match &a.target {
+ AliasTarget::Outer {
+ outer,
+ index,
+ kind: ComponentOuterAliasKind::CoreType,
+ } => {
+ encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index));
+ }
+ _ => unreachable!("only outer type aliases are supported"),
+ },
+ ModuleTypeDecl::Import(i) => {
+ encoded.import(i.module, i.field, (&i.item.kind).into());
+ }
+ ModuleTypeDecl::Export(name, item) => {
+ encoded.export(name, (&item.kind).into());
+ }
+ }
+ }
+
+ encoded
+ }
+}
+
+impl From<&InstantiationArgKind<'_>> for (wasm_encoder::ComponentExportKind, u32) {
+ fn from(kind: &InstantiationArgKind) -> Self {
+ match kind {
+ InstantiationArgKind::Item(i) => i.into(),
+ InstantiationArgKind::BundleOfExports(..) => unreachable!("should be expanded already"),
+ }
+ }
+}
+
+impl From<&ComponentExportKind<'_>> for (wasm_encoder::ComponentExportKind, u32) {
+ fn from(kind: &ComponentExportKind) -> Self {
+ match kind {
+ ComponentExportKind::CoreModule(m) => {
+ (wasm_encoder::ComponentExportKind::Module, m.idx.into())
+ }
+ ComponentExportKind::Func(f) => (wasm_encoder::ComponentExportKind::Func, f.idx.into()),
+ ComponentExportKind::Value(v) => {
+ (wasm_encoder::ComponentExportKind::Value, v.idx.into())
+ }
+ ComponentExportKind::Type(t) => (wasm_encoder::ComponentExportKind::Type, t.idx.into()),
+ ComponentExportKind::Component(c) => {
+ (wasm_encoder::ComponentExportKind::Component, c.idx.into())
+ }
+ ComponentExportKind::Instance(i) => {
+ (wasm_encoder::ComponentExportKind::Instance, i.idx.into())
+ }
+ }
+ }
+}
+
+impl From<ComponentOuterAliasKind> for wasm_encoder::ComponentOuterAliasKind {
+ fn from(kind: ComponentOuterAliasKind) -> Self {
+ match kind {
+ ComponentOuterAliasKind::CoreModule => Self::CoreModule,
+ ComponentOuterAliasKind::CoreType => Self::CoreType,
+ ComponentOuterAliasKind::Type => Self::Type,
+ ComponentOuterAliasKind::Component => Self::Component,
+ }
+ }
+}
+
+impl From<ComponentExportAliasKind> for wasm_encoder::ComponentExportKind {
+ fn from(kind: ComponentExportAliasKind) -> Self {
+ match kind {
+ ComponentExportAliasKind::CoreModule => Self::Module,
+ ComponentExportAliasKind::Func => Self::Func,
+ ComponentExportAliasKind::Value => Self::Value,
+ ComponentExportAliasKind::Type => Self::Type,
+ ComponentExportAliasKind::Component => Self::Component,
+ ComponentExportAliasKind::Instance => Self::Instance,
+ }
+ }
+}
+
+impl From<&CanonOpt<'_>> for wasm_encoder::CanonicalOption {
+ fn from(opt: &CanonOpt) -> Self {
+ match opt {
+ CanonOpt::StringUtf8 => Self::UTF8,
+ CanonOpt::StringUtf16 => Self::UTF16,
+ CanonOpt::StringLatin1Utf16 => Self::CompactUTF16,
+ CanonOpt::Memory(m) => Self::Memory(m.idx.into()),
+ CanonOpt::Realloc(f) => Self::Realloc(f.idx.into()),
+ CanonOpt::PostReturn(f) => Self::PostReturn(f.idx.into()),
+ }
+ }
+}
+
+impl<'a> From<&AliasTarget<'a>> for wasm_encoder::Alias<'a> {
+ fn from(target: &AliasTarget<'a>) -> Self {
+ match target {
+ AliasTarget::Export {
+ instance,
+ name,
+ kind,
+ } => wasm_encoder::Alias::InstanceExport {
+ instance: (*instance).into(),
+ kind: (*kind).into(),
+ name,
+ },
+ AliasTarget::CoreExport {
+ instance,
+ name,
+ kind,
+ } => wasm_encoder::Alias::CoreInstanceExport {
+ instance: (*instance).into(),
+ kind: (*kind).into(),
+ name,
+ },
+ AliasTarget::Outer { outer, index, kind } => wasm_encoder::Alias::Outer {
+ count: (*outer).into(),
+ kind: (*kind).into(),
+ index: (*index).into(),
+ },
+ }
+ }
+}
diff --git a/third_party/rust/wast/src/component/component.rs b/third_party/rust/wast/src/component/component.rs
new file mode 100644
index 0000000000..8424e083b8
--- /dev/null
+++ b/third_party/rust/wast/src/component/component.rs
@@ -0,0 +1,313 @@
+use crate::annotation;
+use crate::component::*;
+use crate::kw;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::Index;
+use crate::token::{Id, NameAnnotation, Span};
+
+/// A parsed WebAssembly component module.
+#[derive(Debug)]
+pub struct Component<'a> {
+ /// Where this `component` was defined
+ pub span: Span,
+ /// An optional identifier this component is known by
+ pub id: Option<Id<'a>>,
+ /// An optional `@name` annotation for this component
+ pub name: Option<NameAnnotation<'a>>,
+ /// What kind of component this was parsed as.
+ pub kind: ComponentKind<'a>,
+}
+
+/// The different kinds of ways to define a component.
+#[derive(Debug)]
+pub enum ComponentKind<'a> {
+ /// A component defined in the textual s-expression format.
+ Text(Vec<ComponentField<'a>>),
+ /// A component that had its raw binary bytes defined via the `binary`
+ /// directive.
+ Binary(Vec<&'a [u8]>),
+}
+
+impl<'a> Component<'a> {
+ /// Performs a name resolution pass on this [`Component`], resolving all
+ /// symbolic names to indices.
+ ///
+ /// The WAT format contains a number of shorthands to make it easier to
+ /// write, such as inline exports, inline imports, inline type definitions,
+ /// etc. Additionally it allows using symbolic names such as `$foo` instead
+ /// of using indices. This module will postprocess an AST to remove all of
+ /// this syntactic sugar, preparing the AST for binary emission. This is
+ /// where expansion and name resolution happens.
+ ///
+ /// This function will mutate the AST of this [`Component`] and replace all
+ /// [`Index`](crate::token::Index) arguments with `Index::Num`. This will
+ /// also expand inline exports/imports listed on fields and handle various
+ /// other shorthands of the text format.
+ ///
+ /// If successful the AST was modified to be ready for binary encoding.
+ ///
+ /// # Errors
+ ///
+ /// If an error happens during resolution, such a name resolution error or
+ /// items are found in the wrong order, then an error is returned.
+ pub fn resolve(&mut self) -> std::result::Result<(), crate::Error> {
+ match &mut self.kind {
+ ComponentKind::Text(fields) => {
+ crate::component::expand::expand(fields);
+ }
+ ComponentKind::Binary(_) => {}
+ }
+ crate::component::resolve::resolve(self)
+ }
+
+ /// Encodes this [`Component`] to its binary form.
+ ///
+ /// This function will take the textual representation in [`Component`] and
+ /// perform all steps necessary to convert it to a binary WebAssembly
+ /// component, suitable for writing to a `*.wasm` file. This function may
+ /// internally modify the [`Component`], for example:
+ ///
+ /// * Name resolution is performed to ensure that `Index::Id` isn't present
+ /// anywhere in the AST.
+ ///
+ /// * Inline shorthands such as imports/exports/types are all expanded to be
+ /// dedicated fields of the component.
+ ///
+ /// * Component fields may be shuffled around to preserve index ordering from
+ /// expansions.
+ ///
+ /// After all of this expansion has happened the component will be converted to
+ /// its binary form and returned as a `Vec<u8>`. This is then suitable to
+ /// hand off to other wasm runtimes and such.
+ ///
+ /// # Errors
+ ///
+ /// This function can return an error for name resolution errors and other
+ /// expansion-related errors.
+ pub fn encode(&mut self) -> std::result::Result<Vec<u8>, crate::Error> {
+ self.resolve()?;
+ Ok(crate::component::binary::encode(self))
+ }
+
+ pub(crate) fn validate(&self, parser: Parser<'_>) -> Result<()> {
+ let mut starts = 0;
+ if let ComponentKind::Text(fields) = &self.kind {
+ for item in fields.iter() {
+ if let ComponentField::Start(_) = item {
+ starts += 1;
+ }
+ }
+ }
+ if starts > 1 {
+ return Err(parser.error("multiple start sections found"));
+ }
+ Ok(())
+ }
+}
+
+impl<'a> Parse<'a> for Component<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let _r = parser.register_annotation("custom");
+
+ let span = parser.parse::<kw::component>()?.0;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+
+ let kind = if parser.peek::<kw::binary>() {
+ parser.parse::<kw::binary>()?;
+ let mut data = Vec::new();
+ while !parser.is_empty() {
+ data.push(parser.parse()?);
+ }
+ ComponentKind::Binary(data)
+ } else {
+ ComponentKind::Text(ComponentField::parse_remaining(parser)?)
+ };
+ Ok(Component {
+ span,
+ id,
+ name,
+ kind,
+ })
+ }
+}
+
+/// A listing of all possible fields that can make up a WebAssembly component.
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub enum ComponentField<'a> {
+ CoreModule(CoreModule<'a>),
+ CoreInstance(CoreInstance<'a>),
+ CoreType(CoreType<'a>),
+ Component(NestedComponent<'a>),
+ Instance(Instance<'a>),
+ Alias(Alias<'a>),
+ Type(Type<'a>),
+ CanonicalFunc(CanonicalFunc<'a>),
+ CoreFunc(CoreFunc<'a>), // Supports inverted forms of other items
+ Func(Func<'a>), // Supports inverted forms of other items
+ Start(Start<'a>),
+ Import(ComponentImport<'a>),
+ Export(ComponentExport<'a>),
+ Custom(Custom<'a>),
+}
+
+impl<'a> ComponentField<'a> {
+ fn parse_remaining(parser: Parser<'a>) -> Result<Vec<ComponentField>> {
+ let mut fields = Vec::new();
+ while !parser.is_empty() {
+ fields.push(parser.parens(ComponentField::parse)?);
+ }
+ Ok(fields)
+ }
+}
+
+impl<'a> Parse<'a> for ComponentField<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<kw::core>() {
+ if parser.peek2::<kw::module>() {
+ return Ok(Self::CoreModule(parser.parse()?));
+ }
+ if parser.peek2::<kw::instance>() {
+ return Ok(Self::CoreInstance(parser.parse()?));
+ }
+ if parser.peek2::<kw::r#type>() {
+ return Ok(Self::CoreType(parser.parse()?));
+ }
+ if parser.peek2::<kw::func>() {
+ return Ok(Self::CoreFunc(parser.parse()?));
+ }
+ } else {
+ if parser.peek::<kw::component>() {
+ return Ok(Self::Component(parser.parse()?));
+ }
+ if parser.peek::<kw::instance>() {
+ return Ok(Self::Instance(parser.parse()?));
+ }
+ if parser.peek::<kw::alias>() {
+ return Ok(Self::Alias(parser.parse()?));
+ }
+ if parser.peek::<kw::r#type>() {
+ return Ok(Self::Type(parser.parse()?));
+ }
+ if parser.peek::<kw::import>() {
+ return Ok(Self::Import(parser.parse()?));
+ }
+ if parser.peek::<kw::func>() {
+ return Ok(Self::Func(parser.parse()?));
+ }
+ if parser.peek::<kw::export>() {
+ return Ok(Self::Export(parser.parse()?));
+ }
+ if parser.peek::<kw::start>() {
+ return Ok(Self::Start(parser.parse()?));
+ }
+ if parser.peek::<annotation::custom>() {
+ return Ok(Self::Custom(parser.parse()?));
+ }
+ }
+ Err(parser.error("expected valid component field"))
+ }
+}
+
+/// A function to call at instantiation time.
+#[derive(Debug)]
+pub struct Start<'a> {
+ /// The function to call.
+ pub func: Index<'a>,
+ /// The arguments to pass to the function.
+ pub args: Vec<ItemRef<'a, kw::value>>,
+ /// Names of the result values.
+ pub results: Vec<Option<Id<'a>>>,
+}
+
+impl<'a> Parse<'a> for Start<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::start>()?;
+ let func = parser.parse()?;
+ let mut args = Vec::new();
+ while !parser.is_empty() && !parser.peek2::<kw::result>() {
+ args.push(parser.parens(|parser| parser.parse())?);
+ }
+
+ let mut results = Vec::new();
+ while !parser.is_empty() && parser.peek2::<kw::result>() {
+ results.push(parser.parens(|parser| {
+ parser.parse::<kw::result>()?;
+ parser.parens(|parser| {
+ parser.parse::<kw::value>()?;
+ parser.parse()
+ })
+ })?);
+ }
+
+ Ok(Start {
+ func,
+ args,
+ results,
+ })
+ }
+}
+
+/// A nested WebAssembly component.
+#[derive(Debug)]
+pub struct NestedComponent<'a> {
+ /// Where this `component` was defined
+ pub span: Span,
+ /// An optional identifier this component is known by
+ pub id: Option<Id<'a>>,
+ /// An optional `@name` annotation for this component
+ 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 component this was parsed as.
+ pub kind: NestedComponentKind<'a>,
+}
+
+/// The different kinds of ways to define a nested component.
+#[derive(Debug)]
+pub enum NestedComponentKind<'a> {
+ /// This is actually an inline import of a component
+ Import {
+ /// The information about where this is being imported from.
+ import: InlineImport<'a>,
+ /// The type of component being imported.
+ ty: ComponentTypeUse<'a, ComponentType<'a>>,
+ },
+ /// The component is defined inline as a local definition with its fields
+ /// listed here.
+ Inline(Vec<ComponentField<'a>>),
+}
+
+impl<'a> Parse<'a> for NestedComponent<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+
+ let span = parser.parse::<kw::component>()?.0;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let exports = parser.parse()?;
+
+ let kind = if let Some(import) = parser.parse()? {
+ NestedComponentKind::Import {
+ import,
+ ty: parser.parse()?,
+ }
+ } else {
+ let mut fields = Vec::new();
+ while !parser.is_empty() {
+ fields.push(parser.parens(|p| p.parse())?);
+ }
+ NestedComponentKind::Inline(fields)
+ };
+
+ Ok(NestedComponent {
+ span,
+ id,
+ name,
+ exports,
+ kind,
+ })
+ }
+}
diff --git a/third_party/rust/wast/src/component/custom.rs b/third_party/rust/wast/src/component/custom.rs
new file mode 100644
index 0000000000..b17a7fafb4
--- /dev/null
+++ b/third_party/rust/wast/src/component/custom.rs
@@ -0,0 +1,28 @@
+use crate::annotation;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::Span;
+
+/// A custom section within a component.
+#[derive(Debug)]
+pub struct Custom<'a> {
+ /// Where this `@custom` was defined.
+ pub span: Span,
+
+ /// Name of the custom section.
+ pub name: &'a str,
+
+ /// Payload of this custom section.
+ pub data: Vec<&'a [u8]>,
+}
+
+impl<'a> Parse<'a> for Custom<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<annotation::custom>()?.0;
+ let name = parser.parse()?;
+ let mut data = Vec::new();
+ while !parser.is_empty() {
+ data.push(parser.parse()?);
+ }
+ Ok(Self { span, name, data })
+ }
+}
diff --git a/third_party/rust/wast/src/component/expand.rs b/third_party/rust/wast/src/component/expand.rs
new file mode 100644
index 0000000000..2bf0b529e4
--- /dev/null
+++ b/third_party/rust/wast/src/component/expand.rs
@@ -0,0 +1,859 @@
+use crate::component::*;
+use crate::core;
+use crate::gensym;
+use crate::kw;
+use crate::token::Id;
+use crate::token::{Index, Span};
+use std::collections::HashMap;
+use std::mem;
+
+/// Performs an AST "expansion" pass over the component fields provided.
+///
+/// This expansion is intended to desugar the AST from various parsed constructs
+/// to bits and bobs amenable for name resolution as well as binary encoding.
+/// For example `(import "i" (func))` is split into a type definition followed by
+/// the import referencing that type definition.
+///
+/// Most forms of AST expansion happen in this file and afterwards the AST will
+/// be handed to the name resolution pass which will convert `Index::Id` to
+/// `Index::Num` wherever it's found.
+pub fn expand(fields: &mut Vec<ComponentField<'_>>) {
+ Expander::default().expand_component_fields(fields)
+}
+
+enum AnyType<'a> {
+ Core(CoreType<'a>),
+ Component(Type<'a>),
+}
+
+impl<'a> From<AnyType<'a>> for ComponentTypeDecl<'a> {
+ fn from(t: AnyType<'a>) -> Self {
+ match t {
+ AnyType::Core(t) => Self::CoreType(t),
+ AnyType::Component(t) => Self::Type(t),
+ }
+ }
+}
+
+impl<'a> From<AnyType<'a>> for InstanceTypeDecl<'a> {
+ fn from(t: AnyType<'a>) -> Self {
+ match t {
+ AnyType::Core(t) => Self::CoreType(t),
+ AnyType::Component(t) => Self::Type(t),
+ }
+ }
+}
+
+impl<'a> From<AnyType<'a>> for ComponentField<'a> {
+ fn from(t: AnyType<'a>) -> Self {
+ match t {
+ AnyType::Core(t) => Self::CoreType(t),
+ AnyType::Component(t) => Self::Type(t),
+ }
+ }
+}
+
+#[derive(Default)]
+struct Expander<'a> {
+ /// Fields, during processing, which should be prepended to the
+ /// currently-being-processed field. This should always be empty after
+ /// processing is complete.
+ types_to_prepend: Vec<AnyType<'a>>,
+ component_fields_to_prepend: Vec<ComponentField<'a>>,
+
+ /// Fields that are appended to the end of the module once everything has
+ /// finished.
+ component_fields_to_append: Vec<ComponentField<'a>>,
+}
+
+impl<'a> Expander<'a> {
+ fn expand_component_fields(&mut self, fields: &mut Vec<ComponentField<'a>>) {
+ let mut cur = 0;
+ while cur < fields.len() {
+ self.expand_field(&mut fields[cur]);
+ let amt = self.types_to_prepend.len() + self.component_fields_to_prepend.len();
+ fields.splice(cur..cur, self.component_fields_to_prepend.drain(..));
+ fields.splice(cur..cur, self.types_to_prepend.drain(..).map(Into::into));
+ cur += 1 + amt;
+ }
+ fields.append(&mut self.component_fields_to_append);
+ }
+
+ fn expand_decls<T>(&mut self, decls: &mut Vec<T>, expand: fn(&mut Self, &mut T))
+ where
+ T: From<AnyType<'a>>,
+ {
+ let mut cur = 0;
+ while cur < decls.len() {
+ expand(self, &mut decls[cur]);
+ assert!(self.component_fields_to_prepend.is_empty());
+ assert!(self.component_fields_to_append.is_empty());
+ let amt = self.types_to_prepend.len();
+ decls.splice(cur..cur, self.types_to_prepend.drain(..).map(From::from));
+ cur += 1 + amt;
+ }
+ }
+
+ fn expand_field(&mut self, item: &mut ComponentField<'a>) {
+ let expanded = match item {
+ ComponentField::CoreModule(m) => self.expand_core_module(m),
+ ComponentField::CoreInstance(i) => {
+ self.expand_core_instance(i);
+ None
+ }
+ ComponentField::CoreType(t) => {
+ self.expand_core_type(t);
+ None
+ }
+ ComponentField::Component(c) => self.expand_nested_component(c),
+ ComponentField::Instance(i) => self.expand_instance(i),
+ ComponentField::Type(t) => {
+ self.expand_type(t);
+ None
+ }
+ ComponentField::CanonicalFunc(f) => {
+ self.expand_canonical_func(f);
+ None
+ }
+ ComponentField::CoreFunc(f) => self.expand_core_func(f),
+ ComponentField::Func(f) => self.expand_func(f),
+ ComponentField::Import(i) => {
+ self.expand_item_sig(&mut i.item);
+ None
+ }
+ ComponentField::Export(e) => {
+ if let Some(sig) = &mut e.ty {
+ self.expand_item_sig(&mut sig.0);
+ }
+ None
+ }
+ ComponentField::Start(_) | ComponentField::Alias(_) | ComponentField::Custom(_) => None,
+ };
+
+ if let Some(expanded) = expanded {
+ *item = expanded;
+ }
+ }
+
+ fn expand_core_module(&mut self, module: &mut CoreModule<'a>) -> Option<ComponentField<'a>> {
+ for (name, url) in module.exports.names.drain(..) {
+ let id = gensym::fill(module.span, &mut module.id);
+ self.component_fields_to_append
+ .push(ComponentField::Export(ComponentExport {
+ span: module.span,
+ id: None,
+ debug_name: None,
+ name,
+ url,
+ kind: ComponentExportKind::module(module.span, id),
+ ty: None,
+ }));
+ }
+ match &mut module.kind {
+ // inline modules are expanded later during resolution
+ CoreModuleKind::Inline { .. } => None,
+ CoreModuleKind::Import { import, ty } => {
+ let idx = self.expand_core_type_use(ty);
+ Some(ComponentField::Import(ComponentImport {
+ span: module.span,
+ name: import.name,
+ url: import.url,
+ item: ItemSig {
+ span: module.span,
+ id: module.id,
+ name: None,
+ kind: ItemSigKind::CoreModule(CoreTypeUse::Ref(idx)),
+ },
+ }))
+ }
+ }
+ }
+
+ fn expand_core_instance(&mut self, instance: &mut CoreInstance<'a>) {
+ match &mut instance.kind {
+ CoreInstanceKind::Instantiate { args, .. } => {
+ for arg in args {
+ self.expand_core_instantiation_arg(&mut arg.kind);
+ }
+ }
+ CoreInstanceKind::BundleOfExports { .. } => {}
+ }
+ }
+
+ fn expand_nested_component(
+ &mut self,
+ component: &mut NestedComponent<'a>,
+ ) -> Option<ComponentField<'a>> {
+ for (name, url) in component.exports.names.drain(..) {
+ let id = gensym::fill(component.span, &mut component.id);
+ self.component_fields_to_append
+ .push(ComponentField::Export(ComponentExport {
+ span: component.span,
+ id: None,
+ debug_name: None,
+ name,
+ url,
+ kind: ComponentExportKind::component(component.span, id),
+ ty: None,
+ }));
+ }
+ match &mut component.kind {
+ NestedComponentKind::Inline(fields) => {
+ expand(fields);
+ None
+ }
+ NestedComponentKind::Import { import, ty } => {
+ let idx = self.expand_component_type_use(ty);
+ Some(ComponentField::Import(ComponentImport {
+ span: component.span,
+ name: import.name,
+ url: import.url,
+ item: ItemSig {
+ span: component.span,
+ id: component.id,
+ name: None,
+ kind: ItemSigKind::Component(ComponentTypeUse::Ref(idx)),
+ },
+ }))
+ }
+ }
+ }
+
+ fn expand_instance(&mut self, instance: &mut Instance<'a>) -> Option<ComponentField<'a>> {
+ for (name, url) in instance.exports.names.drain(..) {
+ let id = gensym::fill(instance.span, &mut instance.id);
+ self.component_fields_to_append
+ .push(ComponentField::Export(ComponentExport {
+ span: instance.span,
+ id: None,
+ debug_name: None,
+ name,
+ url,
+ kind: ComponentExportKind::instance(instance.span, id),
+ ty: None,
+ }));
+ }
+ match &mut instance.kind {
+ InstanceKind::Import { import, ty } => {
+ let idx = self.expand_component_type_use(ty);
+ Some(ComponentField::Import(ComponentImport {
+ span: instance.span,
+ name: import.name,
+ url: import.url,
+ item: ItemSig {
+ span: instance.span,
+ id: instance.id,
+ name: None,
+ kind: ItemSigKind::Instance(ComponentTypeUse::Ref(idx)),
+ },
+ }))
+ }
+ InstanceKind::Instantiate { args, .. } => {
+ for arg in args {
+ self.expand_instantiation_arg(&mut arg.kind);
+ }
+ None
+ }
+ InstanceKind::BundleOfExports { .. } => None,
+ }
+ }
+
+ fn expand_canonical_func(&mut self, func: &mut CanonicalFunc<'a>) {
+ match &mut func.kind {
+ CanonicalFuncKind::Lift { ty, .. } => {
+ self.expand_component_type_use(ty);
+ }
+ CanonicalFuncKind::Lower(_) => {}
+ }
+ }
+
+ fn expand_core_func(&mut self, func: &mut CoreFunc<'a>) -> Option<ComponentField<'a>> {
+ match &mut func.kind {
+ CoreFuncKind::Alias(a) => Some(ComponentField::Alias(Alias {
+ span: func.span,
+ id: func.id,
+ name: func.name,
+ target: AliasTarget::CoreExport {
+ instance: a.instance,
+ name: a.name,
+ kind: core::ExportKind::Func,
+ },
+ })),
+ CoreFuncKind::Lower(info) => Some(ComponentField::CanonicalFunc(CanonicalFunc {
+ span: func.span,
+ id: func.id,
+ name: func.name,
+ kind: CanonicalFuncKind::Lower(mem::take(info)),
+ })),
+ }
+ }
+
+ fn expand_func(&mut self, func: &mut Func<'a>) -> Option<ComponentField<'a>> {
+ for (name, url) in func.exports.names.drain(..) {
+ let id = gensym::fill(func.span, &mut func.id);
+ self.component_fields_to_append
+ .push(ComponentField::Export(ComponentExport {
+ span: func.span,
+ id: None,
+ debug_name: None,
+ name,
+ url,
+ kind: ComponentExportKind::func(func.span, id),
+ ty: None,
+ }));
+ }
+ match &mut func.kind {
+ FuncKind::Import { import, ty } => {
+ let idx = self.expand_component_type_use(ty);
+ Some(ComponentField::Import(ComponentImport {
+ span: func.span,
+ name: import.name,
+ url: import.url,
+ item: ItemSig {
+ span: func.span,
+ id: func.id,
+ name: None,
+ kind: ItemSigKind::Func(ComponentTypeUse::Ref(idx)),
+ },
+ }))
+ }
+ FuncKind::Lift { ty, info } => {
+ let idx = self.expand_component_type_use(ty);
+ Some(ComponentField::CanonicalFunc(CanonicalFunc {
+ span: func.span,
+ id: func.id,
+ name: func.name,
+ kind: CanonicalFuncKind::Lift {
+ ty: ComponentTypeUse::Ref(idx),
+ info: mem::take(info),
+ },
+ }))
+ }
+ FuncKind::Alias(a) => Some(ComponentField::Alias(Alias {
+ span: func.span,
+ id: func.id,
+ name: func.name,
+ target: AliasTarget::Export {
+ instance: a.instance,
+ name: a.name,
+ kind: ComponentExportAliasKind::Func,
+ },
+ })),
+ }
+ }
+
+ fn expand_core_type(&mut self, field: &mut CoreType<'a>) {
+ match &mut field.def {
+ CoreTypeDef::Def(_) => {}
+ CoreTypeDef::Module(m) => self.expand_module_ty(m),
+ }
+
+ let id = gensym::fill(field.span, &mut field.id);
+ let index = Index::Id(id);
+ match &field.def {
+ CoreTypeDef::Def(_) => {}
+ CoreTypeDef::Module(t) => t.key().insert(self, index),
+ }
+ }
+
+ fn expand_type(&mut self, field: &mut Type<'a>) {
+ match &mut field.def {
+ TypeDef::Defined(d) => self.expand_defined_ty(d),
+ TypeDef::Func(f) => self.expand_func_ty(f),
+ TypeDef::Component(c) => self.expand_component_ty(c),
+ TypeDef::Instance(i) => self.expand_instance_ty(i),
+ }
+
+ let id = gensym::fill(field.span, &mut field.id);
+ let index = Index::Id(id);
+ match &field.def {
+ TypeDef::Defined(t) => t.key().insert(self, index),
+ TypeDef::Func(t) => t.key().insert(self, index),
+ TypeDef::Component(t) => t.key().insert(self, index),
+ TypeDef::Instance(t) => t.key().insert(self, index),
+ }
+ for (name, url) in field.exports.names.drain(..) {
+ self.component_fields_to_append
+ .push(ComponentField::Export(ComponentExport {
+ span: field.span,
+ id: None,
+ debug_name: None,
+ name,
+ url,
+ kind: ComponentExportKind::ty(field.span, id),
+ ty: None,
+ }));
+ }
+ }
+
+ fn expand_func_ty(&mut self, ty: &mut ComponentFunctionType<'a>) {
+ for param in ty.params.iter_mut() {
+ self.expand_component_val_ty(&mut param.ty);
+ }
+
+ for result in ty.results.iter_mut() {
+ self.expand_component_val_ty(&mut result.ty);
+ }
+ }
+
+ fn expand_module_ty(&mut self, ty: &mut ModuleType<'a>) {
+ use crate::core::resolve::types::{FuncKey, TypeKey, TypeReference};
+
+ // Note that this is a custom implementation from everything else in
+ // this file since this is using core wasm types instead of component
+ // types, so a small part of the core wasm expansion process is
+ // inlined here to handle the `TypeUse` from core wasm.
+
+ let mut func_type_to_idx = HashMap::new();
+ let mut to_prepend = Vec::new();
+ let mut i = 0;
+ while i < ty.decls.len() {
+ match &mut ty.decls[i] {
+ ModuleTypeDecl::Type(ty) => match &ty.def {
+ core::TypeDef::Func(f) => {
+ let id = gensym::fill(ty.span, &mut ty.id);
+ func_type_to_idx.insert(f.key(), Index::Id(id));
+ }
+ core::TypeDef::Struct(_) => {}
+ core::TypeDef::Array(_) => {}
+ },
+ ModuleTypeDecl::Alias(_) => {}
+ ModuleTypeDecl::Import(ty) => {
+ expand_sig(&mut ty.item, &mut to_prepend, &mut func_type_to_idx);
+ }
+ ModuleTypeDecl::Export(_, item) => {
+ expand_sig(item, &mut to_prepend, &mut func_type_to_idx);
+ }
+ }
+ ty.decls.splice(i..i, to_prepend.drain(..));
+ i += 1;
+ }
+
+ fn expand_sig<'a>(
+ item: &mut core::ItemSig<'a>,
+ to_prepend: &mut Vec<ModuleTypeDecl<'a>>,
+ func_type_to_idx: &mut HashMap<FuncKey<'a>, Index<'a>>,
+ ) {
+ match &mut item.kind {
+ core::ItemKind::Func(t) | core::ItemKind::Tag(core::TagType::Exception(t)) => {
+ // If the index is already filled in then this is skipped
+ if t.index.is_some() {
+ return;
+ }
+
+ // Otherwise the inline type information is used to
+ // generate a type into this module if necessary. If the
+ // function type already exists we reuse the same key,
+ // otherwise a fresh type definition is created and we use
+ // that one instead.
+ let ty = t.inline.take().unwrap_or_default();
+ let key = ty.key();
+ if let Some(idx) = func_type_to_idx.get(&key) {
+ t.index = Some(*idx);
+ return;
+ }
+ let id = gensym::gen(item.span);
+ to_prepend.push(ModuleTypeDecl::Type(core::Type {
+ span: item.span,
+ id: Some(id),
+ name: None,
+ def: key.to_def(item.span),
+ parent: None,
+ }));
+ let idx = Index::Id(id);
+ t.index = Some(idx);
+ }
+ core::ItemKind::Global(_)
+ | core::ItemKind::Table(_)
+ | core::ItemKind::Memory(_) => {}
+ }
+ }
+ }
+
+ fn expand_component_ty(&mut self, ty: &mut ComponentType<'a>) {
+ Expander::default().expand_decls(&mut ty.decls, |e, decl| match decl {
+ ComponentTypeDecl::CoreType(t) => e.expand_core_type(t),
+ ComponentTypeDecl::Type(t) => e.expand_type(t),
+ ComponentTypeDecl::Alias(_) => {}
+ ComponentTypeDecl::Export(t) => e.expand_item_sig(&mut t.item),
+ ComponentTypeDecl::Import(t) => e.expand_item_sig(&mut t.item),
+ })
+ }
+
+ fn expand_instance_ty(&mut self, ty: &mut InstanceType<'a>) {
+ Expander::default().expand_decls(&mut ty.decls, |e, decl| match decl {
+ InstanceTypeDecl::CoreType(t) => e.expand_core_type(t),
+ InstanceTypeDecl::Type(t) => e.expand_type(t),
+ InstanceTypeDecl::Alias(_) => {}
+ InstanceTypeDecl::Export(t) => e.expand_item_sig(&mut t.item),
+ })
+ }
+
+ fn expand_item_sig(&mut self, ext: &mut ItemSig<'a>) {
+ match &mut ext.kind {
+ ItemSigKind::CoreModule(t) => {
+ self.expand_core_type_use(t);
+ }
+ ItemSigKind::Func(t) => {
+ self.expand_component_type_use(t);
+ }
+ ItemSigKind::Component(t) => {
+ self.expand_component_type_use(t);
+ }
+ ItemSigKind::Instance(t) => {
+ self.expand_component_type_use(t);
+ }
+ ItemSigKind::Value(t) => {
+ self.expand_component_val_ty(&mut t.0);
+ }
+ ItemSigKind::Type(_) => {}
+ }
+ }
+
+ fn expand_defined_ty(&mut self, ty: &mut ComponentDefinedType<'a>) {
+ match ty {
+ ComponentDefinedType::Primitive(_)
+ | ComponentDefinedType::Flags(_)
+ | ComponentDefinedType::Enum(_) => {}
+ ComponentDefinedType::Record(r) => {
+ for field in r.fields.iter_mut() {
+ self.expand_component_val_ty(&mut field.ty);
+ }
+ }
+ ComponentDefinedType::Variant(v) => {
+ for case in v.cases.iter_mut() {
+ if let Some(ty) = &mut case.ty {
+ self.expand_component_val_ty(ty);
+ }
+ }
+ }
+ ComponentDefinedType::List(t) => {
+ self.expand_component_val_ty(&mut t.element);
+ }
+ ComponentDefinedType::Tuple(t) => {
+ for field in t.fields.iter_mut() {
+ self.expand_component_val_ty(field);
+ }
+ }
+ ComponentDefinedType::Union(u) => {
+ for ty in u.types.iter_mut() {
+ self.expand_component_val_ty(ty);
+ }
+ }
+ ComponentDefinedType::Option(t) => {
+ self.expand_component_val_ty(&mut t.element);
+ }
+ ComponentDefinedType::Result(r) => {
+ if let Some(ty) = &mut r.ok {
+ self.expand_component_val_ty(ty);
+ }
+
+ if let Some(ty) = &mut r.err {
+ self.expand_component_val_ty(ty);
+ }
+ }
+ }
+ }
+
+ fn expand_component_val_ty(&mut self, ty: &mut ComponentValType<'a>) {
+ let inline = match ty {
+ ComponentValType::Inline(ComponentDefinedType::Primitive(_))
+ | ComponentValType::Ref(_) => return,
+ ComponentValType::Inline(inline) => {
+ self.expand_defined_ty(inline);
+ mem::take(inline)
+ }
+ };
+ // If this inline type has already been defined within this context
+ // then reuse the previously defined type to avoid injecting too many
+ // types into the type index space.
+ if let Some(idx) = inline.key().lookup(self) {
+ *ty = ComponentValType::Ref(idx);
+ return;
+ }
+
+ // And if this type isn't already defined we append it to the index
+ // space with a fresh and unique name.
+ let span = Span::from_offset(0); // FIXME(#613): don't manufacture
+ let id = gensym::gen(span);
+
+ self.types_to_prepend.push(inline.into_any_type(span, id));
+
+ let idx = Index::Id(id);
+ *ty = ComponentValType::Ref(idx);
+ }
+
+ fn expand_core_type_use<T>(
+ &mut self,
+ item: &mut CoreTypeUse<'a, T>,
+ ) -> CoreItemRef<'a, kw::r#type>
+ where
+ T: TypeReference<'a>,
+ {
+ let span = Span::from_offset(0); // FIXME(#613): don't manufacture
+ let mut inline = match mem::take(item) {
+ // If this type-use was already a reference to an existing type
+ // then we put it back the way it was and return the corresponding
+ // index.
+ CoreTypeUse::Ref(idx) => {
+ *item = CoreTypeUse::Ref(idx.clone());
+ return idx;
+ }
+
+ // ... otherwise with an inline type definition we go into
+ // processing below.
+ CoreTypeUse::Inline(inline) => inline,
+ };
+ inline.expand(self);
+
+ // If this inline type has already been defined within this context
+ // then reuse the previously defined type to avoid injecting too many
+ // types into the type index space.
+ if let Some(idx) = inline.key().lookup(self) {
+ let ret = CoreItemRef {
+ idx,
+ kind: kw::r#type(span),
+ export_name: None,
+ };
+ *item = CoreTypeUse::Ref(ret.clone());
+ return ret;
+ }
+
+ // And if this type isn't already defined we append it to the index
+ // space with a fresh and unique name.
+ let id = gensym::gen(span);
+
+ self.types_to_prepend.push(inline.into_any_type(span, id));
+
+ let idx = Index::Id(id);
+ let ret = CoreItemRef {
+ idx,
+ kind: kw::r#type(span),
+ export_name: None,
+ };
+
+ *item = CoreTypeUse::Ref(ret.clone());
+ ret
+ }
+
+ fn expand_component_type_use<T>(
+ &mut self,
+ item: &mut ComponentTypeUse<'a, T>,
+ ) -> ItemRef<'a, kw::r#type>
+ where
+ T: TypeReference<'a>,
+ {
+ let span = Span::from_offset(0); // FIXME(#613): don't manufacture
+ let mut inline = match mem::take(item) {
+ // If this type-use was already a reference to an existing type
+ // then we put it back the way it was and return the corresponding
+ // index.
+ ComponentTypeUse::Ref(idx) => {
+ *item = ComponentTypeUse::Ref(idx.clone());
+ return idx;
+ }
+
+ // ... otherwise with an inline type definition we go into
+ // processing below.
+ ComponentTypeUse::Inline(inline) => inline,
+ };
+ inline.expand(self);
+
+ // If this inline type has already been defined within this context
+ // then reuse the previously defined type to avoid injecting too many
+ // types into the type index space.
+ if let Some(idx) = inline.key().lookup(self) {
+ let ret = ItemRef {
+ idx,
+ kind: kw::r#type(span),
+ export_names: Vec::new(),
+ };
+ *item = ComponentTypeUse::Ref(ret.clone());
+ return ret;
+ }
+
+ // And if this type isn't already defined we append it to the index
+ // space with a fresh and unique name.
+ let id = gensym::gen(span);
+
+ self.types_to_prepend.push(inline.into_any_type(span, id));
+
+ let idx = Index::Id(id);
+ let ret = ItemRef {
+ idx,
+ kind: kw::r#type(span),
+ export_names: Vec::new(),
+ };
+
+ *item = ComponentTypeUse::Ref(ret.clone());
+ ret
+ }
+
+ fn expand_core_instantiation_arg(&mut self, arg: &mut CoreInstantiationArgKind<'a>) {
+ let (span, exports) = match arg {
+ CoreInstantiationArgKind::Instance(_) => return,
+ CoreInstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)),
+ };
+ let id = gensym::gen(span);
+ self.component_fields_to_prepend
+ .push(ComponentField::CoreInstance(CoreInstance {
+ span,
+ id: Some(id),
+ name: None,
+ kind: CoreInstanceKind::BundleOfExports(exports),
+ }));
+ *arg = CoreInstantiationArgKind::Instance(CoreItemRef {
+ kind: kw::instance(span),
+ idx: Index::Id(id),
+ export_name: None,
+ });
+ }
+
+ fn expand_instantiation_arg(&mut self, arg: &mut InstantiationArgKind<'a>) {
+ let (span, exports) = match arg {
+ InstantiationArgKind::Item(_) => return,
+ InstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)),
+ };
+ let id = gensym::gen(span);
+ self.component_fields_to_prepend
+ .push(ComponentField::Instance(Instance {
+ span,
+ id: Some(id),
+ name: None,
+ exports: Default::default(),
+ kind: InstanceKind::BundleOfExports(exports),
+ }));
+ *arg = InstantiationArgKind::Item(ComponentExportKind::instance(span, id));
+ }
+}
+
+trait TypeReference<'a> {
+ type Key: TypeKey<'a>;
+ fn key(&self) -> Self::Key;
+ fn expand(&mut self, cx: &mut Expander<'a>);
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a>;
+}
+
+impl<'a> TypeReference<'a> for ComponentDefinedType<'a> {
+ type Key = Todo; // FIXME(#598): should implement this
+
+ fn key(&self) -> Self::Key {
+ Todo
+ }
+
+ fn expand(&mut self, cx: &mut Expander<'a>) {
+ cx.expand_defined_ty(self)
+ }
+
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> {
+ AnyType::Component(Type {
+ span,
+ id: Some(id),
+ name: None,
+ exports: Default::default(),
+ def: TypeDef::Defined(self),
+ })
+ }
+}
+
+impl<'a> TypeReference<'a> for ComponentType<'a> {
+ type Key = Todo; // FIXME(#598): should implement this
+
+ fn key(&self) -> Self::Key {
+ Todo
+ }
+
+ fn expand(&mut self, cx: &mut Expander<'a>) {
+ cx.expand_component_ty(self)
+ }
+
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> {
+ AnyType::Component(Type {
+ span,
+ id: Some(id),
+ name: None,
+ exports: Default::default(),
+ def: TypeDef::Component(self),
+ })
+ }
+}
+
+impl<'a> TypeReference<'a> for ModuleType<'a> {
+ type Key = Todo; // FIXME(#598): should implement this
+
+ fn key(&self) -> Self::Key {
+ Todo
+ }
+
+ fn expand(&mut self, cx: &mut Expander<'a>) {
+ cx.expand_module_ty(self)
+ }
+
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> {
+ AnyType::Core(CoreType {
+ span,
+ id: Some(id),
+ name: None,
+ def: CoreTypeDef::Module(self),
+ })
+ }
+}
+
+impl<'a> TypeReference<'a> for InstanceType<'a> {
+ type Key = Todo; // FIXME(#598): should implement this
+
+ fn key(&self) -> Self::Key {
+ Todo
+ }
+
+ fn expand(&mut self, cx: &mut Expander<'a>) {
+ cx.expand_instance_ty(self)
+ }
+
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> {
+ AnyType::Component(Type {
+ span,
+ id: Some(id),
+ name: None,
+ exports: Default::default(),
+ def: TypeDef::Instance(self),
+ })
+ }
+}
+
+impl<'a> TypeReference<'a> for ComponentFunctionType<'a> {
+ type Key = Todo; // FIXME(#598): should implement this
+
+ fn key(&self) -> Self::Key {
+ Todo
+ }
+
+ fn expand(&mut self, cx: &mut Expander<'a>) {
+ cx.expand_func_ty(self)
+ }
+
+ fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> {
+ AnyType::Component(Type {
+ span,
+ id: Some(id),
+ name: None,
+ exports: Default::default(),
+ def: TypeDef::Func(self),
+ })
+ }
+}
+
+trait TypeKey<'a> {
+ fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>>;
+ fn insert(&self, cx: &mut Expander<'a>, index: Index<'a>);
+}
+
+struct Todo;
+
+impl<'a> TypeKey<'a> for Todo {
+ fn lookup(&self, _cx: &Expander<'a>) -> Option<Index<'a>> {
+ None
+ }
+
+ fn insert(&self, _cx: &mut Expander<'a>, _index: Index<'a>) {}
+}
diff --git a/third_party/rust/wast/src/component/export.rs b/third_party/rust/wast/src/component/export.rs
new file mode 100644
index 0000000000..ce9baaf453
--- /dev/null
+++ b/third_party/rust/wast/src/component/export.rs
@@ -0,0 +1,221 @@
+use super::{ItemRef, ItemSigNoName};
+use crate::kw;
+use crate::parser::{Cursor, Parse, Parser, Peek, Result};
+use crate::token::{Id, Index, NameAnnotation, Span};
+
+/// An entry in a WebAssembly component's export section.
+#[derive(Debug)]
+pub struct ComponentExport<'a> {
+ /// Where this export was defined.
+ pub span: Span,
+ /// Optional identifier bound to this export.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this instance stored in the custom `name` section.
+ pub debug_name: Option<NameAnnotation<'a>>,
+ /// The name of this export from the component.
+ pub name: &'a str,
+ /// The URL of the export.
+ pub url: Option<&'a str>,
+ /// The kind of export.
+ pub kind: ComponentExportKind<'a>,
+ /// The kind of export.
+ pub ty: Option<ItemSigNoName<'a>>,
+}
+
+impl<'a> Parse<'a> for ComponentExport<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::export>()?.0;
+ let id = parser.parse()?;
+ let debug_name = parser.parse()?;
+ let name = parser.parse()?;
+ let url = parser.parse()?;
+ let kind = parser.parse()?;
+ let ty = if !parser.is_empty() {
+ Some(parser.parens(|p| p.parse())?)
+ } else {
+ None
+ };
+ Ok(ComponentExport {
+ span,
+ id,
+ debug_name,
+ name,
+ url,
+ kind,
+ ty,
+ })
+ }
+}
+
+impl<'a> Parse<'a> for Vec<ComponentExport<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut exports = Vec::new();
+ while !parser.is_empty() {
+ exports.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(exports)
+ }
+}
+
+/// The kind of exported item.
+#[derive(Debug)]
+pub enum ComponentExportKind<'a> {
+ /// The export is a core module.
+ ///
+ /// Note this isn't a core item ref as currently only
+ /// components can export core modules.
+ CoreModule(ItemRef<'a, kw::module>),
+ /// The export is a function.
+ Func(ItemRef<'a, kw::func>),
+ /// The export is a value.
+ Value(ItemRef<'a, kw::value>),
+ /// The export is a type.
+ Type(ItemRef<'a, kw::r#type>),
+ /// The export is a component.
+ Component(ItemRef<'a, kw::component>),
+ /// The export is an instance.
+ Instance(ItemRef<'a, kw::instance>),
+}
+
+impl<'a> ComponentExportKind<'a> {
+ pub(crate) fn module(span: Span, id: Id<'a>) -> Self {
+ Self::CoreModule(ItemRef {
+ kind: kw::module(span),
+ idx: Index::Id(id),
+ export_names: Default::default(),
+ })
+ }
+
+ pub(crate) fn component(span: Span, id: Id<'a>) -> Self {
+ Self::Component(ItemRef {
+ kind: kw::component(span),
+ idx: Index::Id(id),
+ export_names: Default::default(),
+ })
+ }
+
+ pub(crate) fn instance(span: Span, id: Id<'a>) -> Self {
+ Self::Instance(ItemRef {
+ kind: kw::instance(span),
+ idx: Index::Id(id),
+ export_names: Default::default(),
+ })
+ }
+
+ pub(crate) fn func(span: Span, id: Id<'a>) -> Self {
+ Self::Func(ItemRef {
+ kind: kw::func(span),
+ idx: Index::Id(id),
+ export_names: Default::default(),
+ })
+ }
+
+ pub(crate) fn ty(span: Span, id: Id<'a>) -> Self {
+ Self::Type(ItemRef {
+ kind: kw::r#type(span),
+ idx: Index::Id(id),
+ export_names: Default::default(),
+ })
+ }
+}
+
+impl<'a> Parse<'a> for ComponentExportKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parens(|parser| {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::core>() {
+ // Remove core prefix
+ parser.parse::<kw::core>()?;
+ Ok(Self::CoreModule(parser.parse()?))
+ } else if l.peek::<kw::func>() {
+ Ok(Self::Func(parser.parse()?))
+ } else if l.peek::<kw::value>() {
+ Ok(Self::Value(parser.parse()?))
+ } else if l.peek::<kw::r#type>() {
+ Ok(Self::Type(parser.parse()?))
+ } else if l.peek::<kw::component>() {
+ Ok(Self::Component(parser.parse()?))
+ } else if l.peek::<kw::instance>() {
+ Ok(Self::Instance(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ })
+ }
+}
+
+impl Peek for ComponentExportKind<'_> {
+ fn peek(cursor: Cursor) -> bool {
+ let cursor = match cursor.lparen() {
+ Some(c) => c,
+ None => return false,
+ };
+
+ let cursor = match cursor.keyword() {
+ Some(("core", c)) => match c.keyword() {
+ Some(("module", c)) => c,
+ _ => return false,
+ },
+ Some(("func", c))
+ | Some(("value", c))
+ | Some(("type", c))
+ | Some(("component", c))
+ | Some(("instance", c)) => c,
+ _ => return false,
+ };
+
+ Index::peek(cursor)
+ }
+
+ fn display() -> &'static str {
+ "component export"
+ }
+}
+
+/// A listing of inline `(export "foo" <url>)` statements on a WebAssembly
+/// component item in its textual format.
+#[derive(Debug, Default)]
+pub struct InlineExport<'a> {
+ /// The extra names to export an item as, if any.
+ pub names: Vec<(&'a str, Option<&'a str>)>,
+}
+
+impl<'a> Parse<'a> for InlineExport<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut names = Vec::new();
+ while parser.peek::<Self>() {
+ names.push(parser.parens(|p| {
+ p.parse::<kw::export>()?;
+ Ok((p.parse()?, p.parse()?))
+ })?);
+ }
+ Ok(InlineExport { names })
+ }
+}
+
+impl Peek for InlineExport<'_> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ let cursor = match cursor.lparen() {
+ Some(cursor) => cursor,
+ None => return false,
+ };
+ let cursor = match cursor.keyword() {
+ Some(("export", cursor)) => cursor,
+ _ => return false,
+ };
+ // Name
+ let mut cursor = match cursor.string() {
+ Some((_, cursor)) => cursor,
+ None => return false,
+ };
+ // Optional URL
+ if let Some((_, c)) = cursor.string() {
+ cursor = c;
+ }
+ cursor.rparen().is_some()
+ }
+
+ fn display() -> &'static str {
+ "inline export"
+ }
+}
diff --git a/third_party/rust/wast/src/component/func.rs b/third_party/rust/wast/src/component/func.rs
new file mode 100644
index 0000000000..4edbc63171
--- /dev/null
+++ b/third_party/rust/wast/src/component/func.rs
@@ -0,0 +1,372 @@
+use crate::component::*;
+use crate::kw;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::{Id, Index, LParen, NameAnnotation, Span};
+
+/// A declared core function.
+///
+/// This is a member of both the core alias and canon sections.
+#[derive(Debug)]
+pub struct CoreFunc<'a> {
+ /// Where this `core 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>>,
+ /// The kind of core function.
+ pub kind: CoreFuncKind<'a>,
+}
+
+impl<'a> Parse<'a> for CoreFunc<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::core>()?.0;
+ parser.parse::<kw::func>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let kind = parser.parse()?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ kind,
+ })
+ }
+}
+
+/// Represents the kind of core functions.
+#[derive(Debug)]
+pub enum CoreFuncKind<'a> {
+ /// The core function is defined in terms of lowering a component function.
+ ///
+ /// The core function is actually a member of the canon section.
+ Lower(CanonLower<'a>),
+ /// The core function is defined in terms of aliasing a module instance export.
+ ///
+ /// The core function is actually a member of the core alias section.
+ Alias(InlineExportAlias<'a>),
+}
+
+impl<'a> Parse<'a> for CoreFuncKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parens(|parser| {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::canon>() {
+ parser.parse::<kw::canon>()?;
+ Ok(Self::Lower(parser.parse()?))
+ } else if l.peek::<kw::alias>() {
+ Ok(Self::Alias(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ })
+ }
+}
+
+/// A declared component function.
+///
+/// This may be a member of the import, alias, or canon 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>,
+ /// The kind of function.
+ pub kind: FuncKind<'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 kind = parser.parse()?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ exports,
+ kind,
+ })
+ }
+}
+
+/// Represents the kind of component functions.
+#[derive(Debug)]
+pub enum FuncKind<'a> {
+ /// A function which is actually defined as an import, such as:
+ ///
+ /// ```text
+ /// (func (import "foo") (param string))
+ /// ```
+ Import {
+ /// The import name of this import.
+ import: InlineImport<'a>,
+ /// The type that this function will have.
+ ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>,
+ },
+ /// The function is defined in terms of lifting a core function.
+ ///
+ /// The function is actually a member of the canon section.
+ Lift {
+ /// The lifted function's type.
+ ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>,
+ /// Information relating to the lifting of the core function.
+ info: CanonLift<'a>,
+ },
+ /// The function is defined in terms of aliasing a component instance export.
+ ///
+ /// The function is actually a member of the alias section.
+ Alias(InlineExportAlias<'a>),
+}
+
+impl<'a> Parse<'a> for FuncKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if let Some(import) = parser.parse()? {
+ Ok(Self::Import {
+ import,
+ ty: parser.parse()?,
+ })
+ } else if parser.peek::<LParen>() && parser.peek2::<kw::alias>() {
+ parser.parens(|parser| Ok(Self::Alias(parser.parse()?)))
+ } else {
+ Ok(Self::Lift {
+ ty: parser.parse()?,
+ info: parser.parens(|parser| {
+ parser.parse::<kw::canon>()?;
+ parser.parse()
+ })?,
+ })
+ }
+ }
+}
+
+/// A WebAssembly canonical function to be inserted into a component.
+///
+/// This is a member of the canonical section.
+#[derive(Debug)]
+pub struct CanonicalFunc<'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>>,
+ /// What kind of function this is, be it a lowered or lifted function.
+ pub kind: CanonicalFuncKind<'a>,
+}
+
+impl<'a> Parse<'a> for CanonicalFunc<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::canon>()?.0;
+
+ if parser.peek::<kw::lift>() {
+ let info = parser.parse()?;
+ let (id, name, ty) = parser.parens(|parser| {
+ parser.parse::<kw::func>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let ty = parser.parse()?;
+ Ok((id, name, ty))
+ })?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ kind: CanonicalFuncKind::Lift { info, ty },
+ })
+ } else if parser.peek::<kw::lower>() {
+ let info = parser.parse()?;
+ let (id, name) = parser.parens(|parser| {
+ parser.parse::<kw::core>()?;
+ parser.parse::<kw::func>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ Ok((id, name))
+ })?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ kind: CanonicalFuncKind::Lower(info),
+ })
+ } else {
+ Err(parser.error("expected `canon lift` or `canon lower`"))
+ }
+ }
+}
+
+/// Possible ways to define a canonical function in the text format.
+#[derive(Debug)]
+pub enum CanonicalFuncKind<'a> {
+ /// A canonical function that is defined in terms of lifting a core function.
+ Lift {
+ /// The lifted function's type.
+ ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>,
+ /// Information relating to the lifting of the core function.
+ info: CanonLift<'a>,
+ },
+ /// A canonical function that is defined in terms of lowering a component function.
+ Lower(CanonLower<'a>),
+}
+
+/// Information relating to lifting a core function.
+#[derive(Debug)]
+pub struct CanonLift<'a> {
+ /// The core function being lifted.
+ pub func: CoreItemRef<'a, kw::func>,
+ /// The canonical options for the lifting.
+ pub opts: Vec<CanonOpt<'a>>,
+}
+
+impl<'a> Parse<'a> for CanonLift<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::lift>()?;
+
+ Ok(Self {
+ func: parser.parens(|parser| {
+ parser.parse::<kw::core>()?;
+ parser.parse()
+ })?,
+ opts: parser.parse()?,
+ })
+ }
+}
+
+impl Default for CanonLift<'_> {
+ fn default() -> Self {
+ let span = Span::from_offset(0);
+ Self {
+ func: CoreItemRef {
+ kind: kw::func(span),
+ idx: Index::Num(0, span),
+ export_name: None,
+ },
+ opts: Vec::new(),
+ }
+ }
+}
+
+/// Information relating to lowering a component function.
+#[derive(Debug)]
+pub struct CanonLower<'a> {
+ /// The function being lowered.
+ pub func: ItemRef<'a, kw::func>,
+ /// The canonical options for the lowering.
+ pub opts: Vec<CanonOpt<'a>>,
+}
+
+impl<'a> Parse<'a> for CanonLower<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::lower>()?;
+
+ Ok(Self {
+ func: parser.parens(|parser| parser.parse())?,
+ opts: parser.parse()?,
+ })
+ }
+}
+
+impl Default for CanonLower<'_> {
+ fn default() -> Self {
+ let span = Span::from_offset(0);
+ Self {
+ func: ItemRef {
+ kind: kw::func(span),
+ idx: Index::Num(0, span),
+ export_names: Vec::new(),
+ },
+ opts: Vec::new(),
+ }
+ }
+}
+
+#[derive(Debug)]
+/// Canonical ABI options.
+pub enum CanonOpt<'a> {
+ /// Encode strings as UTF-8.
+ StringUtf8,
+ /// Encode strings as UTF-16.
+ StringUtf16,
+ /// Encode strings as "compact UTF-16".
+ StringLatin1Utf16,
+ /// Use the specified memory for canonical ABI memory access.
+ Memory(CoreItemRef<'a, kw::memory>),
+ /// Use the specified reallocation function for memory allocations.
+ Realloc(CoreItemRef<'a, kw::func>),
+ /// Call the specified function after the lifted function has returned.
+ PostReturn(CoreItemRef<'a, kw::func>),
+}
+
+impl<'a> Parse<'a> for CanonOpt<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::string_utf8>() {
+ parser.parse::<kw::string_utf8>()?;
+ Ok(Self::StringUtf8)
+ } else if l.peek::<kw::string_utf16>() {
+ parser.parse::<kw::string_utf16>()?;
+ Ok(Self::StringUtf16)
+ } else if l.peek::<kw::string_latin1_utf16>() {
+ parser.parse::<kw::string_latin1_utf16>()?;
+ Ok(Self::StringLatin1Utf16)
+ } else if l.peek::<LParen>() {
+ parser.parens(|parser| {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::memory>() {
+ let span = parser.parse::<kw::memory>()?.0;
+ Ok(CanonOpt::Memory(parse_trailing_item_ref(
+ kw::memory(span),
+ parser,
+ )?))
+ } else if l.peek::<kw::realloc>() {
+ parser.parse::<kw::realloc>()?;
+ Ok(CanonOpt::Realloc(
+ parser.parse::<IndexOrCoreRef<'_, _>>()?.0,
+ ))
+ } else if l.peek::<kw::post_return>() {
+ parser.parse::<kw::post_return>()?;
+ Ok(CanonOpt::PostReturn(
+ parser.parse::<IndexOrCoreRef<'_, _>>()?.0,
+ ))
+ } else {
+ Err(l.error())
+ }
+ })
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+fn parse_trailing_item_ref<T>(kind: T, parser: Parser) -> Result<CoreItemRef<T>> {
+ Ok(CoreItemRef {
+ kind,
+ idx: parser.parse()?,
+ export_name: parser.parse()?,
+ })
+}
+
+impl<'a> Parse<'a> for Vec<CanonOpt<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut funcs = Vec::new();
+ while !parser.is_empty() {
+ funcs.push(parser.parse()?);
+ }
+ Ok(funcs)
+ }
+}
diff --git a/third_party/rust/wast/src/component/import.rs b/third_party/rust/wast/src/component/import.rs
new file mode 100644
index 0000000000..98fec55aa7
--- /dev/null
+++ b/third_party/rust/wast/src/component/import.rs
@@ -0,0 +1,176 @@
+use crate::component::*;
+use crate::kw;
+use crate::parser::{Cursor, Parse, Parser, Peek, Result};
+use crate::token::Index;
+use crate::token::{Id, NameAnnotation, Span};
+
+/// An `import` statement and entry in a WebAssembly component.
+#[derive(Debug)]
+pub struct ComponentImport<'a> {
+ /// Where this `import` was defined
+ pub span: Span,
+ /// The name of the item to import.
+ pub name: &'a str,
+ /// The optional URL of the import.
+ pub url: Option<&'a str>,
+ /// The item that's being imported.
+ pub item: ItemSig<'a>,
+}
+
+impl<'a> Parse<'a> for ComponentImport<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::import>()?.0;
+ let name = parser.parse()?;
+ let url = parser.parse()?;
+ let item = parser.parens(|p| p.parse())?;
+ Ok(ComponentImport {
+ span,
+ name,
+ url,
+ item,
+ })
+ }
+}
+
+/// An item signature for imported items.
+#[derive(Debug)]
+pub struct ItemSig<'a> {
+ /// Where this item is defined in the source.
+ pub span: Span,
+ /// An optional identifier used during name resolution to refer to this item
+ /// from the rest of the component.
+ pub id: Option<Id<'a>>,
+ /// An optional name which, for functions, will be stored in the
+ /// custom `name` section.
+ pub name: Option<NameAnnotation<'a>>,
+ /// What kind of item this is.
+ pub kind: ItemSigKind<'a>,
+}
+
+impl<'a> Parse<'a> for ItemSig<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parse_item_sig(parser, true)
+ }
+}
+
+/// An item signature for imported items.
+#[derive(Debug)]
+pub struct ItemSigNoName<'a>(pub ItemSig<'a>);
+
+impl<'a> Parse<'a> for ItemSigNoName<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ Ok(ItemSigNoName(parse_item_sig(parser, false)?))
+ }
+}
+
+fn parse_item_sig<'a>(parser: Parser<'a>, name: bool) -> Result<ItemSig<'a>> {
+ let mut l = parser.lookahead1();
+ let (span, parse_kind): (_, fn(Parser<'a>) -> Result<ItemSigKind>) = if l.peek::<kw::core>() {
+ let span = parser.parse::<kw::core>()?.0;
+ parser.parse::<kw::module>()?;
+ (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?)))
+ } else if l.peek::<kw::func>() {
+ let span = parser.parse::<kw::func>()?.0;
+ (span, |parser| Ok(ItemSigKind::Func(parser.parse()?)))
+ } else if l.peek::<kw::component>() {
+ let span = parser.parse::<kw::component>()?.0;
+ (span, |parser| Ok(ItemSigKind::Component(parser.parse()?)))
+ } else if l.peek::<kw::instance>() {
+ let span = parser.parse::<kw::instance>()?.0;
+ (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?)))
+ } else if l.peek::<kw::value>() {
+ let span = parser.parse::<kw::value>()?.0;
+ (span, |parser| Ok(ItemSigKind::Value(parser.parse()?)))
+ } else if l.peek::<kw::r#type>() {
+ let span = parser.parse::<kw::r#type>()?.0;
+ (span, |parser| {
+ Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?))
+ })
+ } else {
+ return Err(l.error());
+ };
+ Ok(ItemSig {
+ span,
+ id: if name { parser.parse()? } else { None },
+ name: if name { parser.parse()? } else { None },
+ kind: parse_kind(parser)?,
+ })
+}
+
+/// The kind of signatures for imported items.
+#[derive(Debug)]
+pub enum ItemSigKind<'a> {
+ /// The item signature is for a core module.
+ CoreModule(CoreTypeUse<'a, ModuleType<'a>>),
+ /// The item signature is for a function.
+ Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>),
+ /// The item signature is for a component.
+ Component(ComponentTypeUse<'a, ComponentType<'a>>),
+ /// The item signature is for an instance.
+ Instance(ComponentTypeUse<'a, InstanceType<'a>>),
+ /// The item signature is for a value.
+ Value(ComponentValTypeUse<'a>),
+ /// The item signature is for a type.
+ Type(TypeBounds<'a>),
+}
+
+/// Represents the bounds applied to types being imported.
+#[derive(Debug)]
+pub enum TypeBounds<'a> {
+ /// The equality type bounds.
+ Eq(Index<'a>),
+}
+
+impl<'a> Parse<'a> for TypeBounds<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ // Currently this is the only supported type bounds.
+ parser.parse::<kw::eq>()?;
+ Ok(Self::Eq(parser.parse()?))
+ }
+}
+
+/// A listing of a inline `(import "foo")` statement.
+///
+/// This is the same as `core::InlineImport` except only one string import is
+/// required.
+#[derive(Debug, Clone)]
+pub struct InlineImport<'a> {
+ /// The name of the item being imported.
+ pub name: &'a str,
+ /// The optional URL of the item being imported.
+ pub url: Option<&'a str>,
+}
+
+impl<'a> Parse<'a> for InlineImport<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parens(|p| {
+ p.parse::<kw::import>()?;
+ Ok(InlineImport {
+ name: p.parse()?,
+ url: p.parse()?,
+ })
+ })
+ }
+}
+
+impl Peek for InlineImport<'_> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ let cursor = match cursor.lparen() {
+ Some(cursor) => cursor,
+ None => return false,
+ };
+ let cursor = match cursor.keyword() {
+ Some(("import", cursor)) => cursor,
+ _ => return false,
+ };
+ let cursor = match cursor.string() {
+ Some((_, cursor)) => cursor,
+ None => return false,
+ };
+ cursor.rparen().is_some()
+ }
+
+ fn display() -> &'static str {
+ "inline import"
+ }
+}
diff --git a/third_party/rust/wast/src/component/instance.rs b/third_party/rust/wast/src/component/instance.rs
new file mode 100644
index 0000000000..888f4ee9f9
--- /dev/null
+++ b/third_party/rust/wast/src/component/instance.rs
@@ -0,0 +1,296 @@
+use crate::component::*;
+use crate::core;
+use crate::kw;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::{Id, LParen, NameAnnotation, Span};
+
+/// A core instance defined by instantiation or exporting core items.
+#[derive(Debug)]
+pub struct CoreInstance<'a> {
+ /// Where this `core instance` was defined.
+ pub span: Span,
+ /// An identifier that this instance is resolved with (optionally) for name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this instance stored in the custom `name` section.
+ pub name: Option<NameAnnotation<'a>>,
+ /// What kind of instance this is.
+ pub kind: CoreInstanceKind<'a>,
+}
+
+impl<'a> Parse<'a> for CoreInstance<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::core>()?.0;
+ parser.parse::<kw::instance>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let kind = parser.parse()?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ kind,
+ })
+ }
+}
+
+/// The kinds of core instances in the text format.
+#[derive(Debug)]
+pub enum CoreInstanceKind<'a> {
+ /// Instantiate a core module.
+ Instantiate {
+ /// The module being instantiated.
+ module: ItemRef<'a, kw::module>,
+ /// Arguments used to instantiate the instance.
+ args: Vec<CoreInstantiationArg<'a>>,
+ },
+ /// The instance is defined by exporting local items as an instance.
+ BundleOfExports(Vec<CoreInstanceExport<'a>>),
+}
+
+impl<'a> Parse<'a> for CoreInstanceKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<LParen>() && parser.peek2::<kw::instantiate>() {
+ parser.parens(|parser| {
+ parser.parse::<kw::instantiate>()?;
+ Ok(Self::Instantiate {
+ module: parser.parse::<IndexOrRef<'_, _>>()?.0,
+ args: parser.parse()?,
+ })
+ })
+ } else {
+ Ok(Self::BundleOfExports(parser.parse()?))
+ }
+ }
+}
+
+impl Default for kw::module {
+ fn default() -> kw::module {
+ kw::module(Span::from_offset(0))
+ }
+}
+
+/// An argument to instantiate a core module.
+#[derive(Debug)]
+pub struct CoreInstantiationArg<'a> {
+ /// The name of the instantiation argument.
+ pub name: &'a str,
+ /// The kind of core instantiation argument.
+ pub kind: CoreInstantiationArgKind<'a>,
+}
+
+impl<'a> Parse<'a> for CoreInstantiationArg<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::with>()?;
+ Ok(Self {
+ name: parser.parse()?,
+ kind: parser.parse()?,
+ })
+ }
+}
+
+impl<'a> Parse<'a> for Vec<CoreInstantiationArg<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut args = Vec::new();
+ while !parser.is_empty() {
+ args.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(args)
+ }
+}
+
+/// The kind of core instantiation argument.
+#[derive(Debug)]
+pub enum CoreInstantiationArgKind<'a> {
+ /// The argument is a reference to an instance.
+ Instance(CoreItemRef<'a, kw::instance>),
+ /// The argument is an instance created from local exported core items.
+ ///
+ /// This is syntactic sugar for defining a core instance and also using it
+ /// as an instantiation argument.
+ BundleOfExports(Span, Vec<CoreInstanceExport<'a>>),
+}
+
+impl<'a> Parse<'a> for CoreInstantiationArgKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parens(|parser| {
+ if let Some(r) = parser.parse()? {
+ Ok(Self::Instance(r))
+ } else {
+ let span = parser.parse::<kw::instance>()?.0;
+ Ok(Self::BundleOfExports(span, parser.parse()?))
+ }
+ })
+ }
+}
+
+/// An exported item as part of a core instance.
+#[derive(Debug)]
+pub struct CoreInstanceExport<'a> {
+ /// Where this export was defined.
+ pub span: Span,
+ /// The name of this export from the instance.
+ pub name: &'a str,
+ /// What's being exported from the instance.
+ pub item: CoreItemRef<'a, core::ExportKind>,
+}
+
+impl<'a> Parse<'a> for CoreInstanceExport<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ Ok(Self {
+ span: parser.parse::<kw::export>()?.0,
+ name: parser.parse()?,
+ item: parser.parens(|parser| parser.parse())?,
+ })
+ }
+}
+
+impl<'a> Parse<'a> for Vec<CoreInstanceExport<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut exports = Vec::new();
+ while !parser.is_empty() {
+ exports.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(exports)
+ }
+}
+
+/// A component instance defined by instantiation or exporting items.
+#[derive(Debug)]
+pub struct Instance<'a> {
+ /// Where this `instance` was defined.
+ pub span: Span,
+ /// An identifier that this instance is resolved with (optionally) for name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this instance 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 instance this is.
+ pub kind: InstanceKind<'a>,
+}
+
+impl<'a> Parse<'a> for Instance<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::instance>()?.0;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let exports = parser.parse()?;
+ let kind = parser.parse()?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ exports,
+ kind,
+ })
+ }
+}
+
+/// The kinds of instances in the text format.
+#[derive(Debug)]
+pub enum InstanceKind<'a> {
+ /// The `(instance (import "x"))` sugar syntax
+ Import {
+ /// The name of the import
+ import: InlineImport<'a>,
+ /// The type of the instance being imported
+ ty: ComponentTypeUse<'a, InstanceType<'a>>,
+ },
+ /// Instantiate a component.
+ Instantiate {
+ /// The component being instantiated.
+ component: ItemRef<'a, kw::component>,
+ /// Arguments used to instantiate the instance.
+ args: Vec<InstantiationArg<'a>>,
+ },
+ /// The instance is defined by exporting local items as an instance.
+ BundleOfExports(Vec<ComponentExport<'a>>),
+}
+
+impl<'a> Parse<'a> for InstanceKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if let Some(import) = parser.parse()? {
+ return Ok(Self::Import {
+ import,
+ ty: parser.parse()?,
+ });
+ }
+
+ if parser.peek::<LParen>() && parser.peek2::<kw::instantiate>() {
+ parser.parens(|parser| {
+ parser.parse::<kw::instantiate>()?;
+ Ok(Self::Instantiate {
+ component: parser.parse::<IndexOrRef<'_, _>>()?.0,
+ args: parser.parse()?,
+ })
+ })
+ } else {
+ Ok(Self::BundleOfExports(parser.parse()?))
+ }
+ }
+}
+
+impl Default for kw::component {
+ fn default() -> kw::component {
+ kw::component(Span::from_offset(0))
+ }
+}
+
+/// An argument to instantiate a component.
+#[derive(Debug)]
+pub struct InstantiationArg<'a> {
+ /// The name of the instantiation argument.
+ pub name: &'a str,
+ /// The kind of instantiation argument.
+ pub kind: InstantiationArgKind<'a>,
+}
+
+impl<'a> Parse<'a> for InstantiationArg<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::with>()?;
+ Ok(Self {
+ name: parser.parse()?,
+ kind: parser.parse()?,
+ })
+ }
+}
+
+impl<'a> Parse<'a> for Vec<InstantiationArg<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut args = Vec::new();
+ while !parser.is_empty() {
+ args.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(args)
+ }
+}
+
+/// The kind of instantiation argument.
+#[derive(Debug)]
+pub enum InstantiationArgKind<'a> {
+ /// The argument is a reference to a component item.
+ Item(ComponentExportKind<'a>),
+ /// The argument is an instance created from local exported items.
+ ///
+ /// This is syntactic sugar for defining an instance and also using it
+ /// as an instantiation argument.
+ BundleOfExports(Span, Vec<ComponentExport<'a>>),
+}
+
+impl<'a> Parse<'a> for InstantiationArgKind<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if let Some(item) = parser.parse()? {
+ Ok(Self::Item(item))
+ } else {
+ parser.parens(|parser| {
+ let span = parser.parse::<kw::instance>()?.0;
+ Ok(Self::BundleOfExports(span, parser.parse()?))
+ })
+ }
+ }
+}
diff --git a/third_party/rust/wast/src/component/item_ref.rs b/third_party/rust/wast/src/component/item_ref.rs
new file mode 100644
index 0000000000..c3bbf2f9f4
--- /dev/null
+++ b/third_party/rust/wast/src/component/item_ref.rs
@@ -0,0 +1,154 @@
+use crate::parser::{Cursor, Parse, Parser, Peek, Result};
+use crate::token::Index;
+
+fn peek<K: Peek>(cursor: Cursor) -> bool {
+ // This is a little fancy because when parsing something like:
+ //
+ // (type (component (type $foo)))
+ //
+ // we need to disambiguate that from
+ //
+ // (type (component (type $foo (func))))
+ //
+ // where the first is a type reference and the second is an inline
+ // component type defining a type internally. The peek here not only
+ // peeks for `K` but also for the index and possibly trailing
+ // strings.
+
+ // Peek for the given keyword type
+ if !K::peek(cursor) {
+ return false;
+ }
+
+ // Move past the given keyword
+ let cursor = match cursor.keyword() {
+ Some((_, c)) => c,
+ _ => return false,
+ };
+
+ // Peek an id or integer index, followed by `)` or string to disambiguate
+ match cursor
+ .id()
+ .map(|p| p.1)
+ .or_else(|| cursor.integer().map(|p| p.1))
+ {
+ Some(cursor) => cursor.rparen().is_some() || cursor.string().is_some(),
+ None => false,
+ }
+}
+
+/// Parses core item references.
+#[derive(Clone, Debug)]
+pub struct CoreItemRef<'a, K> {
+ /// The item kind being parsed.
+ pub kind: K,
+ /// The item or instance reference.
+ pub idx: Index<'a>,
+ /// Export name to resolve the item from.
+ pub export_name: Option<&'a str>,
+}
+
+impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ // This does not parse the surrounding `(` and `)` because
+ // core prefix is context dependent and only the caller knows if it should be
+ // present for core references; therefore, the caller parses the parens and any core prefix
+ let kind = parser.parse::<K>()?;
+ let idx = parser.parse()?;
+ let export_name = parser.parse()?;
+ Ok(Self {
+ kind,
+ idx,
+ export_name,
+ })
+ }
+}
+
+impl<'a, K: Peek> Peek for CoreItemRef<'a, K> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ peek::<K>(cursor)
+ }
+
+ fn display() -> &'static str {
+ "a core item reference"
+ }
+}
+
+/// Parses component item references.
+#[derive(Clone, Debug)]
+pub struct ItemRef<'a, K> {
+ /// The item kind being parsed.
+ pub kind: K,
+ /// The item or instance reference.
+ pub idx: Index<'a>,
+ /// Export names to resolve the item from.
+ pub export_names: Vec<&'a str>,
+}
+
+impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let kind = parser.parse::<K>()?;
+ let idx = parser.parse()?;
+ let mut export_names = Vec::new();
+ while !parser.is_empty() {
+ export_names.push(parser.parse()?);
+ }
+ Ok(Self {
+ kind,
+ idx,
+ export_names,
+ })
+ }
+}
+
+impl<'a, K: Peek> Peek for ItemRef<'a, K> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ peek::<K>(cursor)
+ }
+
+ fn display() -> &'static str {
+ "a component item reference"
+ }
+}
+
+/// Convenience structure to parse `$f` or `(item $f)`.
+#[derive(Clone, Debug)]
+pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>);
+
+impl<'a, K> Parse<'a> for IndexOrRef<'a, K>
+where
+ K: Parse<'a> + Default,
+{
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<Index<'_>>() {
+ Ok(IndexOrRef(ItemRef {
+ kind: K::default(),
+ idx: parser.parse()?,
+ export_names: Vec::new(),
+ }))
+ } else {
+ Ok(IndexOrRef(parser.parens(|p| p.parse())?))
+ }
+ }
+}
+
+/// Convenience structure to parse `$f` or `(item $f)`.
+#[derive(Clone, Debug)]
+pub struct IndexOrCoreRef<'a, K>(pub CoreItemRef<'a, K>);
+
+impl<'a, K> Parse<'a> for IndexOrCoreRef<'a, K>
+where
+ K: Parse<'a> + Default,
+{
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<Index<'_>>() {
+ Ok(IndexOrCoreRef(CoreItemRef {
+ kind: K::default(),
+ idx: parser.parse()?,
+ export_name: None,
+ }))
+ } else {
+ Ok(IndexOrCoreRef(parser.parens(|p| p.parse())?))
+ }
+ }
+}
diff --git a/third_party/rust/wast/src/component/module.rs b/third_party/rust/wast/src/component/module.rs
new file mode 100644
index 0000000000..6871af8d4c
--- /dev/null
+++ b/third_party/rust/wast/src/component/module.rs
@@ -0,0 +1,75 @@
+use crate::component::*;
+use crate::core;
+use crate::kw;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::{Id, NameAnnotation, Span};
+
+/// A core WebAssembly module to be created as part of a component.
+///
+/// This is a member of the core module section.
+#[derive(Debug)]
+pub struct CoreModule<'a> {
+ /// Where this `core module` was defined.
+ pub span: Span,
+ /// An identifier that this module is resolved with (optionally) for name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this module 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 module this is, be it an inline-defined or imported one.
+ pub kind: CoreModuleKind<'a>,
+}
+
+/// Possible ways to define a core module in the text format.
+#[derive(Debug)]
+pub enum CoreModuleKind<'a> {
+ /// A core module which is actually defined as an import
+ Import {
+ /// Where this core module is imported from
+ import: InlineImport<'a>,
+ /// The type that this core module will have.
+ ty: CoreTypeUse<'a, ModuleType<'a>>,
+ },
+
+ /// Modules that are defined inline.
+ Inline {
+ /// Fields in the core module.
+ fields: Vec<core::ModuleField<'a>>,
+ },
+}
+
+impl<'a> Parse<'a> for CoreModule<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+
+ let span = parser.parse::<kw::core>()?.0;
+ parser.parse::<kw::module>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let exports = parser.parse()?;
+
+ let kind = if let Some(import) = parser.parse()? {
+ CoreModuleKind::Import {
+ import,
+ ty: parser.parse()?,
+ }
+ } else {
+ let mut fields = Vec::new();
+ while !parser.is_empty() {
+ fields.push(parser.parens(|p| p.parse())?);
+ }
+ CoreModuleKind::Inline { fields }
+ };
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ exports,
+ kind,
+ })
+ }
+}
diff --git a/third_party/rust/wast/src/component/resolve.rs b/third_party/rust/wast/src/component/resolve.rs
new file mode 100644
index 0000000000..e87350e329
--- /dev/null
+++ b/third_party/rust/wast/src/component/resolve.rs
@@ -0,0 +1,973 @@
+use crate::component::*;
+use crate::core;
+use crate::kw;
+use crate::names::Namespace;
+use crate::token::Span;
+use crate::token::{Id, Index};
+use crate::Error;
+
+/// Resolve the fields of a component and everything nested within it, changing
+/// `Index::Id` to `Index::Num` and expanding alias syntax sugar.
+pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> {
+ let fields = match &mut component.kind {
+ ComponentKind::Text(fields) => fields,
+ ComponentKind::Binary(_) => return Ok(()),
+ };
+ let mut resolver = Resolver::default();
+ resolver.fields(component.id, fields)
+}
+
+impl<'a> From<Alias<'a>> for ComponentField<'a> {
+ fn from(a: Alias<'a>) -> Self {
+ Self::Alias(a)
+ }
+}
+
+impl<'a> From<Alias<'a>> for ModuleTypeDecl<'a> {
+ fn from(a: Alias<'a>) -> Self {
+ Self::Alias(a)
+ }
+}
+
+impl<'a> From<Alias<'a>> for ComponentTypeDecl<'a> {
+ fn from(a: Alias<'a>) -> Self {
+ Self::Alias(a)
+ }
+}
+
+impl<'a> From<Alias<'a>> for InstanceTypeDecl<'a> {
+ fn from(a: Alias<'a>) -> Self {
+ Self::Alias(a)
+ }
+}
+
+#[derive(Default)]
+struct Resolver<'a> {
+ stack: Vec<ComponentState<'a>>,
+
+ // When a name refers to a definition in an outer scope, we'll need to
+ // insert an outer alias before it. This collects the aliases to be
+ // inserted during resolution.
+ aliases_to_insert: Vec<Alias<'a>>,
+}
+
+/// Context structure used to perform name resolution.
+#[derive(Default)]
+struct ComponentState<'a> {
+ id: Option<Id<'a>>,
+
+ // Namespaces within each component. Note that each namespace carries
+ // with it information about the signature of the item in that namespace.
+ // The signature is later used to synthesize the type of a component and
+ // inject type annotations if necessary.
+ core_funcs: Namespace<'a>,
+ core_globals: Namespace<'a>,
+ core_tables: Namespace<'a>,
+ core_memories: Namespace<'a>,
+ core_types: Namespace<'a>,
+ core_tags: Namespace<'a>,
+ core_instances: Namespace<'a>,
+ core_modules: Namespace<'a>,
+
+ funcs: Namespace<'a>,
+ types: Namespace<'a>,
+ instances: Namespace<'a>,
+ components: Namespace<'a>,
+ values: Namespace<'a>,
+}
+
+impl<'a> ComponentState<'a> {
+ fn new(id: Option<Id<'a>>) -> ComponentState<'a> {
+ ComponentState {
+ id,
+ ..ComponentState::default()
+ }
+ }
+
+ fn register_item_sig(&mut self, sig: &ItemSig<'a>) -> Result<u32, Error> {
+ match &sig.kind {
+ ItemSigKind::CoreModule(_) => self.core_modules.register(sig.id, "core module"),
+ ItemSigKind::Func(_) => self.funcs.register(sig.id, "func"),
+ ItemSigKind::Component(_) => self.components.register(sig.id, "component"),
+ ItemSigKind::Instance(_) => self.instances.register(sig.id, "instance"),
+ ItemSigKind::Value(_) => self.values.register(sig.id, "value"),
+ ItemSigKind::Type(_) => self.types.register(sig.id, "type"),
+ }
+ }
+}
+
+impl<'a> Resolver<'a> {
+ fn current(&mut self) -> &mut ComponentState<'a> {
+ self.stack
+ .last_mut()
+ .expect("should have at least one component state")
+ }
+
+ fn fields(
+ &mut self,
+ id: Option<Id<'a>>,
+ fields: &mut Vec<ComponentField<'a>>,
+ ) -> Result<(), Error> {
+ self.stack.push(ComponentState::new(id));
+ self.resolve_prepending_aliases(fields, Resolver::field, ComponentState::register)?;
+ self.stack.pop();
+ Ok(())
+ }
+
+ fn resolve_prepending_aliases<T>(
+ &mut self,
+ fields: &mut Vec<T>,
+ resolve: fn(&mut Self, &mut T) -> Result<(), Error>,
+ register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>,
+ ) -> Result<(), Error>
+ where
+ T: From<Alias<'a>>,
+ {
+ assert!(self.aliases_to_insert.is_empty());
+
+ // Iterate through the fields of the component. We use an index
+ // instead of an iterator because we'll be inserting aliases
+ // as we go.
+ let mut i = 0;
+ while i < fields.len() {
+ // Resolve names within the field.
+ resolve(self, &mut fields[i])?;
+
+ // Name resolution may have emitted some aliases. Insert them before
+ // the current definition.
+ let amt = self.aliases_to_insert.len();
+ fields.splice(i..i, self.aliases_to_insert.drain(..).map(T::from));
+ i += amt;
+
+ // Definitions can't refer to themselves or to definitions that appear
+ // later in the format. Now that we're done resolving this field,
+ // assign it an index for later definitions to refer to.
+ register(self.current(), &fields[i])?;
+
+ i += 1;
+ }
+
+ Ok(())
+ }
+
+ fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> {
+ match field {
+ ComponentField::CoreModule(m) => self.core_module(m),
+ ComponentField::CoreInstance(i) => self.core_instance(i),
+ ComponentField::CoreType(t) => self.core_ty(t),
+ ComponentField::Component(c) => self.component(c),
+ ComponentField::Instance(i) => self.instance(i),
+ ComponentField::Alias(a) => self.alias(a, false),
+ ComponentField::Type(t) => self.ty(t),
+ ComponentField::CanonicalFunc(f) => self.canonical_func(f),
+ ComponentField::CoreFunc(_) => unreachable!("should be expanded already"),
+ ComponentField::Func(_) => unreachable!("should be expanded already"),
+ ComponentField::Start(s) => self.start(s),
+ ComponentField::Import(i) => self.item_sig(&mut i.item),
+ ComponentField::Export(e) => {
+ if let Some(ty) = &mut e.ty {
+ self.item_sig(&mut ty.0)?;
+ }
+ self.export(&mut e.kind)
+ }
+ ComponentField::Custom(_) => Ok(()),
+ }
+ }
+
+ fn core_module(&mut self, module: &mut CoreModule) -> Result<(), Error> {
+ match &mut module.kind {
+ CoreModuleKind::Inline { fields } => {
+ crate::core::resolve::resolve(fields)?;
+ }
+
+ CoreModuleKind::Import { .. } => {
+ unreachable!("should be expanded already")
+ }
+ }
+
+ Ok(())
+ }
+
+ fn component(&mut self, component: &mut NestedComponent<'a>) -> Result<(), Error> {
+ match &mut component.kind {
+ NestedComponentKind::Import { .. } => unreachable!("should be expanded already"),
+ NestedComponentKind::Inline(fields) => self.fields(component.id, fields),
+ }
+ }
+
+ fn core_instance(&mut self, instance: &mut CoreInstance<'a>) -> Result<(), Error> {
+ match &mut instance.kind {
+ CoreInstanceKind::Instantiate { module, args } => {
+ self.component_item_ref(module)?;
+ for arg in args {
+ match &mut arg.kind {
+ CoreInstantiationArgKind::Instance(i) => {
+ self.core_item_ref(i)?;
+ }
+ CoreInstantiationArgKind::BundleOfExports(..) => {
+ unreachable!("should be expanded already");
+ }
+ }
+ }
+ }
+ CoreInstanceKind::BundleOfExports(exports) => {
+ for export in exports {
+ self.core_item_ref(&mut export.item)?;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn instance(&mut self, instance: &mut Instance<'a>) -> Result<(), Error> {
+ match &mut instance.kind {
+ InstanceKind::Instantiate { component, args } => {
+ self.component_item_ref(component)?;
+ for arg in args {
+ match &mut arg.kind {
+ InstantiationArgKind::Item(e) => {
+ self.export(e)?;
+ }
+ InstantiationArgKind::BundleOfExports(..) => {
+ unreachable!("should be expanded already")
+ }
+ }
+ }
+ }
+ InstanceKind::BundleOfExports(exports) => {
+ for export in exports {
+ self.export(&mut export.kind)?;
+ }
+ }
+ InstanceKind::Import { .. } => {
+ unreachable!("should be expanded already")
+ }
+ }
+ Ok(())
+ }
+
+ fn item_sig(&mut self, item: &mut ItemSig<'a>) -> Result<(), Error> {
+ match &mut item.kind {
+ // Here we must be explicit otherwise the module type reference will
+ // be assumed to be in the component type namespace
+ ItemSigKind::CoreModule(t) => self.core_type_use(t),
+ ItemSigKind::Func(t) => self.component_type_use(t),
+ ItemSigKind::Component(t) => self.component_type_use(t),
+ ItemSigKind::Instance(t) => self.component_type_use(t),
+ ItemSigKind::Value(t) => self.component_val_type(&mut t.0),
+ ItemSigKind::Type(b) => match b {
+ TypeBounds::Eq(i) => self.resolve_ns(i, Ns::Type),
+ },
+ }
+ }
+
+ fn export(&mut self, kind: &mut ComponentExportKind<'a>) -> Result<(), Error> {
+ match kind {
+ // Here we do *not* have to be explicit as the item ref is to a core module
+ ComponentExportKind::CoreModule(r) => self.component_item_ref(r),
+ ComponentExportKind::Func(r) => self.component_item_ref(r),
+ ComponentExportKind::Value(r) => self.component_item_ref(r),
+ ComponentExportKind::Type(r) => self.component_item_ref(r),
+ ComponentExportKind::Component(r) => self.component_item_ref(r),
+ ComponentExportKind::Instance(r) => self.component_item_ref(r),
+ }
+ }
+
+ fn start(&mut self, start: &mut Start<'a>) -> Result<(), Error> {
+ self.resolve_ns(&mut start.func, Ns::Func)?;
+ for arg in start.args.iter_mut() {
+ self.component_item_ref(arg)?;
+ }
+ Ok(())
+ }
+
+ fn outer_alias<T: Into<Ns>>(
+ &mut self,
+ outer: &mut Index<'a>,
+ index: &mut Index<'a>,
+ kind: T,
+ span: Span,
+ enclosing_only: bool,
+ ) -> Result<(), Error> {
+ // Short-circuit when both indices are already resolved as this
+ // helps to write tests for invalid modules where wasmparser should
+ // be the one returning the error.
+ if let Index::Num(..) = outer {
+ if let Index::Num(..) = index {
+ return Ok(());
+ }
+ }
+
+ // Resolve `outer`, and compute the depth at which to look up
+ // `index`.
+ let depth = match outer {
+ Index::Id(id) => {
+ let mut depth = 0;
+ for resolver in self.stack.iter().rev() {
+ if resolver.id == Some(*id) {
+ break;
+ }
+ depth += 1;
+ }
+ if depth as usize == self.stack.len() {
+ return Err(Error::new(
+ span,
+ format!("outer component `{}` not found", id.name()),
+ ));
+ }
+ depth
+ }
+ Index::Num(n, _span) => *n,
+ };
+
+ if depth as usize >= self.stack.len() {
+ return Err(Error::new(
+ span,
+ format!("outer count of `{}` is too large", depth),
+ ));
+ }
+
+ if enclosing_only && depth > 1 {
+ return Err(Error::new(
+ span,
+ "only the local or enclosing scope can be aliased".to_string(),
+ ));
+ }
+
+ *outer = Index::Num(depth, span);
+
+ // Resolve `index` within the computed scope depth.
+ let computed = self.stack.len() - 1 - depth as usize;
+ self.stack[computed].resolve(kind.into(), index)?;
+
+ Ok(())
+ }
+
+ fn alias(&mut self, alias: &mut Alias<'a>, enclosing_only: bool) -> Result<(), Error> {
+ match &mut alias.target {
+ AliasTarget::Export {
+ instance,
+ name: _,
+ kind: _,
+ } => self.resolve_ns(instance, Ns::Instance),
+ AliasTarget::CoreExport {
+ instance,
+ name: _,
+ kind: _,
+ } => self.resolve_ns(instance, Ns::CoreInstance),
+ AliasTarget::Outer { outer, index, kind } => {
+ self.outer_alias(outer, index, *kind, alias.span, enclosing_only)
+ }
+ }
+ }
+
+ fn canonical_func(&mut self, func: &mut CanonicalFunc<'a>) -> Result<(), Error> {
+ let opts = match &mut func.kind {
+ CanonicalFuncKind::Lift { ty, info } => {
+ self.component_type_use(ty)?;
+ self.core_item_ref(&mut info.func)?;
+ &mut info.opts
+ }
+ CanonicalFuncKind::Lower(info) => {
+ self.component_item_ref(&mut info.func)?;
+ &mut info.opts
+ }
+ };
+
+ for opt in opts {
+ match opt {
+ CanonOpt::StringUtf8 | CanonOpt::StringUtf16 | CanonOpt::StringLatin1Utf16 => {}
+ CanonOpt::Memory(r) => self.core_item_ref(r)?,
+ CanonOpt::Realloc(r) | CanonOpt::PostReturn(r) => self.core_item_ref(r)?,
+ }
+ }
+
+ Ok(())
+ }
+
+ fn core_type_use<T>(&mut self, ty: &mut CoreTypeUse<'a, T>) -> Result<(), Error> {
+ let item = match ty {
+ CoreTypeUse::Ref(r) => r,
+ CoreTypeUse::Inline(_) => {
+ unreachable!("inline type-use should be expanded by now")
+ }
+ };
+ self.core_item_ref(item)
+ }
+
+ fn component_type_use<T>(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> {
+ let item = match ty {
+ ComponentTypeUse::Ref(r) => r,
+ ComponentTypeUse::Inline(_) => {
+ unreachable!("inline type-use should be expanded by now")
+ }
+ };
+ self.component_item_ref(item)
+ }
+
+ fn defined_type(&mut self, ty: &mut ComponentDefinedType<'a>) -> Result<(), Error> {
+ match ty {
+ ComponentDefinedType::Primitive(_) => {}
+ ComponentDefinedType::Flags(_) => {}
+ ComponentDefinedType::Enum(_) => {}
+ ComponentDefinedType::Record(r) => {
+ for field in r.fields.iter_mut() {
+ self.component_val_type(&mut field.ty)?;
+ }
+ }
+ ComponentDefinedType::Variant(v) => {
+ // Namespace for case identifier resolution
+ let mut ns = Namespace::default();
+ for case in v.cases.iter_mut() {
+ let index = ns.register(case.id, "variant case")?;
+
+ if let Some(ty) = &mut case.ty {
+ self.component_val_type(ty)?;
+ }
+
+ if let Some(refines) = &mut case.refines {
+ if let Refinement::Index(span, idx) = refines {
+ let resolved = ns.resolve(idx, "variant case")?;
+ if resolved == index {
+ return Err(Error::new(
+ *span,
+ "variant case cannot refine itself".to_string(),
+ ));
+ }
+
+ *refines = Refinement::Resolved(resolved);
+ }
+ }
+ }
+ }
+ ComponentDefinedType::List(l) => {
+ self.component_val_type(&mut l.element)?;
+ }
+ ComponentDefinedType::Tuple(t) => {
+ for field in t.fields.iter_mut() {
+ self.component_val_type(field)?;
+ }
+ }
+ ComponentDefinedType::Union(t) => {
+ for ty in t.types.iter_mut() {
+ self.component_val_type(ty)?;
+ }
+ }
+ ComponentDefinedType::Option(o) => {
+ self.component_val_type(&mut o.element)?;
+ }
+ ComponentDefinedType::Result(r) => {
+ if let Some(ty) = &mut r.ok {
+ self.component_val_type(ty)?;
+ }
+
+ if let Some(ty) = &mut r.err {
+ self.component_val_type(ty)?;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn component_val_type(&mut self, ty: &mut ComponentValType<'a>) -> Result<(), Error> {
+ match ty {
+ ComponentValType::Ref(idx) => self.resolve_ns(idx, Ns::Type),
+ ComponentValType::Inline(ComponentDefinedType::Primitive(_)) => Ok(()),
+ ComponentValType::Inline(_) => unreachable!("should be expanded by now"),
+ }
+ }
+
+ fn core_ty(&mut self, field: &mut CoreType<'a>) -> Result<(), Error> {
+ match &mut field.def {
+ CoreTypeDef::Def(_) => {}
+ CoreTypeDef::Module(t) => {
+ self.stack.push(ComponentState::new(field.id));
+ self.module_type(t)?;
+ self.stack.pop();
+ }
+ }
+ Ok(())
+ }
+
+ fn ty(&mut self, field: &mut Type<'a>) -> Result<(), Error> {
+ match &mut field.def {
+ TypeDef::Defined(t) => {
+ self.defined_type(t)?;
+ }
+ TypeDef::Func(f) => {
+ for param in f.params.iter_mut() {
+ self.component_val_type(&mut param.ty)?;
+ }
+
+ for result in f.results.iter_mut() {
+ self.component_val_type(&mut result.ty)?;
+ }
+ }
+ TypeDef::Component(c) => {
+ self.stack.push(ComponentState::new(field.id));
+ self.component_type(c)?;
+ self.stack.pop();
+ }
+ TypeDef::Instance(i) => {
+ self.stack.push(ComponentState::new(field.id));
+ self.instance_type(i)?;
+ self.stack.pop();
+ }
+ }
+ Ok(())
+ }
+
+ fn component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> {
+ self.resolve_prepending_aliases(
+ &mut c.decls,
+ |resolver, decl| match decl {
+ ComponentTypeDecl::Alias(alias) => resolver.alias(alias, false),
+ ComponentTypeDecl::CoreType(ty) => resolver.core_ty(ty),
+ ComponentTypeDecl::Type(ty) => resolver.ty(ty),
+ ComponentTypeDecl::Import(import) => resolver.item_sig(&mut import.item),
+ ComponentTypeDecl::Export(export) => resolver.item_sig(&mut export.item),
+ },
+ |state, decl| {
+ match decl {
+ ComponentTypeDecl::Alias(alias) => {
+ state.register_alias(alias)?;
+ }
+ ComponentTypeDecl::CoreType(ty) => {
+ state.core_types.register(ty.id, "core type")?;
+ }
+ ComponentTypeDecl::Type(ty) => {
+ state.types.register(ty.id, "type")?;
+ }
+ ComponentTypeDecl::Export(e) => {
+ state.register_item_sig(&e.item)?;
+ }
+ ComponentTypeDecl::Import(i) => {
+ state.register_item_sig(&i.item)?;
+ }
+ }
+ Ok(())
+ },
+ )
+ }
+
+ fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> {
+ self.resolve_prepending_aliases(
+ &mut c.decls,
+ |resolver, decl| match decl {
+ InstanceTypeDecl::Alias(alias) => resolver.alias(alias, false),
+ InstanceTypeDecl::CoreType(ty) => resolver.core_ty(ty),
+ InstanceTypeDecl::Type(ty) => resolver.ty(ty),
+ InstanceTypeDecl::Export(export) => resolver.item_sig(&mut export.item),
+ },
+ |state, decl| {
+ match decl {
+ InstanceTypeDecl::Alias(alias) => {
+ state.register_alias(alias)?;
+ }
+ InstanceTypeDecl::CoreType(ty) => {
+ state.core_types.register(ty.id, "core type")?;
+ }
+ InstanceTypeDecl::Type(ty) => {
+ state.types.register(ty.id, "type")?;
+ }
+ InstanceTypeDecl::Export(export) => {
+ state.register_item_sig(&export.item)?;
+ }
+ }
+ Ok(())
+ },
+ )
+ }
+
+ fn core_item_ref<K>(&mut self, item: &mut CoreItemRef<'a, K>) -> Result<(), Error>
+ where
+ K: CoreItem + Copy,
+ {
+ // Check for not being an instance export reference
+ if item.export_name.is_none() {
+ self.resolve_ns(&mut item.idx, item.kind.ns())?;
+ return Ok(());
+ }
+
+ // This is a reference to a core instance export
+ let mut index = item.idx;
+ self.resolve_ns(&mut index, Ns::CoreInstance)?;
+
+ // Record an alias to reference the export
+ let span = item.idx.span();
+ let alias = Alias {
+ span,
+ id: None,
+ name: None,
+ target: AliasTarget::CoreExport {
+ instance: index,
+ name: item.export_name.unwrap(),
+ kind: item.kind.ns().into(),
+ },
+ };
+
+ index = Index::Num(self.current().register_alias(&alias)?, span);
+ self.aliases_to_insert.push(alias);
+
+ item.idx = index;
+ item.export_name = None;
+
+ Ok(())
+ }
+
+ fn component_item_ref<K>(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error>
+ where
+ K: ComponentItem + Copy,
+ {
+ // Check for not being an instance export reference
+ if item.export_names.is_empty() {
+ self.resolve_ns(&mut item.idx, item.kind.ns())?;
+ return Ok(());
+ }
+
+ // This is a reference to an instance export
+ let mut index = item.idx;
+ self.resolve_ns(&mut index, Ns::Instance)?;
+
+ let span = item.idx.span();
+ for (pos, export_name) in item.export_names.iter().enumerate() {
+ // Record an alias to reference the export
+ let alias = Alias {
+ span,
+ id: None,
+ name: None,
+ target: AliasTarget::Export {
+ instance: index,
+ name: export_name,
+ kind: if pos == item.export_names.len() - 1 {
+ item.kind.ns().into()
+ } else {
+ ComponentExportAliasKind::Instance
+ },
+ },
+ };
+
+ index = Index::Num(self.current().register_alias(&alias)?, span);
+ self.aliases_to_insert.push(alias);
+ }
+
+ item.idx = index;
+ item.export_names = Vec::new();
+
+ Ok(())
+ }
+
+ fn resolve_ns(&mut self, idx: &mut Index<'a>, ns: Ns) -> Result<(), Error> {
+ // Perform resolution on a local clone walking up the stack of components
+ // that we have. Note that a local clone is used since we don't want to use
+ // the parent's resolved index if a parent matches, instead we want to use
+ // the index of the alias that we will automatically insert.
+ let mut idx_clone = *idx;
+ for (depth, resolver) in self.stack.iter_mut().rev().enumerate() {
+ let depth = depth as u32;
+ let found = match resolver.resolve(ns, &mut idx_clone) {
+ Ok(idx) => idx,
+ // Try the next parent
+ Err(_) => continue,
+ };
+
+ // If this is the current component then no extra alias is necessary, so
+ // return success.
+ if depth == 0 {
+ *idx = idx_clone;
+ return Ok(());
+ }
+ let id = match idx {
+ Index::Id(id) => *id,
+ Index::Num(..) => unreachable!(),
+ };
+
+ // When resolution succeeds in a parent then an outer alias is
+ // automatically inserted here in this component.
+ let span = idx.span();
+ let alias = Alias {
+ span,
+ id: Some(id),
+ name: None,
+ target: AliasTarget::Outer {
+ outer: Index::Num(depth, span),
+ index: Index::Num(found, span),
+ kind: ns.into(),
+ },
+ };
+ let local_index = self.current().register_alias(&alias)?;
+ self.aliases_to_insert.push(alias);
+ *idx = Index::Num(local_index, span);
+ return Ok(());
+ }
+
+ // If resolution in any parent failed then simply return the error from our
+ // local namespace
+ self.current().resolve(ns, idx)?;
+ unreachable!()
+ }
+
+ fn module_type(&mut self, ty: &mut ModuleType<'a>) -> Result<(), Error> {
+ return self.resolve_prepending_aliases(
+ &mut ty.decls,
+ |resolver, decl| match decl {
+ ModuleTypeDecl::Alias(alias) => resolver.alias(alias, true),
+ ModuleTypeDecl::Type(_) => Ok(()),
+ ModuleTypeDecl::Import(import) => resolve_item_sig(resolver, &mut import.item),
+ ModuleTypeDecl::Export(_, item) => resolve_item_sig(resolver, item),
+ },
+ |state, decl| {
+ match decl {
+ ModuleTypeDecl::Alias(alias) => {
+ state.register_alias(alias)?;
+ }
+ ModuleTypeDecl::Type(ty) => {
+ state.core_types.register(ty.id, "type")?;
+ }
+ // Only the type namespace is populated within the module type
+ // namespace so these are ignored here.
+ ModuleTypeDecl::Import(_) | ModuleTypeDecl::Export(..) => {}
+ }
+ Ok(())
+ },
+ );
+
+ fn resolve_item_sig<'a>(
+ resolver: &Resolver<'a>,
+ sig: &mut core::ItemSig<'a>,
+ ) -> Result<(), Error> {
+ match &mut sig.kind {
+ core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => {
+ let idx = ty.index.as_mut().expect("index should be filled in");
+ resolver
+ .stack
+ .last()
+ .unwrap()
+ .core_types
+ .resolve(idx, "type")?;
+ }
+ core::ItemKind::Memory(_)
+ | core::ItemKind::Global(_)
+ | core::ItemKind::Table(_) => {}
+ }
+ Ok(())
+ }
+ }
+}
+
+impl<'a> ComponentState<'a> {
+ fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result<u32, Error> {
+ match ns {
+ Ns::CoreFunc => self.core_funcs.resolve(idx, "core func"),
+ Ns::CoreGlobal => self.core_globals.resolve(idx, "core global"),
+ Ns::CoreTable => self.core_tables.resolve(idx, "core table"),
+ Ns::CoreMemory => self.core_memories.resolve(idx, "core memory"),
+ Ns::CoreType => self.core_types.resolve(idx, "core type"),
+ Ns::CoreTag => self.core_tags.resolve(idx, "core tag"),
+ Ns::CoreInstance => self.core_instances.resolve(idx, "core instance"),
+ Ns::CoreModule => self.core_modules.resolve(idx, "core module"),
+ Ns::Func => self.funcs.resolve(idx, "func"),
+ Ns::Type => self.types.resolve(idx, "type"),
+ Ns::Instance => self.instances.resolve(idx, "instance"),
+ Ns::Component => self.components.resolve(idx, "component"),
+ Ns::Value => self.values.resolve(idx, "value"),
+ }
+ }
+
+ /// Assign an index to the given field.
+ fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> {
+ match item {
+ ComponentField::CoreModule(m) => self.core_modules.register(m.id, "core module")?,
+ ComponentField::CoreInstance(i) => {
+ self.core_instances.register(i.id, "core instance")?
+ }
+ ComponentField::CoreType(t) => self.core_types.register(t.id, "core type")?,
+ ComponentField::Component(c) => self.components.register(c.id, "component")?,
+ ComponentField::Instance(i) => self.instances.register(i.id, "instance")?,
+ ComponentField::Alias(a) => self.register_alias(a)?,
+ ComponentField::Type(t) => self.types.register(t.id, "type")?,
+ ComponentField::CanonicalFunc(f) => match &f.kind {
+ CanonicalFuncKind::Lift { .. } => self.funcs.register(f.id, "func")?,
+ CanonicalFuncKind::Lower(_) => self.core_funcs.register(f.id, "core func")?,
+ },
+ ComponentField::CoreFunc(_) | ComponentField::Func(_) => {
+ unreachable!("should be expanded already")
+ }
+ ComponentField::Start(s) => {
+ for r in &s.results {
+ self.values.register(*r, "value")?;
+ }
+ return Ok(());
+ }
+ ComponentField::Import(i) => self.register_item_sig(&i.item)?,
+ ComponentField::Export(e) => match &e.kind {
+ ComponentExportKind::CoreModule(_) => {
+ self.core_modules.register(e.id, "core module")?
+ }
+ ComponentExportKind::Func(_) => self.funcs.register(e.id, "func")?,
+ ComponentExportKind::Instance(_) => self.instances.register(e.id, "instance")?,
+ ComponentExportKind::Value(_) => self.values.register(e.id, "value")?,
+ ComponentExportKind::Component(_) => self.components.register(e.id, "component")?,
+ ComponentExportKind::Type(_) => self.types.register(e.id, "type")?,
+ },
+ ComponentField::Custom(_) => return Ok(()),
+ };
+
+ Ok(())
+ }
+
+ fn register_alias(&mut self, alias: &Alias<'a>) -> Result<u32, Error> {
+ match alias.target {
+ AliasTarget::Export { kind, .. } => match kind {
+ ComponentExportAliasKind::CoreModule => {
+ self.core_modules.register(alias.id, "core module")
+ }
+ ComponentExportAliasKind::Func => self.funcs.register(alias.id, "func"),
+ ComponentExportAliasKind::Value => self.values.register(alias.id, "value"),
+ ComponentExportAliasKind::Type => self.types.register(alias.id, "type"),
+ ComponentExportAliasKind::Component => {
+ self.components.register(alias.id, "component")
+ }
+ ComponentExportAliasKind::Instance => self.instances.register(alias.id, "instance"),
+ },
+ AliasTarget::CoreExport { kind, .. } => match kind {
+ core::ExportKind::Func => self.core_funcs.register(alias.id, "core func"),
+ core::ExportKind::Table => self.core_tables.register(alias.id, "core table"),
+ core::ExportKind::Memory => self.core_memories.register(alias.id, "core memory"),
+ core::ExportKind::Global => self.core_globals.register(alias.id, "core global"),
+ core::ExportKind::Tag => self.core_tags.register(alias.id, "core tag"),
+ },
+ AliasTarget::Outer { kind, .. } => match kind {
+ ComponentOuterAliasKind::CoreModule => {
+ self.core_modules.register(alias.id, "core module")
+ }
+ ComponentOuterAliasKind::CoreType => {
+ self.core_types.register(alias.id, "core type")
+ }
+ ComponentOuterAliasKind::Type => self.types.register(alias.id, "type"),
+ ComponentOuterAliasKind::Component => {
+ self.components.register(alias.id, "component")
+ }
+ },
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
+enum Ns {
+ CoreFunc,
+ CoreGlobal,
+ CoreTable,
+ CoreMemory,
+ CoreType,
+ CoreTag,
+ CoreInstance,
+ CoreModule,
+ Func,
+ Type,
+ Instance,
+ Component,
+ Value,
+}
+
+trait ComponentItem {
+ fn ns(&self) -> Ns;
+}
+
+trait CoreItem {
+ fn ns(&self) -> Ns;
+}
+
+macro_rules! component_item {
+ ($kw:path, $kind:ident) => {
+ impl ComponentItem for $kw {
+ fn ns(&self) -> Ns {
+ Ns::$kind
+ }
+ }
+ };
+}
+
+macro_rules! core_item {
+ ($kw:path, $kind:ident) => {
+ impl CoreItem for $kw {
+ fn ns(&self) -> Ns {
+ Ns::$kind
+ }
+ }
+ };
+}
+
+component_item!(kw::func, Func);
+component_item!(kw::r#type, Type);
+component_item!(kw::r#instance, Instance);
+component_item!(kw::component, Component);
+component_item!(kw::value, Value);
+component_item!(kw::module, CoreModule);
+
+core_item!(kw::func, CoreFunc);
+core_item!(kw::memory, CoreMemory);
+core_item!(kw::r#type, CoreType);
+core_item!(kw::r#instance, CoreInstance);
+
+impl From<Ns> for ComponentExportAliasKind {
+ fn from(ns: Ns) -> Self {
+ match ns {
+ Ns::CoreModule => Self::CoreModule,
+ Ns::Func => Self::Func,
+ Ns::Type => Self::Type,
+ Ns::Instance => Self::Instance,
+ Ns::Component => Self::Component,
+ Ns::Value => Self::Value,
+ _ => unreachable!("not a component exportable namespace"),
+ }
+ }
+}
+
+impl From<Ns> for ComponentOuterAliasKind {
+ fn from(ns: Ns) -> Self {
+ match ns {
+ Ns::CoreModule => Self::CoreModule,
+ Ns::CoreType => Self::CoreType,
+ Ns::Type => Self::Type,
+ Ns::Component => Self::Component,
+ _ => unreachable!("not an outer alias namespace"),
+ }
+ }
+}
+
+impl From<Ns> for core::ExportKind {
+ fn from(ns: Ns) -> Self {
+ match ns {
+ Ns::CoreFunc => Self::Func,
+ Ns::CoreTable => Self::Table,
+ Ns::CoreGlobal => Self::Global,
+ Ns::CoreMemory => Self::Memory,
+ Ns::CoreTag => Self::Tag,
+ _ => unreachable!("not a core exportable namespace"),
+ }
+ }
+}
+
+impl From<ComponentOuterAliasKind> for Ns {
+ fn from(kind: ComponentOuterAliasKind) -> Self {
+ match kind {
+ ComponentOuterAliasKind::CoreModule => Self::CoreModule,
+ ComponentOuterAliasKind::CoreType => Self::CoreType,
+ ComponentOuterAliasKind::Type => Self::Type,
+ ComponentOuterAliasKind::Component => Self::Component,
+ }
+ }
+}
+
+impl CoreItem for core::ExportKind {
+ fn ns(&self) -> Ns {
+ match self {
+ Self::Func => Ns::CoreFunc,
+ Self::Table => Ns::CoreTable,
+ Self::Global => Ns::CoreGlobal,
+ Self::Memory => Ns::CoreMemory,
+ Self::Tag => Ns::CoreTag,
+ }
+ }
+}
diff --git a/third_party/rust/wast/src/component/types.rs b/third_party/rust/wast/src/component/types.rs
new file mode 100644
index 0000000000..0ff8cc0183
--- /dev/null
+++ b/third_party/rust/wast/src/component/types.rs
@@ -0,0 +1,965 @@
+use crate::component::*;
+use crate::core;
+use crate::kw;
+use crate::parser::Lookahead1;
+use crate::parser::Peek;
+use crate::parser::{Parse, Parser, Result};
+use crate::token::Index;
+use crate::token::LParen;
+use crate::token::{Id, NameAnnotation, Span};
+
+/// A core type declaration.
+#[derive(Debug)]
+pub struct CoreType<'a> {
+ /// Where this type was defined.
+ pub span: Span,
+ /// An optional identifier to refer to this `core type` by as part of name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// An optional name for this type stored in the custom `name` section.
+ pub name: Option<NameAnnotation<'a>>,
+ /// The core type's definition.
+ pub def: CoreTypeDef<'a>,
+}
+
+impl<'a> Parse<'a> for CoreType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::core>()?.0;
+ parser.parse::<kw::r#type>()?;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let def = parser.parens(|p| p.parse())?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ def,
+ })
+ }
+}
+
+/// Represents a core type definition.
+///
+/// In the future this may be removed when module types are a part of
+/// a core module.
+#[derive(Debug)]
+pub enum CoreTypeDef<'a> {
+ /// The type definition is one of the core types.
+ Def(core::TypeDef<'a>),
+ /// The type definition is a module type.
+ Module(ModuleType<'a>),
+}
+
+impl<'a> Parse<'a> for CoreTypeDef<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<kw::module>() {
+ parser.parse::<kw::module>()?;
+ Ok(Self::Module(parser.parse()?))
+ } else {
+ Ok(Self::Def(parser.parse()?))
+ }
+ }
+}
+
+/// A type definition for a core module.
+#[derive(Debug)]
+pub struct ModuleType<'a> {
+ /// The declarations of the module type.
+ pub decls: Vec<ModuleTypeDecl<'a>>,
+}
+
+impl<'a> Parse<'a> for ModuleType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ Ok(Self {
+ decls: parser.parse()?,
+ })
+ }
+}
+
+/// The declarations of a [`ModuleType`].
+#[derive(Debug)]
+pub enum ModuleTypeDecl<'a> {
+ /// A core type.
+ Type(core::Type<'a>),
+ /// An alias local to the component type.
+ Alias(Alias<'a>),
+ /// An import.
+ Import(core::Import<'a>),
+ /// An export.
+ Export(&'a str, core::ItemSig<'a>),
+}
+
+impl<'a> Parse<'a> for ModuleTypeDecl<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::r#type>() {
+ Ok(Self::Type(parser.parse()?))
+ } else if l.peek::<kw::alias>() {
+ Ok(Self::Alias(Alias::parse_outer_core_type_alias(parser)?))
+ } else if l.peek::<kw::import>() {
+ Ok(Self::Import(parser.parse()?))
+ } else if l.peek::<kw::export>() {
+ parser.parse::<kw::export>()?;
+ let name = parser.parse()?;
+ let et = parser.parens(|parser| parser.parse())?;
+ Ok(Self::Export(name, et))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl<'a> Parse<'a> for Vec<ModuleTypeDecl<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut decls = Vec::new();
+ while !parser.is_empty() {
+ decls.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(decls)
+ }
+}
+
+/// A type declaration in a component.
+#[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 type 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>,
+ /// The type definition.
+ pub def: TypeDef<'a>,
+}
+
+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 exports = parser.parse()?;
+ let def = parser.parse()?;
+
+ Ok(Self {
+ span,
+ id,
+ name,
+ exports,
+ def,
+ })
+ }
+}
+
+/// A definition of a component type.
+#[derive(Debug)]
+pub enum TypeDef<'a> {
+ /// A defined value type.
+ Defined(ComponentDefinedType<'a>),
+ /// A component function type.
+ Func(ComponentFunctionType<'a>),
+ /// A component type.
+ Component(ComponentType<'a>),
+ /// An instance type.
+ Instance(InstanceType<'a>),
+}
+
+impl<'a> Parse<'a> for TypeDef<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<LParen>() {
+ parser.parens(|parser| {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::func>() {
+ parser.parse::<kw::func>()?;
+ Ok(Self::Func(parser.parse()?))
+ } else if l.peek::<kw::component>() {
+ parser.parse::<kw::component>()?;
+ Ok(Self::Component(parser.parse()?))
+ } else if l.peek::<kw::instance>() {
+ parser.parse::<kw::instance>()?;
+ Ok(Self::Instance(parser.parse()?))
+ } else {
+ Ok(Self::Defined(ComponentDefinedType::parse_non_primitive(
+ parser, l,
+ )?))
+ }
+ })
+ } else {
+ // Only primitive types have no parens
+ Ok(Self::Defined(ComponentDefinedType::Primitive(
+ parser.parse()?,
+ )))
+ }
+ }
+}
+
+/// A primitive value type.
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PrimitiveValType {
+ Bool,
+ S8,
+ U8,
+ S16,
+ U16,
+ S32,
+ U32,
+ S64,
+ U64,
+ Float32,
+ Float64,
+ Char,
+ String,
+}
+
+impl<'a> Parse<'a> for PrimitiveValType {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::bool_>() {
+ parser.parse::<kw::bool_>()?;
+ Ok(Self::Bool)
+ } else if l.peek::<kw::s8>() {
+ parser.parse::<kw::s8>()?;
+ Ok(Self::S8)
+ } else if l.peek::<kw::u8>() {
+ parser.parse::<kw::u8>()?;
+ Ok(Self::U8)
+ } else if l.peek::<kw::s16>() {
+ parser.parse::<kw::s16>()?;
+ Ok(Self::S16)
+ } else if l.peek::<kw::u16>() {
+ parser.parse::<kw::u16>()?;
+ Ok(Self::U16)
+ } else if l.peek::<kw::s32>() {
+ parser.parse::<kw::s32>()?;
+ Ok(Self::S32)
+ } else if l.peek::<kw::u32>() {
+ parser.parse::<kw::u32>()?;
+ Ok(Self::U32)
+ } else if l.peek::<kw::s64>() {
+ parser.parse::<kw::s64>()?;
+ Ok(Self::S64)
+ } else if l.peek::<kw::u64>() {
+ parser.parse::<kw::u64>()?;
+ Ok(Self::U64)
+ } else if l.peek::<kw::float32>() {
+ parser.parse::<kw::float32>()?;
+ Ok(Self::Float32)
+ } else if l.peek::<kw::float64>() {
+ parser.parse::<kw::float64>()?;
+ Ok(Self::Float64)
+ } else if l.peek::<kw::char>() {
+ parser.parse::<kw::char>()?;
+ Ok(Self::Char)
+ } else if l.peek::<kw::string>() {
+ parser.parse::<kw::string>()?;
+ Ok(Self::String)
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl Peek for PrimitiveValType {
+ fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
+ matches!(
+ cursor.keyword(),
+ Some(("bool", _))
+ | Some(("s8", _))
+ | Some(("u8", _))
+ | Some(("s16", _))
+ | Some(("u16", _))
+ | Some(("s32", _))
+ | Some(("u32", _))
+ | Some(("s64", _))
+ | Some(("u64", _))
+ | Some(("float32", _))
+ | Some(("float64", _))
+ | Some(("char", _))
+ | Some(("string", _))
+ )
+ }
+
+ fn display() -> &'static str {
+ "primitive value type"
+ }
+}
+
+/// A component value type.
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub enum ComponentValType<'a> {
+ /// The value type is an inline defined type.
+ Inline(ComponentDefinedType<'a>),
+ /// The value type is an index reference to a defined type.
+ Ref(Index<'a>),
+}
+
+impl<'a> Parse<'a> for ComponentValType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<Index<'_>>() {
+ Ok(Self::Ref(parser.parse()?))
+ } else {
+ Ok(Self::Inline(InlineComponentValType::parse(parser)?.0))
+ }
+ }
+}
+
+impl Peek for ComponentValType<'_> {
+ fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
+ Index::peek(cursor) || ComponentDefinedType::peek(cursor)
+ }
+
+ fn display() -> &'static str {
+ "component value type"
+ }
+}
+
+/// An inline-only component value type.
+///
+/// This variation does not parse type indexes.
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub struct InlineComponentValType<'a>(ComponentDefinedType<'a>);
+
+impl<'a> Parse<'a> for InlineComponentValType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<LParen>() {
+ parser.parens(|parser| {
+ Ok(Self(ComponentDefinedType::parse_non_primitive(
+ parser,
+ parser.lookahead1(),
+ )?))
+ })
+ } else {
+ Ok(Self(ComponentDefinedType::Primitive(parser.parse()?)))
+ }
+ }
+}
+
+// A component defined type.
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub enum ComponentDefinedType<'a> {
+ Primitive(PrimitiveValType),
+ Record(Record<'a>),
+ Variant(Variant<'a>),
+ List(List<'a>),
+ Tuple(Tuple<'a>),
+ Flags(Flags<'a>),
+ Enum(Enum<'a>),
+ Union(Union<'a>),
+ Option(OptionType<'a>),
+ Result(ResultType<'a>),
+}
+
+impl<'a> ComponentDefinedType<'a> {
+ fn parse_non_primitive(parser: Parser<'a>, mut l: Lookahead1<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ if l.peek::<kw::record>() {
+ Ok(Self::Record(parser.parse()?))
+ } else if l.peek::<kw::variant>() {
+ Ok(Self::Variant(parser.parse()?))
+ } else if l.peek::<kw::list>() {
+ Ok(Self::List(parser.parse()?))
+ } else if l.peek::<kw::tuple>() {
+ Ok(Self::Tuple(parser.parse()?))
+ } else if l.peek::<kw::flags>() {
+ Ok(Self::Flags(parser.parse()?))
+ } else if l.peek::<kw::enum_>() {
+ Ok(Self::Enum(parser.parse()?))
+ } else if l.peek::<kw::union>() {
+ Ok(Self::Union(parser.parse()?))
+ } else if l.peek::<kw::option>() {
+ Ok(Self::Option(parser.parse()?))
+ } else if l.peek::<kw::result>() {
+ Ok(Self::Result(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl Default for ComponentDefinedType<'_> {
+ fn default() -> Self {
+ Self::Primitive(PrimitiveValType::Bool)
+ }
+}
+
+impl Peek for ComponentDefinedType<'_> {
+ fn peek(cursor: crate::parser::Cursor<'_>) -> bool {
+ if PrimitiveValType::peek(cursor) {
+ return true;
+ }
+
+ match cursor.lparen() {
+ Some(cursor) => matches!(
+ cursor.keyword(),
+ Some(("record", _))
+ | Some(("variant", _))
+ | Some(("list", _))
+ | Some(("tuple", _))
+ | Some(("flags", _))
+ | Some(("enum", _))
+ | Some(("union", _))
+ | Some(("option", _))
+ | Some(("result", _))
+ ),
+ None => false,
+ }
+ }
+
+ fn display() -> &'static str {
+ "component defined type"
+ }
+}
+
+/// A record defined type.
+#[derive(Debug)]
+pub struct Record<'a> {
+ /// The fields of the record.
+ pub fields: Vec<RecordField<'a>>,
+}
+
+impl<'a> Parse<'a> for Record<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::record>()?;
+ let mut fields = Vec::new();
+ while !parser.is_empty() {
+ fields.push(parser.parens(|p| p.parse())?);
+ }
+ Ok(Self { fields })
+ }
+}
+
+/// A record type field.
+#[derive(Debug)]
+pub struct RecordField<'a> {
+ /// The name of the field.
+ pub name: &'a str,
+ /// The type of the field.
+ pub ty: ComponentValType<'a>,
+}
+
+impl<'a> Parse<'a> for RecordField<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::field>()?;
+ Ok(Self {
+ name: parser.parse()?,
+ ty: parser.parse()?,
+ })
+ }
+}
+
+/// A variant defined type.
+#[derive(Debug)]
+pub struct Variant<'a> {
+ /// The cases of the variant type.
+ pub cases: Vec<VariantCase<'a>>,
+}
+
+impl<'a> Parse<'a> for Variant<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::variant>()?;
+ let mut cases = Vec::new();
+ while !parser.is_empty() {
+ cases.push(parser.parens(|p| p.parse())?);
+ }
+ Ok(Self { cases })
+ }
+}
+
+/// A case of a variant type.
+#[derive(Debug)]
+pub struct VariantCase<'a> {
+ /// Where this `case` was defined
+ pub span: Span,
+ /// An optional identifier to refer to this case by as part of name
+ /// resolution.
+ pub id: Option<Id<'a>>,
+ /// The name of the case.
+ pub name: &'a str,
+ /// The optional type of the case.
+ pub ty: Option<ComponentValType<'a>>,
+ /// The optional refinement.
+ pub refines: Option<Refinement<'a>>,
+}
+
+impl<'a> Parse<'a> for VariantCase<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::case>()?.0;
+ let id = parser.parse()?;
+ let name = parser.parse()?;
+ let ty = parser.parse()?;
+ let refines = if !parser.is_empty() {
+ Some(parser.parse()?)
+ } else {
+ None
+ };
+ Ok(Self {
+ span,
+ id,
+ name,
+ ty,
+ refines,
+ })
+ }
+}
+
+/// A refinement for a variant case.
+#[derive(Debug)]
+pub enum Refinement<'a> {
+ /// The refinement is referenced by index.
+ Index(Span, Index<'a>),
+ /// The refinement has been resolved to an index into
+ /// the cases of the variant.
+ Resolved(u32),
+}
+
+impl<'a> Parse<'a> for Refinement<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parens(|parser| {
+ let span = parser.parse::<kw::refines>()?.0;
+ let id = parser.parse()?;
+ Ok(Self::Index(span, id))
+ })
+ }
+}
+
+/// A list type.
+#[derive(Debug)]
+pub struct List<'a> {
+ /// The element type of the array.
+ pub element: Box<ComponentValType<'a>>,
+}
+
+impl<'a> Parse<'a> for List<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::list>()?;
+ Ok(Self {
+ element: Box::new(parser.parse()?),
+ })
+ }
+}
+
+/// A tuple type.
+#[derive(Debug)]
+pub struct Tuple<'a> {
+ /// The types of the fields of the tuple.
+ pub fields: Vec<ComponentValType<'a>>,
+}
+
+impl<'a> Parse<'a> for Tuple<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::tuple>()?;
+ let mut fields = Vec::new();
+ while !parser.is_empty() {
+ fields.push(parser.parse()?);
+ }
+ Ok(Self { fields })
+ }
+}
+
+/// A flags type.
+#[derive(Debug)]
+pub struct Flags<'a> {
+ /// The names of the individual flags.
+ pub names: Vec<&'a str>,
+}
+
+impl<'a> Parse<'a> for Flags<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::flags>()?;
+ let mut names = Vec::new();
+ while !parser.is_empty() {
+ names.push(parser.parse()?);
+ }
+ Ok(Self { names })
+ }
+}
+
+/// An enum type.
+#[derive(Debug)]
+pub struct Enum<'a> {
+ /// The tag names of the enum.
+ pub names: Vec<&'a str>,
+}
+
+impl<'a> Parse<'a> for Enum<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::enum_>()?;
+ let mut names = Vec::new();
+ while !parser.is_empty() {
+ names.push(parser.parse()?);
+ }
+ Ok(Self { names })
+ }
+}
+
+/// A union type.
+#[derive(Debug)]
+pub struct Union<'a> {
+ /// The types of the union.
+ pub types: Vec<ComponentValType<'a>>,
+}
+
+impl<'a> Parse<'a> for Union<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::union>()?;
+ let mut types = Vec::new();
+ while !parser.is_empty() {
+ types.push(parser.parse()?);
+ }
+ Ok(Self { types })
+ }
+}
+
+/// An optional type.
+#[derive(Debug)]
+pub struct OptionType<'a> {
+ /// The type of the value, when a value is present.
+ pub element: Box<ComponentValType<'a>>,
+}
+
+impl<'a> Parse<'a> for OptionType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::option>()?;
+ Ok(Self {
+ element: Box::new(parser.parse()?),
+ })
+ }
+}
+
+/// A result type.
+#[derive(Debug)]
+pub struct ResultType<'a> {
+ /// The type on success.
+ pub ok: Option<Box<ComponentValType<'a>>>,
+ /// The type on failure.
+ pub err: Option<Box<ComponentValType<'a>>>,
+}
+
+impl<'a> Parse<'a> for ResultType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::result>()?;
+
+ let ok: Option<ComponentValType> = parser.parse()?;
+ let err: Option<ComponentValType> = if parser.peek::<LParen>() {
+ Some(parser.parens(|parser| {
+ parser.parse::<kw::error>()?;
+ parser.parse()
+ })?)
+ } else {
+ None
+ };
+
+ Ok(Self {
+ ok: ok.map(Box::new),
+ err: err.map(Box::new),
+ })
+ }
+}
+
+/// A component function type with parameters and result.
+#[derive(Debug)]
+pub struct ComponentFunctionType<'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<[ComponentFunctionParam<'a>]>,
+ /// The result of a function, optionally each having an identifier for
+ /// name resolution and a name for the custom `name` section.
+ pub results: Box<[ComponentFunctionResult<'a>]>,
+}
+
+impl<'a> Parse<'a> for ComponentFunctionType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut params: Vec<ComponentFunctionParam> = Vec::new();
+ while parser.peek2::<kw::param>() {
+ params.push(parser.parens(|p| p.parse())?);
+ }
+
+ let mut results: Vec<ComponentFunctionResult> = Vec::new();
+ while parser.peek2::<kw::result>() {
+ results.push(parser.parens(|p| p.parse())?);
+ }
+
+ Ok(Self {
+ params: params.into(),
+ results: results.into(),
+ })
+ }
+}
+
+/// A parameter of a [`ComponentFunctionType`].
+#[derive(Debug)]
+pub struct ComponentFunctionParam<'a> {
+ /// The name of the parameter
+ pub name: &'a str,
+ /// The type of the parameter.
+ pub ty: ComponentValType<'a>,
+}
+
+impl<'a> Parse<'a> for ComponentFunctionParam<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::param>()?;
+ Ok(Self {
+ name: parser.parse()?,
+ ty: parser.parse()?,
+ })
+ }
+}
+
+/// A result of a [`ComponentFunctionType`].
+#[derive(Debug)]
+pub struct ComponentFunctionResult<'a> {
+ /// An optionally-specified name of this result
+ pub name: Option<&'a str>,
+ /// The type of the result.
+ pub ty: ComponentValType<'a>,
+}
+
+impl<'a> Parse<'a> for ComponentFunctionResult<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.parse::<kw::result>()?;
+ Ok(Self {
+ name: parser.parse()?,
+ ty: parser.parse()?,
+ })
+ }
+}
+
+/// The type of an exported item from an component or instance type.
+#[derive(Debug)]
+pub struct ComponentExportType<'a> {
+ /// Where this export was defined.
+ pub span: Span,
+ /// The name of this export.
+ pub name: &'a str,
+ /// The optional URL of this export.
+ pub url: Option<&'a str>,
+ /// The signature of the item.
+ pub item: ItemSig<'a>,
+}
+
+impl<'a> Parse<'a> for ComponentExportType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let span = parser.parse::<kw::export>()?.0;
+ let id = parser.parse()?;
+ let debug_name = parser.parse()?;
+ let name = parser.parse()?;
+ let url = parser.parse()?;
+ let item = parser.parens(|p| {
+ let mut item = p.parse::<ItemSigNoName<'_>>()?.0;
+ item.id = id;
+ item.name = debug_name;
+ Ok(item)
+ })?;
+ Ok(Self {
+ span,
+ name,
+ url,
+ item,
+ })
+ }
+}
+
+/// A type definition for a component type.
+#[derive(Debug, Default)]
+pub struct ComponentType<'a> {
+ /// The declarations of the component type.
+ pub decls: Vec<ComponentTypeDecl<'a>>,
+}
+
+impl<'a> Parse<'a> for ComponentType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ Ok(Self {
+ decls: parser.parse()?,
+ })
+ }
+}
+
+/// A declaration of a component type.
+#[derive(Debug)]
+pub enum ComponentTypeDecl<'a> {
+ /// A core type definition local to the component type.
+ CoreType(CoreType<'a>),
+ /// A type definition local to the component type.
+ Type(Type<'a>),
+ /// An alias local to the component type.
+ Alias(Alias<'a>),
+ /// An import of the component type.
+ Import(ComponentImport<'a>),
+ /// An export of the component type.
+ Export(ComponentExportType<'a>),
+}
+
+impl<'a> Parse<'a> for ComponentTypeDecl<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::core>() {
+ Ok(Self::CoreType(parser.parse()?))
+ } else if l.peek::<kw::r#type>() {
+ Ok(Self::Type(parser.parse()?))
+ } else if l.peek::<kw::alias>() {
+ Ok(Self::Alias(parser.parse()?))
+ } else if l.peek::<kw::import>() {
+ Ok(Self::Import(parser.parse()?))
+ } else if l.peek::<kw::export>() {
+ Ok(Self::Export(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl<'a> Parse<'a> for Vec<ComponentTypeDecl<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut decls = Vec::new();
+ while !parser.is_empty() {
+ decls.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(decls)
+ }
+}
+
+/// A type definition for an instance type.
+#[derive(Debug)]
+pub struct InstanceType<'a> {
+ /// The declarations of the instance type.
+ pub decls: Vec<InstanceTypeDecl<'a>>,
+}
+
+impl<'a> Parse<'a> for InstanceType<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ Ok(Self {
+ decls: parser.parse()?,
+ })
+ }
+}
+
+/// A declaration of an instance type.
+#[derive(Debug)]
+pub enum InstanceTypeDecl<'a> {
+ /// A core type definition local to the component type.
+ CoreType(CoreType<'a>),
+ /// A type definition local to the instance type.
+ Type(Type<'a>),
+ /// An alias local to the instance type.
+ Alias(Alias<'a>),
+ /// An export of the instance type.
+ Export(ComponentExportType<'a>),
+}
+
+impl<'a> Parse<'a> for InstanceTypeDecl<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut l = parser.lookahead1();
+ if l.peek::<kw::core>() {
+ Ok(Self::CoreType(parser.parse()?))
+ } else if l.peek::<kw::r#type>() {
+ Ok(Self::Type(parser.parse()?))
+ } else if l.peek::<kw::alias>() {
+ Ok(Self::Alias(parser.parse()?))
+ } else if l.peek::<kw::export>() {
+ Ok(Self::Export(parser.parse()?))
+ } else {
+ Err(l.error())
+ }
+ }
+}
+
+impl<'a> Parse<'a> for Vec<InstanceTypeDecl<'a>> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ let mut decls = Vec::new();
+ while !parser.is_empty() {
+ decls.push(parser.parens(|parser| parser.parse())?);
+ }
+ Ok(decls)
+ }
+}
+
+/// A value type declaration used for values in import signatures.
+#[derive(Debug)]
+pub struct ComponentValTypeUse<'a>(pub ComponentValType<'a>);
+
+impl<'a> Parse<'a> for ComponentValTypeUse<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ match ComponentTypeUse::<'a, InlineComponentValType<'a>>::parse(parser)? {
+ ComponentTypeUse::Ref(i) => Ok(Self(ComponentValType::Ref(i.idx))),
+ ComponentTypeUse::Inline(t) => Ok(Self(ComponentValType::Inline(t.0))),
+ }
+ }
+}
+
+/// A reference to a core type defined in this component.
+///
+/// This is the same as `TypeUse`, but accepts `$T` as shorthand for
+/// `(type $T)`.
+#[derive(Debug, Clone)]
+pub enum CoreTypeUse<'a, T> {
+ /// The type that we're referencing.
+ Ref(CoreItemRef<'a, kw::r#type>),
+ /// The inline type.
+ Inline(T),
+}
+
+impl<'a, T: Parse<'a>> Parse<'a> for CoreTypeUse<'a, T> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ // Here the core context is assumed, so no core prefix is expected
+ if parser.peek::<LParen>() && parser.peek2::<CoreItemRef<'a, kw::r#type>>() {
+ Ok(Self::Ref(parser.parens(|parser| parser.parse())?))
+ } else {
+ Ok(Self::Inline(parser.parse()?))
+ }
+ }
+}
+
+impl<T> Default for CoreTypeUse<'_, T> {
+ fn default() -> Self {
+ let span = Span::from_offset(0);
+ Self::Ref(CoreItemRef {
+ idx: Index::Num(0, span),
+ kind: kw::r#type(span),
+ export_name: None,
+ })
+ }
+}
+
+/// A reference to a type defined in this component.
+///
+/// This is the same as `TypeUse`, but accepts `$T` as shorthand for
+/// `(type $T)`.
+#[derive(Debug, Clone)]
+pub enum ComponentTypeUse<'a, T> {
+ /// The type that we're referencing.
+ Ref(ItemRef<'a, kw::r#type>),
+ /// The inline type.
+ Inline(T),
+}
+
+impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ if parser.peek::<LParen>() && parser.peek2::<ItemRef<'a, kw::r#type>>() {
+ Ok(Self::Ref(parser.parens(|parser| parser.parse())?))
+ } else {
+ Ok(Self::Inline(parser.parse()?))
+ }
+ }
+}
+
+impl<T> Default for ComponentTypeUse<'_, T> {
+ fn default() -> Self {
+ let span = Span::from_offset(0);
+ Self::Ref(ItemRef {
+ idx: Index::Num(0, span),
+ kind: kw::r#type(span),
+ export_names: Vec::new(),
+ })
+ }
+}
diff --git a/third_party/rust/wast/src/component/wast.rs b/third_party/rust/wast/src/component/wast.rs
new file mode 100644
index 0000000000..8409a6c969
--- /dev/null
+++ b/third_party/rust/wast/src/component/wast.rs
@@ -0,0 +1,166 @@
+use crate::kw;
+use crate::parser::{Cursor, Parse, Parser, Peek, Result};
+use crate::token::{Float32, Float64};
+
+/// Expression that can be used inside of `invoke` expressions for core wasm
+/// functions.
+#[derive(Debug)]
+#[allow(missing_docs)]
+pub enum WastVal<'a> {
+ Bool(bool),
+ U8(u8),
+ S8(i8),
+ U16(u16),
+ S16(i16),
+ U32(u32),
+ S32(i32),
+ U64(u64),
+ S64(i64),
+ Float32(Float32),
+ Float64(Float64),
+ Char(char),
+ String(&'a str),
+ List(Vec<WastVal<'a>>),
+ Record(Vec<(&'a str, WastVal<'a>)>),
+ Tuple(Vec<WastVal<'a>>),
+ Variant(&'a str, Option<Box<WastVal<'a>>>),
+ Enum(&'a str),
+ Union(u32, Box<WastVal<'a>>),
+ Option(Option<Box<WastVal<'a>>>),
+ Result(Result<Option<Box<WastVal<'a>>>, Option<Box<WastVal<'a>>>>),
+ Flags(Vec<&'a str>),
+}
+
+static CASES: &[(&str, fn(Parser<'_>) -> Result<WastVal<'_>>)] = {
+ use WastVal::*;
+ &[
+ ("bool.const", |p| {
+ let mut l = p.lookahead1();
+ if l.peek::<kw::true_>() {
+ p.parse::<kw::true_>()?;
+ Ok(Bool(true))
+ } else if l.peek::<kw::false_>() {
+ p.parse::<kw::false_>()?;
+ Ok(Bool(false))
+ } else {
+ Err(l.error())
+ }
+ }),
+ ("u8.const", |p| Ok(U8(p.parse()?))),
+ ("s8.const", |p| Ok(S8(p.parse()?))),
+ ("u16.const", |p| Ok(U16(p.parse()?))),
+ ("s16.const", |p| Ok(S16(p.parse()?))),
+ ("u32.const", |p| Ok(U32(p.parse()?))),
+ ("s32.const", |p| Ok(S32(p.parse()?))),
+ ("u64.const", |p| Ok(U64(p.parse()?))),
+ ("s64.const", |p| Ok(S64(p.parse()?))),
+ ("f32.const", |p| Ok(Float32(p.parse()?))),
+ ("f64.const", |p| Ok(Float64(p.parse()?))),
+ ("char.const", |p| {
+ let s = p.parse::<&str>()?;
+ let mut ch = s.chars();
+ let ret = match ch.next() {
+ Some(c) => c,
+ None => return Err(p.error("empty string")),
+ };
+ if ch.next().is_some() {
+ return Err(p.error("more than one character"));
+ }
+ Ok(Char(ret))
+ }),
+ ("str.const", |p| Ok(String(p.parse()?))),
+ ("list.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| p.parse())?);
+ }
+ Ok(List(ret))
+ }),
+ ("record.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| {
+ p.parse::<kw::field>()?;
+ Ok((p.parse()?, p.parse()?))
+ })?);
+ }
+ Ok(Record(ret))
+ }),
+ ("tuple.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parens(|p| p.parse())?);
+ }
+ Ok(Tuple(ret))
+ }),
+ ("variant.const", |p| {
+ let name = p.parse()?;
+ let payload = if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ };
+ Ok(Variant(name, payload))
+ }),
+ ("enum.const", |p| Ok(Enum(p.parse()?))),
+ ("union.const", |p| {
+ let num = p.parse()?;
+ let payload = Box::new(p.parens(|p| p.parse())?);
+ Ok(Union(num, payload))
+ }),
+ ("option.none", |_| Ok(Option(None))),
+ ("option.some", |p| {
+ Ok(Option(Some(Box::new(p.parens(|p| p.parse())?))))
+ }),
+ ("result.ok", |p| {
+ Ok(Result(Ok(if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ })))
+ }),
+ ("result.err", |p| {
+ Ok(Result(Err(if p.is_empty() {
+ None
+ } else {
+ Some(Box::new(p.parens(|p| p.parse())?))
+ })))
+ }),
+ ("flags.const", |p| {
+ let mut ret = Vec::new();
+ while !p.is_empty() {
+ ret.push(p.parse()?);
+ }
+ Ok(Flags(ret))
+ }),
+ ]
+};
+
+impl<'a> Parse<'a> for WastVal<'a> {
+ fn parse(parser: Parser<'a>) -> Result<Self> {
+ parser.depth_check()?;
+ let parse = parser.step(|c| {
+ if let Some((kw, rest)) = c.keyword() {
+ if let Some(i) = CASES.iter().position(|(name, _)| *name == kw) {
+ return Ok((CASES[i].1, rest));
+ }
+ }
+ Err(c.error("expected a [type].const expression"))
+ })?;
+ parse(parser)
+ }
+}
+
+impl Peek for WastVal<'_> {
+ fn peek(cursor: Cursor<'_>) -> bool {
+ let kw = match cursor.keyword() {
+ Some((kw, _)) => kw,
+ None => return false,
+ };
+ CASES.iter().any(|(name, _)| *name == kw)
+ }
+
+ fn display() -> &'static str {
+ "core wasm argument"
+ }
+}