diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/wast/src/component | |
parent | Initial commit. (diff) | |
download | firefox-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.rs | 253 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/binary.rs | 972 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/component.rs | 313 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/custom.rs | 28 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/expand.rs | 859 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/export.rs | 221 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/func.rs | 372 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/import.rs | 176 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/instance.rs | 296 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/item_ref.rs | 154 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/module.rs | 75 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/resolve.rs | 973 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/types.rs | 965 | ||||
-rw-r--r-- | third_party/rust/wast/src/component/wast.rs | 166 |
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" + } +} |