diff --git a/design/mvp/WIT.md b/design/mvp/WIT.md index bec3ad44..20b456c7 100644 --- a/design/mvp/WIT.md +++ b/design/mvp/WIT.md @@ -1,28 +1,568 @@ # The `wit` format -This is intended to document the `wit` format as it exists today. The goal is -to provide an overview to understand what features `wit` files give you and how -they're structured. This isn't intended to be a formal grammar, although it's -expected that one day we'll have a formal grammar for `wit` files. +The Wasm Interface Type (WIT) format is an [IDL] to provide tooling for the +[WebAssembly Component Model][components] in two primary ways: -If you're curious to give things a spin try out the [online -demo](https://bytecodealliance.github.io/wit-bindgen/) of `wit-bindgen` where -you can input `wit` on the left and see output of generated bindings for -languages on the right. If you're looking to start you can try out the -"markdown" output mode which generates documentation for the input document on -the left. +* WIT is a developer-friendly format to describe the imports and exports to a + component. It is easy to read and write and provides the foundational basis + for producing components from guest languages as well as consuming components + in host languages. -## Lexical structure +* WIT packages are the basis of sharing types and definitions in an ecosystem of + components. Authors can import types from other WIT packages when generating a + component, publish a WIT package representing a host embedding, or collaborate + on a WIT definition of a shared set of APIs between platforms. + +A WIT package is a collection of WIT documents. Each WIT document is defined in +a file that uses the file extension `wit`, for example `foo.wit`, and is encoded +as valid utf-8 bytes. Each WIT document contains a collection of +[`interface`s][interfaces] and [`world`s][worlds]. Types can be imported from +sibling documents (files) within a package and additionally from other packages +through a URLs. + +This document will go through the purpose of the syntactic constructs of a WIT +document, a pseudo-formal [grammar specification][lexical-structure], and +additionally a specification of the [binary format][binary-format] of a WIT +package suitable for distribution. + +[IDL]: https://en.wikipedia.org/wiki/Interface_description_language +[components]: https://github.com/webassembly/component-model + +## WIT Interfaces +[interfaces]: #wit-interfaces + +The concept of an "interface" is central in WIT as a collection of [functions] +and [types]. An interface can be thought of as an instance in the WebAssembly +Component Model, for example a unit of functionality imported from the host or +implemented by a component for consumption on a host. All functions and types +belong to an interface. + +An example of an interface is: + +```wit +interface host { + log: func(msg: string) +} +``` + +represents an interface called `host` which provides one function, `log`, which +takes a single `string` argument. If this were imported into a component then it +would correspond to: + +```wasm +(component + (import "host" (instance $host + (export "log" (func (param "msg" string))) + )) + ;; ... +) +``` + +An `interface` can contain [`use`][use] statements, [type][types] definitions, +and [function][functions] definitions. For example: + +```wit +interface wasi-fs { + use pkg.types.{errno} + + record stat { + ino: u64, + size: u64, + // ... + } + + stat-file: func(path: string) -> result +} +``` + +More information about [`use`][use] and [types] are described below, but this +is an example of a collection of items within an `interface`. All items defined +in an `interface`, including [`use`][use] items, are considered as exports from +the interface. This means that types can further be used from the interface by +other interfaces. An interface has a single namespace which means that none of +the defined names can collide. + +A WIT document can contain any number of interfaces listed at the top-level and +in any order. The WIT validator will ensure that all references between +interfaces are well-formed and acyclic. + +An interface may optionally be listed as the `default` of a document. For +example: + +```wit +default interface types { + // ... +} +``` + +This will come up later when describing [`use` statements][use] and indicates +that when a document is imported from the `types` name here, for example, does +not need to be specified as it's the `default`. + +## WIT Worlds +[worlds]: #wit-worlds + +WIT documents can contain a `world` definition at the top-level in addition to +[`interface`][interfaces] definitions. A world is a complete description of +both imports and exports of a component. A world can be thought of as an +equivalent of a `component` type in the component model. For example this +world: + +```wit +world my-world { + import host: interface { + log: func(param: string) + } + + export run: func() +} +``` + +can be thought of as this component type: + +```wasm +(type $my-world (component + (import "host" (instance + (export "log" (func (param "param" string))) + )) + (export "run" (func)) +)) +``` + +Worlds describe a concrete component and are the basis of bindings generation. A +guest language will use a `world` to determine what functions are imported, what +they're named, and what functions are exported, in addition to their names. + +Worlds can contain any number of imports and exports, and can be either a +function or an interface. + +```wit +world command { + import fs: wasi-fs.fs + import random: wasi-random.random + import clock: wasi-clock.clock + // ... + + export main: func(args: list) +} +``` + +An imported or exported interface corresponds to an imported or exported +instance in the component model. Functions are equivalent to bare component +functions. + +Additionally interfaces can be defined "inline" as a form of sugar for defining +it at the top-level + +```wit +interface out-of-line { + the-function: func() +} + +world your-world { + import out-of-line: self.out-of-line + // ... is roughly equivalent to ... + import out-of-line2: interface { + the-function: func() + } +} +``` + +The name of the `import` or `export` is the name of the corresponding item in +the final component. This can be different from the [`interface`][interfaces] +name but must be a [valid identifier][identifiers]. + +There can be multiple `world` descriptions in a single WIT document. When +generating bindings from a WIT document one world must be marked as `default` or +an explicitly named world must be chosen: + +```wit +default world my-world { + // ... +} +``` + +If no `default` world is specified in the WIT document and no named world is +explicitly chosen then bindings cannot be generated. + +## WIT Packages and `use` +[use]: #wit-packages-and-use + +A WIT package represents a unit of distribution that can be published to a +registry, for example, and used by other WIT packages and documents. WIT +packages are a flat list of documents, defined in `*.wit` files. The current +thinking for a convention is that projects will have a `wit` folder where all +`wit/*.wit` files within are members of a WIT package. + +Within a single WIT document (file) a `use` statement can be used to import +between interfaces, for example: + +```wit +interface types { + enum errno { /* ... */ } + + type size = u32 +} + +interface my-host-functions { + use self.types.{errno, size} +} +``` + +Here the `use` starts with `self` which indicates that something from the +current document is being used. Then the interface named `types` is listed, +followed by a list of type names to use from the interface. The interface +`types` may textually come either after or before the `use` directive's +`interface`. Interfaces linked with `use` are not allowed to be cyclic. + +Names imported via `use` can be renamed as they're imported as well: + +```wit +interface my-host-functions { + use self.types.{errno as my-errno} +} +``` + +Documents in a WIT package may also import from each other, for example the +above can be rewritten as: + +```wit +// types.wit +default interface types { + enum errno { /* ... */ } + + type size = u32 +} + +// host.wit +interface my-host-functions { + use pkg.types.{errno, size} +} +``` + +The `pkg` keyword indicates that the `use` statement starts at the package root, +as opposed to the `self` keyword described above starting in the local document. +Additionally note the usage of `default interface` in the `types.wit` file which +simplifies the `use`. WIT documents can also import from any interface defined +within another document, however: + +```wit +// types.wit +default interface types { /* .. */ } + +interface more-types { + type another-type = string +} + +// host.wit +interface my-host-functions { + use pkg.types.more-types.{another-type} +} +``` + +Here `more-types` in the `use` path indicates that it's the specific interface +being referenced. Documents in a WIT package must be named after a [valid +identifier][identifiers] and be unique within the package. Documents cannot +contain cycles between them as well with `use` statements. + +When importing or exporting an [interface][interfaces] in a [world][worlds] +the same syntax is used after the `:` as `use`: + +```wit +world my-world { + import host: self.host + import other-functionality: pkg.sibling-file + import more-functionality: pkg.sibling-file.specific-interface +} + +interface host { + // ... +} +``` + +The `use` statement so far has always started with `self` or `pkg`, but it may +also start with any valid identifier: + +```wit +interface foo { + use package.other-document.{some-type} +} +``` + +This form indicates that the identifier `package` corresponds to some externally +specified package. Resolution of this WIT document requires the name `package` +to be provided via external configuration. For example a registry might indicate +that `package` was downloaded to a particular path at a particular version. The +name `package` could also perhaps be another package defined in the local +project which is configured via bindings generation. + +This syntax allows `use` paths starting with any identifier other than `self` +and `pkg` to create a set of names that the document needs to be resolved +correctly. These names are considered the dependency packages of the current +package being parsed. Note that the set of names here are local to this package +do not need to conflict with dependency names in other packages. This enables +each package to be resolved entirely separately and, if necessary, the name +`foo` could mean different things to different packages. + +> **Note**: The tooling for and mechanism for precisely how these external names +> are defined is not specified here. This is something that will be iterated on +> to create documentation of the tooling in question and community standards +> about how best to do this. +> +> As an example, however, imagine a CLI tool to generate C bindings for creating +> a component that takes, as input, the world to generate. +> +> generate-c-bindings pkg.my-component +> +> The specification of `pkg` here indicates that a locally-written WIT file +> is being consumed. This could look inside of a `wit` folder in the current +> directory for a package to parse as a set of WIT files. Inside this package +> the `my-component` document would be selected and it would be expected to have +> a `default world`. +> +> Similarly an invocation such as: +> +> generate-c-bindings pkg.my-component --extern wasi=./wit/wasi +> +> Could indicate that the identifier `wasi` within `my-component` would be +> resolved to a WIT package located in the `./wit/wasi` folder. Instead of +> `./wit/wasi` it could even pass `./wit/wasi.wasm` which would be the binary +> encoding of the `wasi` package. This sort of filesystem-based heuristic could +> be applied by the `generate-c-bindings` tool as well. +> +> Alternatively there could also be a tool which takes a configuration file: +> +> ```toml +> [wit-dependencies] +> wasi = "1.0" +> ``` +> +> Where running `wit-registry` (a hypothetical CLI command) would parse this +> file, resolve it fully, and download the `wasi` package and place it somewhere +> along with perhaps a `resolve.json` file. This `resolve.json` could then be +> consumed by `generate-c-bindings` as an additional method for defining the +> dependency graph of components. +> +> Note that these scenarios are all hypothetical at this time and are the rough +> direction that tooling is expected to go in. This will evolve over time but is +> intended to set the stage for "what actually happens when I refer to a +> dependency package" where the high-level idea is that it's a concern external +> to the WIT package itself and resolved by higher-level tooling. + +### Transitive imports and worlds + +A `use` statement is not implemented by copying type information around but +instead retains that it's a reference to a type defined elsewhere. This +representation is plumbed all the way through to the final component, meaning +that `use`d types have an impact on the structure of the final generated +component. + +For example this document: + +```wit +interface shared { + record metadata { + // ... + } +} + +world my-world { + import host: interface { + use self.shared.{metadata} + + get: func() -> metadata + } +} +``` + +would generate this component: + +```wasm +(component + (import "shared" (instance $shared + (type $metadata (record (; ... ;))) + (export "metadata" (type (eq $metadata))) + )) + (alias export $shared "metadata" (type $metadata)) + (import "host" (instance $host + (export "get" (func (result $metadata))) + )) +) +``` + +Here it can be seen that despite the `world` only listing `host` as an import +the component additionally imports a `shared` instance. This is due to the fact +that the `use { ... } from shared` implicitly requires that `shared` is imported +into the component as well. + +Note that the name `"shared"` here is derived from the name of the `interface` +which can also lead to conflicts: + +```wit +// shared1.wit +default interface shared { /* ... */ } + +// shared2.wit +default interface shared { /* ... */ } + +// world.wit +world my-world { + import foo: interface { + use pkg.shared1.{a-type} + } + import bar: interface { + use pkg.shared2.{other-type} + } +} +``` + +This is an invalid WIT document because `my-world` needs to import two +unique interfaces called `shared`. To disambiguate a manual import is required: + +``` +world my-world { + import shared1: pkg.shared1 + import shared2: pkg.shared2 + + import foo: interface { + use pkg.shared1.{a-type} + } + import bar: interface { + use pkg.shared2.{other-type} + } +} +``` + +For `export`ed interfaces any transitively `use`d interface is assumed to be an +import unless it's explicitly listed as an export. + +> **Note**: It's planned in the future to have "power user syntax" to configure +> this on a more fine-grained basis for exports, for example being able to +> configure that a `use`'d interface is a particular import or a particular +> export. + +## WIT Functions +[functions]: #wit-functions + +Functions are defined in an [`interface`][interfaces] or are listed as an +`import` or `export` from a [`world`][worlds]. Parameters to a function must all +be named and have unique names: + +```wit +interface foo { + a1: func() + a2: func(x: u32) + a3: func(y: u64, z: float32) +} +``` + +Functions can return at most one unnamed type: + +```wit +interface foo { + a1: func() -> u32 + a2: func() -> string +} +``` + +And functions can also return multiple types by naming them: + +```wit +interface foo { + a: func() -> (a: u32, b: float32) +} +``` + +Note that returning multiple values from a function is not equivalent to +returning a tuple of values from a function. These options are represented +distinctly in the component binary format. + +## WIT Types +[types]: #wit-types + +Types in WIT files can only be defined in [`interface`s][interfaces] at this +time. The types supported in WIT is the same set of types supported in the +component model itself: + +```wit +interface foo { + // "package of named fields" + record r { + a: u32, + b: string, + } + + // values of this type will be one of the specified cases + variant human { + baby, + child(u32), // optional type payload + adult, + } + + // similar to `variant`, but no type payloads + enum errno { + too-big, + too-small, + too-fast, + too-slow, + } + + // similar to `variant`, but doesn't require naming cases and all variants + // have a type payload -- note that this is not a C union, it still has a + // discriminant + union input { + u64, + string, + } + + // a bitflags type + flags permissions { + read, + write, + exec, + } + + // type aliases are allowed to primitive types and additionally here are some + // examples of other types + type t1 = u32 + type t2 = tuple + type t3 = string + type t4 = option + type t5 = result<_, errno> // no "ok" type + type t6 = result // no "err" type + type t7 = result // both types specified + type t8 = result // no "ok" or "err" type + type t9 = list + type t10 = t9 +} +``` + +The `record`, `variant`, `enum`, `union`, and `flags` types must all have names +associated with them. The `list`, `option`, `result`, `tuple`, and primitive +types do not need a name and can be mentioned in any context. This restriction +is in place to assist with code generation in all languages to leverage +language-builtin types where possible while accommodating types that need to be +defined within each language as well. + +## WIT Identifiers +[identifiers]: #wit-identifiers + +Identifiers in WIT documents are required to be valid component identifiers, +meaning that they're "kebab cased". This currently is restricted to ascii +characters and numbers that are `-` separated. + +For more information on this see the [binary format](./Binary.md). + +# Lexical structure +[lexical-structure]: #lexical-structure The `wit` format is a curly-braced-based format where whitespace is optional (but -recommended). It is intended to be easily human readable and supports features -like comments, multi-line comments, and custom identifiers. A `wit` document -is parsed as a unicode string, and when stored in a file is expected to be -encoded as UTF-8. +recommended). A `wit` document is parsed as a unicode string, and when stored in +a file is expected to be encoded as utf-8. -Additionally, wit files must not contain any bidirectional override scalar values, -control codes other than newline, carriage return, and horizontal tab, or -codepoints that Unicode officially deprecates or strongly discourages. +Additionally, wit files must not contain any bidirectional override scalar +values, control codes other than newline, carriage return, and horizontal tab, +or codepoints that Unicode officially deprecates or strongly discourages. The current structure of tokens are: @@ -32,7 +572,6 @@ token ::= whitespace | operator | keyword | identifier - | strlit ``` Whitespace and comments are ignored when parsing structures defined elsewhere @@ -106,7 +645,6 @@ keyword ::= 'use' | 'list' | 'result' | 'as' - | 'from' | 'static' | 'interface' | 'tuple' @@ -115,6 +653,7 @@ keyword ::= 'use' | 'world' | 'import' | 'export' + | 'default' ``` ## Top-level items @@ -135,45 +674,53 @@ Worlds define a [componenttype](https://github.com/WebAssembly/component-model/b Concretely, the structure of a world is: ```wit -world-item ::= 'world' id '{' world-items* '}' +world-item ::= 'default'? 'world' id '{' world-items* '}' -world-items ::= export-item | import-item +world-items ::= export-item | import-item | use-item | typedef-item export-item ::= 'export' id ':' extern-type import-item ::= 'import' id ':' extern-type -extern-type ::= ty | func-type | interface-type +extern-type ::= func-type | interface-type interface-type ::= 'interface' '{' interface-items* '}' + | use-path ``` +Note that worlds can import types and define their own types to be exported +from the root of a component and used within functions imported and exported. + ## Item: `interface` -Interfaces can be defined in a `wit` document. Interfaces have a name and a sequence of items and functions. +Interfaces can be defined in a `wit` document. Interfaces have a name and a +sequence of items and functions. Specifically interfaces have the structure: ```wit -interface-item ::= 'interface' id strlit? '{' interface-items* '}' +interface-item ::= 'default'? 'interface' id '{' interface-items* '}' -interface-items ::= resource-item - | variant-items - | record-item - | union-items - | flags-items - | enum-items - | type-item +interface-items ::= typedef-item | use-item | func-item +typedef-item ::= resource-item + | variant-items + | record-item + | union-items + | flags-items + | enum-items + | type-item + func-item ::= id ':' func-type -func-type ::= 'func' param-list '->' result-list +func-type ::= 'func' param-list result-list param-list ::= '(' named-type-list ')' -result-list ::= ty - | '(' named-type-list ')' +result-list ::= nil + | '->' ty + | '->' '(' named-type-list ')' named-type-list ::= nil | named-type ( ',' named-type )* @@ -187,24 +734,23 @@ A `use` statement enables importing type or resource definitions from other wit documents. The structure of a use statement is: ```wit -use * from other-file -use { a, list, of, names } from another-file -use { name as other-name } from yet-another-file +use self.interface.{a, list, of, names} +use pkg.document.some-type +use my-dependency.document.other-type ``` Specifically the structure of this is: ```wit -use-item ::= 'use' use-names 'from' id - -use-names ::= '*' - | '{' use-names-list '}' +use-item ::= 'use' use-path '.' '{' use-names-list '}' use-names-list ::= use-names-item | use-names-item ',' use-names-list? use-names-item ::= id | id 'as' id + +use-path ::= id ('.' id)* ``` Note: Here `use-names-list?` means at least one `use-name-list` term. @@ -264,10 +810,9 @@ record-field ::= id ':' ty ### Item: `flags` (bag-of-bools) -A `flags` statement defines a new `record`-like structure where all the fields -are booleans. The `flags` type is distinct from `record` in that it typically is -represented as a bit flags representation in the canonical ABI. For the purposes -of type-checking, however, it's simply syntactic sugar for a record-of-booleans. +A `flags` represents a bitset structure with a name for each bit. The `flags` +type is represented as a bit flags representation in +the canonical ABI. ```wit flags properties { @@ -275,14 +820,6 @@ flags properties { marvel-superhero, supervillan, } - -// type-wise equivalent to: -// -// record properties { -// lego: bool, -// marvel-superhero: bool, -// supervillan: bool, -// } ``` Specifically the structure of this is: @@ -341,16 +878,6 @@ enum color { yellow, other, } - -// type-wise equivalent to: -// -// variant color { -// red, -// green, -// blue, -// yellow, -// other, -// } ``` Specifically the structure of this is: @@ -366,22 +893,14 @@ enum-cases ::= id A `union` statement defines a new type which is semantically equivalent to a `variant` where all of the cases have a payload type and the case names are -numerical. This is special-cased, however, to possibly have a different -representation in the language ABIs or have different bindings generated in for -languages. +numerical. This is special-cased, however, to have a different representation +in the language ABIs or have different bindings generated in for languages. ```wit union configuration { string, list, } - -// type-wise equivalent to: -// -// variant configuration { -// 0(string), -// 1(list), -// } ``` Specifically the structure of this is: @@ -393,42 +912,6 @@ union-cases ::= ty | ty ',' union-cases? ``` -## Item: `resource` - -Resources represent a value that has a hidden representation not known to the -outside world. This means that the resource is operated on through a "handle" (a -pointer of sorts). Resources also have ownership associated with them and -languages will have to manage the lifetime of resources manually (they're -similar to file descriptors). - -Resources can also optionally have functions defined within them which adds an -implicit "self" argument as the first argument to each function of the same type -of the including resource, unless the function is flagged as `static`. - -```wit -resource file-descriptor - -resource request { - static new: func() -> request - - body: func() -> future> - headers: func() -> list -} -``` - -Specifically resources have the structure: - -```wit -resource-item ::= 'resource' id resource-contents - -resource-contents ::= nil - | '{' resource-defs '}' - -resource-defs ::= resource-def resource-defs? - -resource-def ::= 'static'? func-item -``` - ## Types As mentioned previously the intention of `wit` is to allow defining types @@ -456,8 +939,6 @@ ty ::= 'u8' | 'u16' | 'u32' | 'u64' | option | result | handle - | future - | stream | id tuple ::= 'tuple' '<' tuple-list '>' @@ -472,14 +953,6 @@ result ::= 'result' '<' ty ',' ty '>' | 'result' '<' '_' ',' ty '>' | 'result' '<' ty '>' | 'result' - -future ::= 'future' '<' ty '>' - | 'future' - -stream ::= 'stream' '<' ty ',' ty '>' - | 'stream' '<' '_' ',' ty '>' - | 'stream' '<' ty '>' - | 'stream' ``` The `tuple` type is semantically equivalent to a `record` with numerical fields, @@ -613,9 +1086,302 @@ record bar2 { } ``` -The intention of `wit` is that it maps down to interface types, so the goal of -name resolution is to effectively create the type section of a wasm module using -interface types. The restrictions about self-referential types and such come -from how types can be defined in the interface types section. Additionally -definitions of named types such as `record foo { ... }` are intended to map -roughly to declarations in the type section of new types. +# Binary Format +[binary-format]: #binary-format + +In addition to a textual format WIT packages can also be encoded to a binary +format. The binary format for WIT is represented as a WebAssembly Component +binary with a specific structure. The purpose of the WIT binary format is to: + +* Provide a way to clearly define what an `interface` and a `world` map to in + the component model. For example a host is said to implement an `interface` if + it provides a subtype of the `instance` type defined in a component. Similarly + a component is said to implement a `world` if the component's type is a + subtype of the `world`'s type. + +* Provide a means by which the textual format of WIT can be evolved while + minimizing impact to the ecosystem. Similar to how the WebAssembly text format + has changed over time it's envisioned that it may be necessary to change the + WIT format for new features as new component model features are implemented. + The binary format provides a clear delineation of what to ubiquitously consume + without having to be so concerned with text format parsers. + +* A binary format is intended to be more efficient parse and store. + +The binary format for a WIT document can also be thought of in a loose sense as +a fully-resolved and indexed representation of a WIT document. Constructs such +as `use` are preserved but all name resolution has been boiled away to index +references. Additionally the transitive import set is all finalized as well. + +An example of the binary format is that this document: + +```wit +// host.wit +interface console { + log: func(arg: string) +} +``` + +would correspond to: + +```wasm +(component + (type (export "host") (component + (type $console (instance + (export "log" (func (param "arg" string))) + )) + (export "console" (instance (type $console))) + )) +) +``` + +Here it can be seen how an `interface` corresponds to an `instance` in the +component model. Note that the WIT document is encoded entirely within the type +section of a component and does not actually represent any concrete instances. +This is done to implement `use` statements: + +```wit +// host.wit +interface types { + enum level { + info, + debug, + } +} + +interface console { + use self.types.{level} + log: func(level: level, msg: string) +} +``` + +would correspond to: + +```wasm +(component + (type (export "host") (component + (type $types (instance + (type $level (enum "info" "debug")) + (export "level" (type (eq $level))) + )) + (export $types "types" (instance (type $types))) + (alias export $types "level" (type $level)) + (type $console (instance + (export $level' "level" (type (eq $level))) + (export "log" (func (param "level" $level') (param "msg" string))) + )) + (export "console" (instance (type $console))) + )) +) +``` + +Here the `alias` of `"level"` indicates that the exact type is being used from a +different interface. + +A `world` is represented as a component type. + +```wit +// host.wit +world the-world { + export test: func() + export run: func() +} +``` + +would correspond to: + +```wasm +(component + (type (export "host") (component + (export "the-world" (component + (export "test" (func)) + (export "run" (func)) + )) + )) +) +``` + +Component types in the WebAssembly component binary format cannot close over +outer instances so interfaces referred to by a component are redefined, at least +the parts needed, within the component: + + +```wit +// host.wit +world the-world { + import console: console +} + +interface console { + log: func(arg: string) +} +``` + +would correspond to: + +```wasm +(component + (type (export "host") (component + (type $console (instance + (export "log" (func (param "arg" string))) + )) + (export "console" (instance (type $console))) + (export "the-world" (component + (import "console" (instance + (export "log" (func (param "arg" string))) + )) + )) + )) +) +``` + +Each WIT document in a package becomes a top-level export of the component: + +```wit +// foo.wit +interface foo {} + +// bar.wit +interface bar {} +``` + +would correspond to: + +```wasm +(component + (type (export "foo") (component + (type $foo (instance + )) + (export "foo" (instance (type $foo))) + )) + (type (export "bar") (component + (type $bar (instance + )) + (export "bar" (instance (type $bar))) + )) +) +``` + +Imports of packages are encoded as imports to the outermost component +type as well. + +```wit +// foo.wit +interface foo { + use registry-package.types.{some-type} +} +``` + +would correspond to: + +```wasm +(component + (type (export "foo") (component + (import "types" "URL" (instance $types + (type $some-type ...) + (export "some-type" (type (eq $some-type))) + )) + (alias export $types "some-type" (type $some-type)) + (type $foo (instance + (export "some-type" (type (eq $some-type))) + )) + (export "foo" (instance (type $foo))) + )) +) +``` + +Note that `URL` would be provided by external tooling providing the definition +of `registry-package` here as well. + +Putting all of this together an example of development of the `wasi-http` +package would be: + +```wit +// wasi-http repo + +// wit/types.wit +default interface types { + resource request { ... } + resource response { ... } +} + +// wit/handler.wit +default interface handler { + use pkg.types.{request, response} + handle: func(request) -> response +} + +// wit/proxy.wit +default world proxy { + import console: wasi-logging.backend + import origin: pkg.handler + export handler: pkg.handler +} +``` + +and its corresponding binary encoding would be: + +```wasm +(component + ;; corresponds to `wit/types.wit` + (type (export "types") (component + (export "types" (instance + (type $request (record)) + (type $response (record)) + (export "request" (type (eq $request))) + (export "response" (type (eq $response))) + )) + )) + ;; corresponds to `wit/handler.wit` + (type (export "handler") (component + ;; interfaces not required in a document are imported here. The name "types" + ;; with no URL refers to the `types` document in this package. + (import "types" "pkg:/types/types" (instance $types + (type $request (record)) + (type $response (record)) + (export "request" (type (eq $request))) + (export "response" (type (eq $response))) + )) + + ;; aliases represent `use` from the imported document + (alias export $types "request" (type $request)) + (alias export $types "response" (type $response)) + (export "handler" (instance + (export $request' "request" (type (eq $request))) + (export $response' "response" (type (eq $response))) + (export "handle" (func (param "request" $request') (result $response'))) + )) + )) + ;; corresponds to `wit/proxy.wit` + (type (export "proxy") (component + (export "proxy" (component + ;; This world transitively depends on "types" so it's listed as an + ;; import. + (import "types" "pkg:/types/types" (instance $types + (type $request (record)) + (type $response (record)) + (export "request" (type (eq $request))) + (export "response" (type (eq $response))) + )) + (alias export $types "request" (type $request)) + (alias export $types "response" (type $response)) + + ;; This is filled in with the contents of what `wasi-logging.backend` + ;; resolved to + (import "console" "dep:/foo/bar/baz" (instance + ;; ... + )) + (import "origin" "pkg:/handler/handler" (instance + (export $request' "request" (type (eq $request))) + (export $response' "response" (type (eq $response))) + (export "handle" (func (param "request" $request') (result $response'))) + )) + (export "handler" "pkg:/handler/handler" (instance + (export $request' "request" (type (eq $request))) + (export $response' "response" (type (eq $response))) + (export "handle" (func (param "request" $request') (result $response'))) + )) + )) + )) +) +```