diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e1cc9ad4..259037b1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -14,7 +14,7 @@ on: env: go-modules: ./... ./cm/... - wasm-tools-version: "1.219.1" + wasm-tools-version: "1.222.0" wasmtime-version: "26.0.0" jobs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 708d96ad..0d0fb18e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Changed -- Incremental support for Component Model async types `stream` and `future`. +- Initial support for Component Model [async](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md) types `stream`, `future`, and `error-context`. +- Breaking: generated `*.wasm.go` files will now have correct WIT kebab-case base name. Interfaces or worlds with `-` in their name will require removal of the previous `*.wasm.go` files. - Dropped support for TinyGo v0.32.0. ## [v0.5.0] — 2024-12-14 diff --git a/cm/CHANGELOG.md b/cm/CHANGELOG.md index 184e21ed..7974b70e 100644 --- a/cm/CHANGELOG.md +++ b/cm/CHANGELOG.md @@ -2,6 +2,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Initial support for Component Model [async](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md) types `stream`, `future`, and `error-context`. + ## [v0.1.0] — 2024-12-14 Initial version, extracted into module [`go.bytecodealliance.org/cm`](https://pkg.go.dev/go.bytecodealliance.org/cm). diff --git a/cm/empty.s b/cm/empty.s new file mode 100644 index 00000000..5444f200 --- /dev/null +++ b/cm/empty.s @@ -0,0 +1,3 @@ +// This file exists for testing this package without WebAssembly, +// allowing empty function bodies with a //go:wasmimport directive. +// See https://pkg.go.dev/cmd/compile for more information. diff --git a/cm/error.go b/cm/error.go new file mode 100644 index 00000000..77b5bfd6 --- /dev/null +++ b/cm/error.go @@ -0,0 +1,48 @@ +package cm + +import "unsafe" + +// ErrorContext represents the Component Model [error-context] type, +// an immutable, non-deterministic, host-defined value meant to aid in debugging. +// +// [error-context]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#error-context-type +type ErrorContext struct { + _ HostLayout + errorContext +} + +type errorContext uint32 + +// Error implements the [error] interface. It returns the debug message associated with err. +func (err errorContext) Error() string { + return err.DebugMessage() +} + +// String implements [fmt.Stringer]. +func (err errorContext) String() string { + return err.DebugMessage() +} + +// DebugMessage represents the Canonical ABI [error-context.debug-message] function. +// +// [error-context.debug-message]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#error-contextdebug-message +func (err errorContext) DebugMessage() string { + var s string + errorContextDebugMessage(err, unsafe.Pointer(&s)) + return s +} + +//go:wasmimport canon error-context.debug-message +//go:noescape +func errorContextDebugMessage(err errorContext, msg unsafe.Pointer) + +// Drop represents the Canonical ABI [error-context.drop] function. +// +// [error-context.drop]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#error-contextdrop +func (err errorContext) Drop() { + errorContextDrop(err) +} + +//go:wasmimport canon error-context.drop +//go:noescape +func errorContextDrop(err errorContext) diff --git a/cm/future.go b/cm/future.go new file mode 100644 index 00000000..e82183f6 --- /dev/null +++ b/cm/future.go @@ -0,0 +1,15 @@ +package cm + +// Future represents the Component Model [future] type. +// A future is a special case of stream. In non-error cases, +// a future delivers exactly one value before being automatically closed. +// +// [future]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#asynchronous-value-types +type Future[T any] struct { + _ HostLayout + future[T] +} + +type future[T any] uint32 + +// TODO: implement methods on type future diff --git a/cm/stream.go b/cm/stream.go new file mode 100644 index 00000000..80ef062e --- /dev/null +++ b/cm/stream.go @@ -0,0 +1,15 @@ +package cm + +// Stream represents the Component Model [stream] type. +// A stream is a special case of stream. In non-error cases, +// a stream delivers exactly one value before being automatically closed. +// +// [stream]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#asynchronous-value-types +type Stream[T any] struct { + _ HostLayout + stream[T] +} + +type stream[T any] uint32 + +// TODO: implement methods on type stream diff --git a/testdata/codegen/error-context.wit b/testdata/codegen/error-context.wit new file mode 100644 index 00000000..00966bf2 --- /dev/null +++ b/testdata/codegen/error-context.wit @@ -0,0 +1,13 @@ +package foo:foo; + +interface error-contexts { + type foo = error-context; + + bar: func(x: foo, y: error-context, z: future) -> result, error-context>; +} + +world foo { + import error-contexts; + export error-contexts; +} + diff --git a/testdata/codegen/error-context.wit.json b/testdata/codegen/error-context.wit.json new file mode 100644 index 00000000..af3c35a1 --- /dev/null +++ b/testdata/codegen/error-context.wit.json @@ -0,0 +1,105 @@ +{ + "worlds": [ + { + "name": "foo", + "imports": { + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "exports": { + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "package": 0 + } + ], + "interfaces": [ + { + "name": "error-contexts", + "types": { + "foo": 0 + }, + "functions": { + "bar": { + "name": "bar", + "kind": "freestanding", + "params": [ + { + "name": "x", + "type": 0 + }, + { + "name": "y", + "type": 1 + }, + { + "name": "z", + "type": 2 + } + ], + "results": [ + { + "type": 4 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "foo", + "kind": "errorcontext", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": "errorcontext", + "owner": null + }, + { + "name": null, + "kind": { + "future": 1 + }, + "owner": null + }, + { + "name": null, + "kind": { + "stream": 1 + }, + "owner": null + }, + { + "name": null, + "kind": { + "result": { + "ok": 3, + "err": 1 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:foo", + "interfaces": { + "error-contexts": 0 + }, + "worlds": { + "foo": 0 + } + } + ] +} \ No newline at end of file diff --git a/testdata/codegen/error-context.wit.json.golden.wit b/testdata/codegen/error-context.wit.json.golden.wit new file mode 100644 index 00000000..98b2799c --- /dev/null +++ b/testdata/codegen/error-context.wit.json.golden.wit @@ -0,0 +1,11 @@ +package foo:foo; + +interface error-contexts { + type foo = error-context; + bar: func(x: foo, y: error-context, z: future) -> result, error-context>; +} + +world foo { + import error-contexts; + export error-contexts; +} diff --git a/testdata/wit-parser/error-context.wit.json b/testdata/wit-parser/error-context.wit.json new file mode 100644 index 00000000..1a63f8fb --- /dev/null +++ b/testdata/wit-parser/error-context.wit.json @@ -0,0 +1,66 @@ +{ + "worlds": [], + "interfaces": [ + { + "name": "error-contexts", + "types": { + "t1": 0 + }, + "functions": { + "foo": { + "name": "foo", + "kind": "freestanding", + "params": [ + { + "name": "x", + "type": 1 + }, + { + "name": "y", + "type": 0 + } + ], + "results": [ + { + "type": 2 + } + ] + } + }, + "package": 0 + } + ], + "types": [ + { + "name": "t1", + "kind": "errorcontext", + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": "errorcontext", + "owner": null + }, + { + "name": null, + "kind": { + "result": { + "ok": null, + "err": 1 + } + }, + "owner": null + } + ], + "packages": [ + { + "name": "foo:error-contexts", + "interfaces": { + "error-contexts": 0 + }, + "worlds": {} + } + ] +} \ No newline at end of file diff --git a/testdata/wit-parser/error-context.wit.json.golden.wit b/testdata/wit-parser/error-context.wit.json.golden.wit new file mode 100644 index 00000000..8b80c5da --- /dev/null +++ b/testdata/wit-parser/error-context.wit.json.golden.wit @@ -0,0 +1,6 @@ +package foo:error-contexts; + +interface error-contexts { + type t1 = error-context; + foo: func(x: error-context, y: t1) -> result<_, error-context>; +} diff --git a/tests/generated/wasi/cli/v0.2.0/terminal-input/terminalinput.wasm.go b/tests/generated/wasi/cli/v0.2.0/terminal-input/terminal-input.wasm.go similarity index 100% rename from tests/generated/wasi/cli/v0.2.0/terminal-input/terminalinput.wasm.go rename to tests/generated/wasi/cli/v0.2.0/terminal-input/terminal-input.wasm.go diff --git a/tests/generated/wasi/cli/v0.2.0/terminal-output/terminaloutput.wasm.go b/tests/generated/wasi/cli/v0.2.0/terminal-output/terminal-output.wasm.go similarity index 100% rename from tests/generated/wasi/cli/v0.2.0/terminal-output/terminaloutput.wasm.go rename to tests/generated/wasi/cli/v0.2.0/terminal-output/terminal-output.wasm.go diff --git a/tests/generated/wasi/cli/v0.2.0/terminal-stderr/terminalstderr.wasm.go b/tests/generated/wasi/cli/v0.2.0/terminal-stderr/terminal-stderr.wasm.go similarity index 100% rename from tests/generated/wasi/cli/v0.2.0/terminal-stderr/terminalstderr.wasm.go rename to tests/generated/wasi/cli/v0.2.0/terminal-stderr/terminal-stderr.wasm.go diff --git a/tests/generated/wasi/cli/v0.2.0/terminal-stdin/terminalstdin.wasm.go b/tests/generated/wasi/cli/v0.2.0/terminal-stdin/terminal-stdin.wasm.go similarity index 100% rename from tests/generated/wasi/cli/v0.2.0/terminal-stdin/terminalstdin.wasm.go rename to tests/generated/wasi/cli/v0.2.0/terminal-stdin/terminal-stdin.wasm.go diff --git a/tests/generated/wasi/cli/v0.2.0/terminal-stdout/terminalstdout.wasm.go b/tests/generated/wasi/cli/v0.2.0/terminal-stdout/terminal-stdout.wasm.go similarity index 100% rename from tests/generated/wasi/cli/v0.2.0/terminal-stdout/terminalstdout.wasm.go rename to tests/generated/wasi/cli/v0.2.0/terminal-stdout/terminal-stdout.wasm.go diff --git a/tests/generated/wasi/clocks/v0.2.0/monotonic-clock/monotonicclock.wasm.go b/tests/generated/wasi/clocks/v0.2.0/monotonic-clock/monotonic-clock.wasm.go similarity index 100% rename from tests/generated/wasi/clocks/v0.2.0/monotonic-clock/monotonicclock.wasm.go rename to tests/generated/wasi/clocks/v0.2.0/monotonic-clock/monotonic-clock.wasm.go diff --git a/tests/generated/wasi/clocks/v0.2.0/wall-clock/wallclock.wasm.go b/tests/generated/wasi/clocks/v0.2.0/wall-clock/wall-clock.wasm.go similarity index 100% rename from tests/generated/wasi/clocks/v0.2.0/wall-clock/wallclock.wasm.go rename to tests/generated/wasi/clocks/v0.2.0/wall-clock/wall-clock.wasm.go diff --git a/tests/generated/wasi/io/v0.2.0/error/ioerror.wasm.go b/tests/generated/wasi/io/v0.2.0/error/error.wasm.go similarity index 100% rename from tests/generated/wasi/io/v0.2.0/error/ioerror.wasm.go rename to tests/generated/wasi/io/v0.2.0/error/error.wasm.go diff --git a/tests/generated/wasi/random/v0.2.0/insecure-seed/insecureseed.wasm.go b/tests/generated/wasi/random/v0.2.0/insecure-seed/insecure-seed.wasm.go similarity index 100% rename from tests/generated/wasi/random/v0.2.0/insecure-seed/insecureseed.wasm.go rename to tests/generated/wasi/random/v0.2.0/insecure-seed/insecure-seed.wasm.go diff --git a/tests/generated/wasi/sockets/v0.2.0/instance-network/instancenetwork.wasm.go b/tests/generated/wasi/sockets/v0.2.0/instance-network/instance-network.wasm.go similarity index 100% rename from tests/generated/wasi/sockets/v0.2.0/instance-network/instancenetwork.wasm.go rename to tests/generated/wasi/sockets/v0.2.0/instance-network/instance-network.wasm.go diff --git a/tests/generated/wasi/sockets/v0.2.0/ip-name-lookup/ipnamelookup.wasm.go b/tests/generated/wasi/sockets/v0.2.0/ip-name-lookup/ip-name-lookup.wasm.go similarity index 100% rename from tests/generated/wasi/sockets/v0.2.0/ip-name-lookup/ipnamelookup.wasm.go rename to tests/generated/wasi/sockets/v0.2.0/ip-name-lookup/ip-name-lookup.wasm.go diff --git a/tests/generated/wasi/sockets/v0.2.0/tcp-create-socket/tcpcreatesocket.wasm.go b/tests/generated/wasi/sockets/v0.2.0/tcp-create-socket/tcp-create-socket.wasm.go similarity index 100% rename from tests/generated/wasi/sockets/v0.2.0/tcp-create-socket/tcpcreatesocket.wasm.go rename to tests/generated/wasi/sockets/v0.2.0/tcp-create-socket/tcp-create-socket.wasm.go diff --git a/tests/generated/wasi/sockets/v0.2.0/udp-create-socket/udpcreatesocket.wasm.go b/tests/generated/wasi/sockets/v0.2.0/udp-create-socket/udp-create-socket.wasm.go similarity index 100% rename from tests/generated/wasi/sockets/v0.2.0/udp-create-socket/udpcreatesocket.wasm.go rename to tests/generated/wasi/sockets/v0.2.0/udp-create-socket/udp-create-socket.wasm.go diff --git a/wit/bindgen/generator.go b/wit/bindgen/generator.go index a26d90e8..8ac8ce52 100644 --- a/wit/bindgen/generator.go +++ b/wit/bindgen/generator.go @@ -656,10 +656,12 @@ func (g *generator) typeDefRep(file *gen.File, dir wit.Direction, t *wit.TypeDef return g.ownRep(file, dir, kind) case *wit.Borrow: return g.borrowRep(file, dir, kind) - case *wit.Future: - return "any /* TODO: *wit.Future */" + case *wit.ErrorContext: + return g.errorContextRep(file, dir, kind) case *wit.Stream: - return "any /* TODO: *wit.Stream */" + return g.streamRep(file, dir, kind) + case *wit.Future: + return g.futureRep(file, dir, kind) default: panic(fmt.Sprintf("BUG: unknown wit.TypeDefKind %T", kind)) // should never reach here } @@ -985,6 +987,22 @@ func (g *generator) borrowRep(file *gen.File, dir wit.Direction, b *wit.Borrow) } } +func (g *generator) errorContextRep(file *gen.File, dir wit.Direction, e *wit.ErrorContext) string { + return file.Import(g.opts.cmPackage) + ".ErrorContext" +} + +func (g *generator) streamRep(file *gen.File, dir wit.Direction, s *wit.Stream) string { + var b strings.Builder + stringio.Write(&b, file.Import(g.opts.cmPackage), ".Stream[", g.typeRep(file, dir, s.Type), "]") + return b.String() +} + +func (g *generator) futureRep(file *gen.File, dir wit.Direction, f *wit.Future) string { + var b strings.Builder + stringio.Write(&b, file.Import(g.opts.cmPackage), ".Future[", g.typeRep(file, dir, f.Type), "]") + return b.String() +} + func (g *generator) typeShape(file *gen.File, dir wit.Direction, t wit.Type) string { if !experimentCreateShapeTypes { return g.typeRep(file, dir, t) @@ -1013,8 +1031,10 @@ func (g *generator) typeDefShape(file *gen.File, dir wit.Direction, t *wit.TypeD // Monotypic tuples have a packed memory layout. return g.typeRep(file, dir, t) } - case *wit.Resource, *wit.Own, *wit.Borrow, *wit.Enum, *wit.Flags, *wit.List: - // Resource handles, enum, flags, and list types do not need a custom shape. + case *wit.Enum, *wit.Flags, *wit.List, + *wit.Resource, *wit.Own, *wit.Borrow, *wit.ErrorContext, *wit.Stream, *wit.Future: + // Certain types do not need custom type shapes: + // own, borrow, error-context, stream, future, enum, flags, and list return g.typeRep(file, dir, t) } @@ -1082,12 +1102,9 @@ func (g *generator) lowerTypeDef(file *gen.File, dir wit.Direction, t *wit.TypeD return g.lowerOption(file, dir, t, input) case *wit.List: return g.cmCall(file, "LowerList", input) - case *wit.Resource, *wit.Own, *wit.Borrow: + case *wit.Resource, *wit.Own, *wit.Borrow, + *wit.ErrorContext, *wit.Stream, *wit.Future: return g.cmCall(file, "Reinterpret["+g.typeRep(file, dir, flat[0])+"]", input) - case *wit.Future: - return "/* TODO: lower *wit.Future */" - case *wit.Stream: - return "/* TODO: lower *wit.Stream */" default: panic(fmt.Sprintf("BUG: unknown wit.TypeDef %T", kind)) // should never reach here } @@ -1299,12 +1316,9 @@ func (g *generator) liftTypeDef(file *gen.File, dir wit.Direction, t *wit.TypeDe return g.liftOption(file, dir, t, input) case *wit.List: return g.cmCall(file, "LiftList["+g.typeRep(file, dir, t)+"]", input) - case *wit.Resource, *wit.Own, *wit.Borrow: + case *wit.Resource, *wit.Own, *wit.Borrow, + *wit.ErrorContext, *wit.Stream, *wit.Future: return g.cmCall(file, "Reinterpret["+g.typeRep(file, dir, t)+"]", input) - case *wit.Future: - return "// TODO: lift *wit.Future */" - case *wit.Stream: - return "// TODO: lift *wit.Stream */" default: panic(fmt.Sprintf("BUG: unknown wit.TypeDef %T", kind)) // should never reach here } @@ -2243,7 +2257,7 @@ func (g *generator) exportsFileFor(owner wit.TypeOwner) *gen.File { func (g *generator) wasmFileFor(owner wit.TypeOwner) *gen.File { pkg := g.packageFor(owner) - file := pkg.File(pkg.Name + ".wasm.go") + file := pkg.File(path.Base(pkg.Path) + ".wasm.go") file.GeneratedBy = g.opts.generatedBy if len(file.Header) == 0 { file.Header = fmt.Sprintf("// This file contains wasmimport and wasmexport declarations for \"%s\".\n\n", owner.WITPackage().Name.String()) @@ -2253,7 +2267,7 @@ func (g *generator) wasmFileFor(owner wit.TypeOwner) *gen.File { func (g *generator) cgoFileFor(owner wit.TypeOwner) *gen.File { pkg := g.packageFor(owner) - file := pkg.File(pkg.Name + ".cgo.go") + file := pkg.File(path.Base(pkg.Path) + ".cgo.go") file.GeneratedBy = g.opts.generatedBy if file.GoBuild == "" { file.GoBuild = "tinygo.wasm" diff --git a/wit/codec.go b/wit/codec.go index 28cb7af7..569d635b 100644 --- a/wit/codec.go +++ b/wit/codec.go @@ -324,6 +324,9 @@ func (c *typeDefKindCodec) DecodeString(s string) error { switch s { case "resource": *c.v = &Resource{} + case "errorcontext", // https://github.com/bytecodealliance/wasm-tools/pull/1964 + "error-context": + *c.v = &ErrorContext{} } return nil } @@ -331,18 +334,14 @@ func (c *typeDefKindCodec) DecodeString(s string) error { func (c *typeDefKindCodec) DecodeField(dec codec.Decoder, name string) error { var err error switch name { + case "type": + var v Type + err = dec.Decode(&v) + *c.v = v case "record": v := &Record{} err = dec.Decode(v) *c.v = v - case "resource": // TODO: this might not be necessary - v := &Resource{} - err = dec.Decode(v) - *c.v = v - case "handle": - var v Handle - err = dec.Decode(&v) - *c.v = v case "flags": v := &Flags{} err = dec.Decode(v) @@ -351,6 +350,10 @@ func (c *typeDefKindCodec) DecodeField(dec codec.Decoder, name string) error { v := &Tuple{} err = dec.Decode(v) *c.v = v + case "list": + v := &List{} + err = dec.Decode(&v.Type) + *c.v = v case "variant": v := &Variant{} err = dec.Decode(v) @@ -367,9 +370,9 @@ func (c *typeDefKindCodec) DecodeField(dec codec.Decoder, name string) error { v := &Result{} err = dec.Decode(v) *c.v = v - case "list": - v := &List{} - err = dec.Decode(&v.Type) + case "handle": + var v Handle + err = dec.Decode(&v) *c.v = v case "future": v := &Future{} @@ -379,10 +382,6 @@ func (c *typeDefKindCodec) DecodeField(dec codec.Decoder, name string) error { v := &Stream{} err = dec.Decode(&v.Type) *c.v = v - case "type": - var v Type - err = dec.Decode(&v) - *c.v = v } return err } diff --git a/wit/error.go b/wit/error.go new file mode 100644 index 00000000..07245336 --- /dev/null +++ b/wit/error.go @@ -0,0 +1,26 @@ +package wit + +// ErrorContext represents a WIT [error-context] type. +// It implements the [Node], [ABI], and [TypeDefKind] interfaces. +// +// [resource type]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#error-context-type +type ErrorContext struct{ _typeDefKind } + +// Size returns the [ABI byte size] for [ErrorContext]. +// +// [ABI byte size]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#size +func (*ErrorContext) Size() uintptr { return 4 } + +// Align returns the [ABI byte alignment] for [ErrorContext]. +// +// [ABI byte alignment]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#alignment +func (*ErrorContext) Align() uintptr { return 4 } + +// Flat returns the [flattened] ABI representation of [ErrorContext]. +// +// [flattened]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#flattening +func (*ErrorContext) Flat() []Type { return []Type{U32{}} } + +// hasResource always returns false. +// TODO: is error-context a resource? Does it have direction? +func (*ErrorContext) hasResource() bool { return false } diff --git a/wit/future.go b/wit/future.go index b5ec3380..2fa95e64 100644 --- a/wit/future.go +++ b/wit/future.go @@ -11,22 +11,19 @@ type Future struct { } // Size returns the [ABI byte size] for a [Future]. -// TODO: what is the ABI size of a future? // // [ABI byte size]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#size -func (*Future) Size() uintptr { return 0 } +func (*Future) Size() uintptr { return 4 } // Align returns the [ABI byte alignment] a [Future]. -// TODO: what is the ABI alignment of a future? // // [ABI byte alignment]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#alignment -func (*Future) Align() uintptr { return 0 } +func (*Future) Align() uintptr { return 4 } // Flat returns the [flattened] ABI representation of [Future]. -// TODO: what is the ABI representation of a stream? // // [flattened]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#flattening -func (*Future) Flat() []Type { return nil } +func (*Future) Flat() []Type { return []Type{U32{}} } func (f *Future) hasPointer() bool { return HasPointer(f.Type) } func (f *Future) hasBorrow() bool { return HasBorrow(f.Type) } diff --git a/wit/stream.go b/wit/stream.go index cc5dea40..609967ff 100644 --- a/wit/stream.go +++ b/wit/stream.go @@ -11,22 +11,19 @@ type Stream struct { } // Size returns the [ABI byte size] for a [Stream]. -// TODO: what is the ABI size of a stream? // // [ABI byte size]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#size -func (*Stream) Size() uintptr { return 0 } +func (*Stream) Size() uintptr { return 4 } // Align returns the [ABI byte alignment] a [Stream]. -// TODO: what is the ABI alignment of a stream? // // [ABI byte alignment]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#alignment -func (*Stream) Align() uintptr { return 0 } +func (*Stream) Align() uintptr { return 4 } // Flat returns the [flattened] ABI representation of [Stream]. -// TODO: what is the ABI representation of a stream? // // [flattened]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#flattening -func (*Stream) Flat() []Type { return nil } +func (*Stream) Flat() []Type { return []Type{U32{}} } func (s *Stream) hasPointer() bool { return HasPointer(s.Type) } func (s *Stream) hasBorrow() bool { return HasBorrow(s.Type) } diff --git a/wit/wit.go b/wit/wit.go index aef8df4d..b9687b3b 100644 --- a/wit/wit.go +++ b/wit/wit.go @@ -511,48 +511,49 @@ func escape(name string) string { // A map of all [WIT keywords]. // -// [WIT keywords]: https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wit-parser/src/ast/lex.rs#L524-L591 +// [WIT keywords]: https://github.com/bytecodealliance/wasm-tools/blob/main/crates/wit-parser/src/ast/lex.rs#L528-L578 var witKeywords = map[string]bool{ - "as": true, - "bool": true, - "borrow": true, - "char": true, - "constructor": true, - "enum": true, - "export": true, - "f32": true, - "f64": true, - "flags": true, - "from": true, - "func": true, - "future": true, - "import": true, - "include": true, - "interface": true, - "list": true, - "option": true, - "own": true, - "package": true, - "record": true, - "resource": true, - "result": true, - "s16": true, - "s32": true, - "s64": true, - "s8": true, - "static": true, - "stream": true, - "string": true, - "tuple": true, - "type": true, - "u16": true, - "u32": true, - "u64": true, - "u8": true, - "use": true, - "variant": true, - "wit": true, - "world": true, + "as": true, + "bool": true, + "borrow": true, + "char": true, + "constructor": true, + "enum": true, + "error-context": true, + "export": true, + "f32": true, + "f64": true, + "flags": true, + "from": true, + "func": true, + "future": true, + "import": true, + "include": true, + "interface": true, + "list": true, + "option": true, + "own": true, + "package": true, + "record": true, + "resource": true, + "result": true, + "s16": true, + "s32": true, + "s64": true, + "s8": true, + "static": true, + "stream": true, + "string": true, + "tuple": true, + "type": true, + "u16": true, + "u32": true, + "u64": true, + "u8": true, + "use": true, + "variant": true, + "wit": true, + "world": true, } func relativeName(o TypeOwner, p *Package) string { @@ -691,6 +692,23 @@ func (b *Borrow) WIT(ctx Node, name string) string { return s.String() } +// WITKind returns the WIT kind. +func (*ErrorContext) WITKind() string { return "error-context" } + +// WIT returns the [WIT] text format for [ErrorContext] r. +// +// [WIT]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md +func (*ErrorContext) WIT(_ Node, name string) string { + var b strings.Builder + if name != "" { + b.WriteString("type ") + b.WriteString(escape(name)) + b.WriteString(" = ") + } + b.WriteString("error-context") + return b.String() +} + // WITKind returns the WIT kind. func (*Flags) WITKind() string { return "flags" }