chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "d4e317f22c3bace76cb3205003bcc34b4929037d"
},
"path_in_vcs": "crates/wit-parser"
}

576
vendor/wit-parser/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,576 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "clap"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "escape8259"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6"
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "indexmap"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
"serde",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libtest-mimic"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5297962ef19edda4ce33aaa484386e0a5b3d7f2f4e037cbeee00503ef6b29d33"
dependencies = [
"anstream",
"anstyle",
"clap",
"escape8259",
]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "serde"
version = "1.0.222"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aab69e3f5be1836a1fe0aca0b286e5a5b38f262d6c9e8acd2247818751fcc8fb"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.222"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8ebec5eea07db7df9342aa712db2138f019d9ab3454a60a680579a6f841b80"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.222"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5f61630fe26d0ff555e6c37dc445ab2f15871c8a11ace3cf471b3195d3e4f49"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags",
"indexmap",
"semver",
]
[[package]]
name = "wast"
version = "244.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e7b9f9e23311275920e3d6b56d64137c160cf8af4f84a7283b36cfecbf4acb"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width",
"wasm-encoder",
]
[[package]]
name = "wat"
version = "1.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbf35b87ed352f9ab6cd0732abde5a67dd6153dfd02c493e61459218b19456fa"
dependencies = [
"wast",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-parser"
version = "0.244.0"
dependencies = [
"anyhow",
"env_logger",
"id-arena",
"indexmap",
"libtest-mimic",
"log",
"pretty_assertions",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
"wat",
]
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

157
vendor/wit-parser/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,157 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.81.0"
name = "wit-parser"
version = "0.244.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = """
Tooling for parsing `*.wit` files and working with their contents.
"""
homepage = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser"
documentation = "https://docs.rs/wit-parser"
readme = "README.md"
license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser"
[features]
decoding = ["dep:wasmparser"]
default = [
"serde",
"decoding",
]
serde = [
"dep:serde",
"dep:serde_derive",
"indexmap/serde",
"serde_json",
]
wat = [
"decoding",
"dep:wat",
]
[lib]
name = "wit_parser"
path = "src/lib.rs"
[[test]]
name = "all"
path = "tests/all.rs"
harness = false
[dependencies.anyhow]
version = "1.0.58"
[dependencies.id-arena]
version = "2"
[dependencies.indexmap]
version = "2.7.0"
features = ["std"]
default-features = false
[dependencies.log]
version = "0.4.17"
[dependencies.semver]
version = "1.0.0"
default-features = false
[dependencies.serde]
version = "1.0.166"
features = ["alloc"]
optional = true
default-features = false
[dependencies.serde_derive]
version = "1.0.166"
optional = true
[dependencies.serde_json]
version = "1"
optional = true
[dependencies.unicode-xid]
version = "0.2.2"
[dependencies.wasmparser]
version = "0.244.0"
features = [
"simd",
"std",
"validate",
"component-model",
"features",
]
optional = true
default-features = false
[dependencies.wat]
version = "1.244.0"
features = ["component-model"]
optional = true
default-features = false
[dev-dependencies.env_logger]
version = "0.11"
[dev-dependencies.libtest-mimic]
version = "0.8.1"
[dev-dependencies.pretty_assertions]
version = "1.3.0"
[dev-dependencies.serde_json]
version = "1"
[lints.clippy]
clone_on_copy = "warn"
manual_strip = "warn"
map_clone = "warn"
uninlined_format_args = "warn"
unnecessary_cast = "warn"
unnecessary_fallible_conversions = "warn"
unnecessary_mut_passed = "warn"
unnecessary_to_owned = "warn"
[lints.clippy.all]
level = "allow"
priority = -1
[lints.rust]
deprecated-safe-2024 = "warn"
keyword_idents_2024 = "warn"
missing-unsafe-on-extern = "warn"
rust-2024-guarded-string-incompatible-syntax = "warn"
rust-2024-incompatible-pat = "warn"
rust-2024-prelude-collisions = "warn"
unsafe-attr-outside-unsafe = "warn"
unsafe-op-in-unsafe-fn = "warn"
unsafe_code = "deny"
unstable_features = "warn"
unused-lifetimes = "warn"
unused-macro-rules = "warn"
unused_extern_crates = "warn"
unused_import_braces = "warn"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ["cfg(fuzzing)"]

13
vendor/wit-parser/README.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# `wit-parser`
A Rust crate for parsing and interpreting the [`*.wit`][wit] text format. This
text format is used to describe the imports and exports of a [component].
[wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
[component]: https://github.com/webassembly/component-model
This crate is a low-level tooling crate which is intended to be integrated
further into toolchains elsewhere and isn't necessarily interacted with on a
day-to-day basis. Internally it supports parsing a `*.wit` document into a
structured AST. Additionally it implements mechanisms of the canonical ABI to
assist in binding the canonical ABI into various languages.

410
vendor/wit-parser/src/abi.rs vendored Normal file
View File

@@ -0,0 +1,410 @@
use crate::{Function, Handle, Int, Resolve, Type, TypeDefKind};
/// A core WebAssembly signature with params and results.
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct WasmSignature {
/// The WebAssembly parameters of this function.
pub params: Vec<WasmType>,
/// The WebAssembly results of this function.
pub results: Vec<WasmType>,
/// Whether or not this signature is passing all of its parameters
/// indirectly through a pointer within `params`.
///
/// Note that `params` still reflects the true wasm parameters of this
/// function, this is auxiliary information for code generators if
/// necessary.
pub indirect_params: bool,
/// Whether or not this signature is using a return pointer to store the
/// result of the function, which is reflected either in `params` or
/// `results` depending on the context this function is used (e.g. an import
/// or an export).
pub retptr: bool,
}
/// Enumerates wasm types used by interface types when lowering/lifting.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum WasmType {
I32,
I64,
F32,
F64,
/// A pointer type. In core Wasm this typically lowers to either `i32` or
/// `i64` depending on the index type of the exported linear memory,
/// however bindings can use different source-level types to preserve
/// provenance.
///
/// Users that don't do anything special for pointers can treat this as
/// `i32`.
Pointer,
/// A type for values which can be either pointers or 64-bit integers.
/// This occurs in variants, when pointers and non-pointers are unified.
///
/// Users that don't do anything special for pointers can treat this as
/// `i64`.
PointerOrI64,
/// An array length type. In core Wasm this lowers to either `i32` or `i64`
/// depending on the index type of the exported linear memory.
///
/// Users that don't do anything special for pointers can treat this as
/// `i32`.
Length,
// NOTE: we don't lower interface types to any other Wasm type,
// e.g. externref, so we don't need to define them here.
}
fn join(a: WasmType, b: WasmType) -> WasmType {
use WasmType::*;
match (a, b) {
(I32, I32)
| (I64, I64)
| (F32, F32)
| (F64, F64)
| (Pointer, Pointer)
| (PointerOrI64, PointerOrI64)
| (Length, Length) => a,
(I32, F32) | (F32, I32) => I32,
// A length is at least an `i32`, maybe more, so it wins over
// 32-bit types.
(Length, I32 | F32) => Length,
(I32 | F32, Length) => Length,
// A length might be an `i64`, but might not be, so if we have
// 64-bit types, they win.
(Length, I64 | F64) => I64,
(I64 | F64, Length) => I64,
// Pointers have provenance and are at least an `i32`, so they
// win over 32-bit and length types.
(Pointer, I32 | F32 | Length) => Pointer,
(I32 | F32 | Length, Pointer) => Pointer,
// If we need 64 bits and provenance, we need to use the special
// `PointerOrI64`.
(Pointer, I64 | F64) => PointerOrI64,
(I64 | F64, Pointer) => PointerOrI64,
// PointerOrI64 wins over everything.
(PointerOrI64, _) => PointerOrI64,
(_, PointerOrI64) => PointerOrI64,
// Otherwise, `i64` wins.
(_, I64 | F64) | (I64 | F64, _) => I64,
}
}
impl From<Int> for WasmType {
fn from(i: Int) -> WasmType {
match i {
Int::U8 | Int::U16 | Int::U32 => WasmType::I32,
Int::U64 => WasmType::I64,
}
}
}
/// We use a different ABI for wasm importing functions exported by the host
/// than for wasm exporting functions imported by the host.
///
/// Note that this reflects the flavor of ABI we generate, and not necessarily
/// the way the resulting bindings will be used by end users. See the comments
/// on the `Direction` enum in gen-core for details.
///
/// The bindings ABI has a concept of a "guest" and a "host". There are two
/// variants of the ABI, one specialized for the "guest" importing and calling
/// a function defined and exported in the "host", and the other specialized for
/// the "host" importing and calling a function defined and exported in the "guest".
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum AbiVariant {
/// The guest is importing and calling the function.
GuestImport,
/// The guest is defining and exporting the function.
GuestExport,
GuestImportAsync,
GuestExportAsync,
GuestExportAsyncStackful,
}
impl AbiVariant {
pub fn is_async(&self) -> bool {
match self {
Self::GuestImport | Self::GuestExport => false,
Self::GuestImportAsync | Self::GuestExportAsync | Self::GuestExportAsyncStackful => {
true
}
}
}
}
pub struct FlatTypes<'a> {
types: &'a mut [WasmType],
cur: usize,
overflow: bool,
}
impl<'a> FlatTypes<'a> {
pub fn new(types: &'a mut [WasmType]) -> FlatTypes<'a> {
FlatTypes {
types,
cur: 0,
overflow: false,
}
}
pub fn push(&mut self, ty: WasmType) -> bool {
match self.types.get_mut(self.cur) {
Some(next) => {
*next = ty;
self.cur += 1;
true
}
None => {
self.overflow = true;
false
}
}
}
pub fn to_vec(&self) -> Vec<WasmType> {
self.types[..self.cur].to_vec()
}
}
impl Resolve {
pub const MAX_FLAT_PARAMS: usize = 16;
pub const MAX_FLAT_ASYNC_PARAMS: usize = 4;
pub const MAX_FLAT_RESULTS: usize = 1;
/// Get the WebAssembly type signature for this interface function
///
/// The first entry returned is the list of parameters and the second entry
/// is the list of results for the wasm function signature.
pub fn wasm_signature(&self, variant: AbiVariant, func: &Function) -> WasmSignature {
// Note that one extra parameter is allocated in case a return pointer
// is needed down below for imports.
let mut storage = [WasmType::I32; Self::MAX_FLAT_PARAMS + 1];
let mut params = FlatTypes::new(&mut storage);
let ok = self.push_flat_list(func.params.iter().map(|(_, param)| param), &mut params);
assert_eq!(ok, !params.overflow);
let max = match variant {
AbiVariant::GuestImport
| AbiVariant::GuestExport
| AbiVariant::GuestExportAsync
| AbiVariant::GuestExportAsyncStackful => Self::MAX_FLAT_PARAMS,
AbiVariant::GuestImportAsync => Self::MAX_FLAT_ASYNC_PARAMS,
};
let indirect_params = !ok || params.cur > max;
if indirect_params {
params.types[0] = WasmType::Pointer;
params.cur = 1;
} else {
if matches!(
(&func.kind, variant),
(
crate::FunctionKind::Method(_) | crate::FunctionKind::AsyncMethod(_),
AbiVariant::GuestExport
| AbiVariant::GuestExportAsync
| AbiVariant::GuestExportAsyncStackful
)
) {
// Guest exported methods always receive resource rep as first argument
//
// TODO: Ideally you would distinguish between imported and exported
// resource Handles and then use either I32 or Pointer in abi::push_flat().
// But this contextual information isn't available, yet.
// See https://github.com/bytecodealliance/wasm-tools/pull/1438 for more details.
assert!(matches!(params.types[0], WasmType::I32));
params.types[0] = WasmType::Pointer;
}
}
let mut storage = [WasmType::I32; Self::MAX_FLAT_RESULTS];
let mut results = FlatTypes::new(&mut storage);
let mut retptr = false;
match variant {
AbiVariant::GuestImport | AbiVariant::GuestExport => {
if let Some(ty) = &func.result {
self.push_flat(ty, &mut results);
}
retptr = results.overflow;
// Rust/C don't support multi-value well right now, so if a
// function would have multiple results then instead truncate
// it. Imports take a return pointer to write into and exports
// return a pointer they wrote into.
if retptr {
results.cur = 0;
match variant {
AbiVariant::GuestImport => {
assert!(params.push(WasmType::Pointer));
}
AbiVariant::GuestExport => {
assert!(results.push(WasmType::Pointer));
}
_ => unreachable!(),
}
}
}
AbiVariant::GuestImportAsync => {
// If this function has a result, a pointer must be passed to
// get filled in by the async runtime.
if func.result.is_some() {
assert!(params.push(WasmType::Pointer));
retptr = true;
}
// The result of this function is a status code.
assert!(results.push(WasmType::I32));
}
AbiVariant::GuestExportAsync => {
// The result of this function is a status code. Note that the
// function results are entirely ignored here as they aren't
// part of the ABI and are handled in the `task.return`
// intrinsic.
assert!(results.push(WasmType::I32));
}
AbiVariant::GuestExportAsyncStackful => {
// No status code, and like async exports no result handling.
}
}
WasmSignature {
params: params.to_vec(),
indirect_params,
results: results.to_vec(),
retptr,
}
}
fn push_flat_list<'a>(
&self,
mut list: impl Iterator<Item = &'a Type>,
result: &mut FlatTypes<'_>,
) -> bool {
list.all(|ty| self.push_flat(ty, result))
}
/// Appends the flat wasm types representing `ty` onto the `result`
/// list provided.
pub fn push_flat(&self, ty: &Type, result: &mut FlatTypes<'_>) -> bool {
match ty {
Type::Bool
| Type::S8
| Type::U8
| Type::S16
| Type::U16
| Type::S32
| Type::U32
| Type::Char
| Type::ErrorContext => result.push(WasmType::I32),
Type::U64 | Type::S64 => result.push(WasmType::I64),
Type::F32 => result.push(WasmType::F32),
Type::F64 => result.push(WasmType::F64),
Type::String => result.push(WasmType::Pointer) && result.push(WasmType::Length),
Type::Id(id) => match &self.types[*id].kind {
TypeDefKind::Type(t) => self.push_flat(t, result),
TypeDefKind::Handle(Handle::Own(_) | Handle::Borrow(_)) => {
result.push(WasmType::I32)
}
TypeDefKind::Resource => todo!(),
TypeDefKind::Record(r) => {
self.push_flat_list(r.fields.iter().map(|f| &f.ty), result)
}
TypeDefKind::Tuple(t) => self.push_flat_list(t.types.iter(), result),
TypeDefKind::Flags(r) => {
self.push_flat_list((0..r.repr().count()).map(|_| &Type::U32), result)
}
TypeDefKind::List(_) => {
result.push(WasmType::Pointer) && result.push(WasmType::Length)
}
TypeDefKind::Map(_, _) => {
result.push(WasmType::Pointer) && result.push(WasmType::Length)
}
TypeDefKind::FixedSizeList(ty, size) => {
self.push_flat_list((0..*size).map(|_| ty), result)
}
TypeDefKind::Variant(v) => {
result.push(v.tag().into())
&& self.push_flat_variants(v.cases.iter().map(|c| c.ty.as_ref()), result)
}
TypeDefKind::Enum(e) => result.push(e.tag().into()),
TypeDefKind::Option(t) => {
result.push(WasmType::I32) && self.push_flat_variants([None, Some(t)], result)
}
TypeDefKind::Result(r) => {
result.push(WasmType::I32)
&& self.push_flat_variants([r.ok.as_ref(), r.err.as_ref()], result)
}
TypeDefKind::Future(_) => result.push(WasmType::I32),
TypeDefKind::Stream(_) => result.push(WasmType::I32),
TypeDefKind::Unknown => unreachable!(),
},
}
}
fn push_flat_variants<'a>(
&self,
tys: impl IntoIterator<Item = Option<&'a Type>>,
result: &mut FlatTypes<'_>,
) -> bool {
let mut temp = result.types[result.cur..].to_vec();
let mut temp = FlatTypes::new(&mut temp);
let start = result.cur;
// Push each case's type onto a temporary vector, and then
// merge that vector into our final list starting at
// `start`. Note that this requires some degree of
// "unification" so we can handle things like `Result<i32,
// f32>` where that turns into `[i32 i32]` where the second
// `i32` might be the `f32` bitcasted.
for ty in tys {
if let Some(ty) = ty {
if !self.push_flat(ty, &mut temp) {
result.overflow = true;
return false;
}
for (i, ty) in temp.types[..temp.cur].iter().enumerate() {
let i = i + start;
if i < result.cur {
result.types[i] = join(result.types[i], *ty);
} else if result.cur == result.types.len() {
result.overflow = true;
return false;
} else {
result.types[i] = *ty;
result.cur += 1;
}
}
temp.cur = 0;
}
}
true
}
}

1958
vendor/wit-parser/src/ast.rs vendored Normal file

File diff suppressed because it is too large Load Diff

751
vendor/wit-parser/src/ast/lex.rs vendored Normal file
View File

@@ -0,0 +1,751 @@
use anyhow::{Result, bail};
use std::char;
use std::fmt;
use std::str;
use unicode_xid::UnicodeXID;
use self::Token::*;
#[derive(Clone)]
pub struct Tokenizer<'a> {
input: &'a str,
span_offset: u32,
chars: CrlfFold<'a>,
require_f32_f64: bool,
}
#[derive(Clone)]
struct CrlfFold<'a> {
chars: str::CharIndices<'a>,
}
/// A span, designating a range of bytes where a token is located.
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub struct Span {
/// The start of the range.
pub start: u32,
/// The end of the range (exclusive).
pub end: u32,
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Token {
Whitespace,
Comment,
Equals,
Comma,
Colon,
Period,
Semicolon,
LeftParen,
RightParen,
LeftBrace,
RightBrace,
LessThan,
GreaterThan,
RArrow,
Star,
At,
Slash,
Plus,
Minus,
Use,
Type,
Func,
U8,
U16,
U32,
U64,
S8,
S16,
S32,
S64,
F32,
F64,
Char,
Record,
Resource,
Own,
Borrow,
Flags,
Variant,
Enum,
Bool,
String_,
Option_,
Result_,
Future,
Stream,
ErrorContext,
List,
Map,
Underscore,
As,
From_,
Static,
Interface,
Tuple,
Import,
Export,
World,
Package,
Constructor,
Async,
Id,
ExplicitId,
Integer,
Include,
With,
}
#[derive(Eq, PartialEq, Debug)]
#[allow(dead_code)]
pub enum Error {
InvalidCharInId(u32, char),
IdPartEmpty(u32),
InvalidEscape(u32, char),
Unexpected(u32, char),
UnterminatedComment(u32),
Wanted {
at: u32,
expected: &'static str,
found: &'static str,
},
}
// NB: keep in sync with `crates/wit-component/src/printing.rs`.
const REQUIRE_F32_F64_BY_DEFAULT: bool = true;
impl<'a> Tokenizer<'a> {
pub fn new(
input: &'a str,
span_offset: u32,
require_f32_f64: Option<bool>,
) -> Result<Tokenizer<'a>> {
detect_invalid_input(input)?;
let mut t = Tokenizer {
input,
span_offset,
chars: CrlfFold {
chars: input.char_indices(),
},
require_f32_f64: require_f32_f64.unwrap_or_else(|| {
match std::env::var("WIT_REQUIRE_F32_F64") {
Ok(s) => s == "1",
Err(_) => REQUIRE_F32_F64_BY_DEFAULT,
}
}),
};
// Eat utf-8 BOM
t.eatc('\u{feff}');
Ok(t)
}
pub fn expect_semicolon(&mut self) -> Result<()> {
self.expect(Token::Semicolon)?;
Ok(())
}
pub fn get_span(&self, span: Span) -> &'a str {
let start = usize::try_from(span.start - self.span_offset).unwrap();
let end = usize::try_from(span.end - self.span_offset).unwrap();
&self.input[start..end]
}
pub fn parse_id(&self, span: Span) -> Result<&'a str> {
let ret = self.get_span(span);
validate_id(span.start, &ret)?;
Ok(ret)
}
pub fn parse_explicit_id(&self, span: Span) -> Result<&'a str> {
let token = self.get_span(span);
let id_part = token.strip_prefix('%').unwrap();
validate_id(span.start, id_part)?;
Ok(id_part)
}
pub fn next(&mut self) -> Result<Option<(Span, Token)>, Error> {
loop {
match self.next_raw()? {
Some((_, Token::Whitespace)) | Some((_, Token::Comment)) => {}
other => break Ok(other),
}
}
}
/// Three possibilities when calling this method: an `Err(...)` indicates that lexing failed, an
/// `Ok(Some(...))` produces the next token, and `Ok(None)` indicates that there are no more
/// tokens available.
pub fn next_raw(&mut self) -> Result<Option<(Span, Token)>, Error> {
let (str_start, ch) = match self.chars.next() {
Some(pair) => pair,
None => return Ok(None),
};
let start = self.span_offset + u32::try_from(str_start).unwrap();
let token = match ch {
'\n' | '\t' | ' ' => {
// Eat all contiguous whitespace tokens
while self.eatc(' ') || self.eatc('\t') || self.eatc('\n') {}
Whitespace
}
'/' => {
// Eat a line comment if it's `//...`
if self.eatc('/') {
for (_, ch) in &mut self.chars {
if ch == '\n' {
break;
}
}
Comment
// eat a block comment if it's `/*...`
} else if self.eatc('*') {
let mut depth = 1;
while depth > 0 {
let (_, ch) = match self.chars.next() {
Some(pair) => pair,
None => return Err(Error::UnterminatedComment(start)),
};
match ch {
'/' if self.eatc('*') => depth += 1,
'*' if self.eatc('/') => depth -= 1,
_ => {}
}
}
Comment
} else {
Slash
}
}
'=' => Equals,
',' => Comma,
':' => Colon,
'.' => Period,
';' => Semicolon,
'(' => LeftParen,
')' => RightParen,
'{' => LeftBrace,
'}' => RightBrace,
'<' => LessThan,
'>' => GreaterThan,
'*' => Star,
'@' => At,
'-' => {
if self.eatc('>') {
RArrow
} else {
Minus
}
}
'+' => Plus,
'%' => {
let mut iter = self.chars.clone();
if let Some((_, ch)) = iter.next() {
if is_keylike_start(ch) {
self.chars = iter.clone();
while let Some((_, ch)) = iter.next() {
if !is_keylike_continue(ch) {
break;
}
self.chars = iter.clone();
}
}
}
ExplicitId
}
ch if is_keylike_start(ch) => {
let remaining = self.chars.chars.as_str().len();
let mut iter = self.chars.clone();
while let Some((_, ch)) = iter.next() {
if !is_keylike_continue(ch) {
break;
}
self.chars = iter.clone();
}
let str_end =
str_start + ch.len_utf8() + (remaining - self.chars.chars.as_str().len());
match &self.input[str_start..str_end] {
"use" => Use,
"type" => Type,
"func" => Func,
"u8" => U8,
"u16" => U16,
"u32" => U32,
"u64" => U64,
"s8" => S8,
"s16" => S16,
"s32" => S32,
"s64" => S64,
"f32" => F32,
"f64" => F64,
"float32" if !self.require_f32_f64 => F32,
"float64" if !self.require_f32_f64 => F64,
"char" => Char,
"resource" => Resource,
"own" => Own,
"borrow" => Borrow,
"record" => Record,
"flags" => Flags,
"variant" => Variant,
"enum" => Enum,
"bool" => Bool,
"string" => String_,
"option" => Option_,
"result" => Result_,
"future" => Future,
"stream" => Stream,
"error-context" => ErrorContext,
"list" => List,
"map" => Map,
"_" => Underscore,
"as" => As,
"from" => From_,
"static" => Static,
"interface" => Interface,
"tuple" => Tuple,
"world" => World,
"import" => Import,
"export" => Export,
"package" => Package,
"constructor" => Constructor,
"include" => Include,
"with" => With,
"async" => Async,
_ => Id,
}
}
ch if ch.is_ascii_digit() => {
let mut iter = self.chars.clone();
while let Some((_, ch)) = iter.next() {
if !ch.is_ascii_digit() {
break;
}
self.chars = iter.clone();
}
Integer
}
ch => return Err(Error::Unexpected(start, ch)),
};
let end = match self.chars.clone().next() {
Some((i, _)) => i,
None => self.input.len(),
};
let end = self.span_offset + u32::try_from(end).unwrap();
Ok(Some((Span { start, end }, token)))
}
pub fn eat(&mut self, expected: Token) -> Result<bool, Error> {
let mut other = self.clone();
match other.next()? {
Some((_span, found)) if expected == found => {
*self = other;
Ok(true)
}
Some(_) => Ok(false),
None => Ok(false),
}
}
pub fn expect(&mut self, expected: Token) -> Result<Span, Error> {
match self.next()? {
Some((span, found)) => {
if expected == found {
Ok(span)
} else {
Err(Error::Wanted {
at: span.start,
expected: expected.describe(),
found: found.describe(),
})
}
}
None => Err(Error::Wanted {
at: self.span_offset + u32::try_from(self.input.len()).unwrap(),
expected: expected.describe(),
found: "eof",
}),
}
}
fn eatc(&mut self, ch: char) -> bool {
let mut iter = self.chars.clone();
match iter.next() {
Some((_, ch2)) if ch == ch2 => {
self.chars = iter;
true
}
_ => false,
}
}
pub fn eof_span(&self) -> Span {
let end = self.span_offset + u32::try_from(self.input.len()).unwrap();
Span { start: end, end }
}
}
impl<'a> Iterator for CrlfFold<'a> {
type Item = (usize, char);
fn next(&mut self) -> Option<(usize, char)> {
self.chars.next().map(|(i, c)| {
if c == '\r' {
let mut attempt = self.chars.clone();
if let Some((_, '\n')) = attempt.next() {
self.chars = attempt;
return (i, '\n');
}
}
(i, c)
})
}
}
fn detect_invalid_input(input: &str) -> Result<()> {
// Disallow specific codepoints.
let mut line = 1;
for ch in input.chars() {
match ch {
'\n' => line += 1,
'\r' | '\t' => {}
// Bidirectional override codepoints can be used to craft source code that
// appears to have a different meaning than its actual meaning. See
// [CVE-2021-42574] for background and motivation.
//
// [CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574
'\u{202a}' | '\u{202b}' | '\u{202c}' | '\u{202d}' | '\u{202e}' | '\u{2066}'
| '\u{2067}' | '\u{2068}' | '\u{2069}' => {
bail!(
"Input contains bidirectional override codepoint {:?} at line {}",
ch.escape_unicode(),
line
);
}
// Disallow several characters which are deprecated or discouraged in Unicode.
//
// U+149 deprecated; see Unicode 13.0.0, sec. 7.1 Latin, Compatibility Digraphs.
// U+673 deprecated; see Unicode 13.0.0, sec. 9.2 Arabic, Additional Vowel Marks.
// U+F77 and U+F79 deprecated; see Unicode 13.0.0, sec. 13.4 Tibetan, Vowels.
// U+17A3 and U+17A4 deprecated, and U+17B4 and U+17B5 discouraged; see
// Unicode 13.0.0, sec. 16.4 Khmer, Characters Whose Use Is Discouraged.
'\u{149}' | '\u{673}' | '\u{f77}' | '\u{f79}' | '\u{17a3}' | '\u{17a4}'
| '\u{17b4}' | '\u{17b5}' => {
bail!(
"Codepoint {:?} at line {} is discouraged by Unicode",
ch.escape_unicode(),
line
);
}
// Disallow control codes other than the ones explicitly recognized above,
// so that viewing a wit file on a terminal doesn't have surprising side
// effects or appear to have a different meaning than its actual meaning.
ch if ch.is_control() => {
bail!("Control code '{}' at line {}", ch.escape_unicode(), line);
}
_ => {}
}
}
Ok(())
}
fn is_keylike_start(ch: char) -> bool {
// Lex any XID start, `_`, or '-'. These aren't all valid identifier chars,
// but we'll diagnose that after we've lexed the full string.
UnicodeXID::is_xid_start(ch) || ch == '_' || ch == '-'
}
fn is_keylike_continue(ch: char) -> bool {
// Lex any XID continue (which includes `_`) or '-'.
UnicodeXID::is_xid_continue(ch) || ch == '-'
}
pub fn validate_id(start: u32, id: &str) -> Result<(), Error> {
// IDs must have at least one part.
if id.is_empty() {
return Err(Error::IdPartEmpty(start));
}
// Ids consist of parts separated by '-'s.
for (idx, part) in id.split('-').enumerate() {
// Parts must be non-empty and contain either all ASCII lowercase or
// all ASCII uppercase. Non-first segment can also start with a digit.
let Some(first_char) = part.chars().next() else {
return Err(Error::IdPartEmpty(start));
};
if idx == 0 && !first_char.is_ascii_alphabetic() {
return Err(Error::InvalidCharInId(start, first_char));
}
let mut upper = None;
for ch in part.chars() {
if ch.is_ascii_digit() {
// Digits are accepted in both uppercase and lowercase segments.
} else if ch.is_ascii_uppercase() {
if upper.is_none() {
upper = Some(true);
} else if let Some(false) = upper {
return Err(Error::InvalidCharInId(start, ch));
}
} else if ch.is_ascii_lowercase() {
if upper.is_none() {
upper = Some(false);
} else if let Some(true) = upper {
return Err(Error::InvalidCharInId(start, ch));
}
} else {
return Err(Error::InvalidCharInId(start, ch));
}
}
}
Ok(())
}
impl Token {
pub fn describe(&self) -> &'static str {
match self {
Whitespace => "whitespace",
Comment => "a comment",
Equals => "'='",
Comma => "','",
Colon => "':'",
Period => "'.'",
Semicolon => "';'",
LeftParen => "'('",
RightParen => "')'",
LeftBrace => "'{'",
RightBrace => "'}'",
LessThan => "'<'",
GreaterThan => "'>'",
Use => "keyword `use`",
Type => "keyword `type`",
Func => "keyword `func`",
U8 => "keyword `u8`",
U16 => "keyword `u16`",
U32 => "keyword `u32`",
U64 => "keyword `u64`",
S8 => "keyword `s8`",
S16 => "keyword `s16`",
S32 => "keyword `s32`",
S64 => "keyword `s64`",
F32 => "keyword `f32`",
F64 => "keyword `f64`",
Char => "keyword `char`",
Own => "keyword `own`",
Borrow => "keyword `borrow`",
Resource => "keyword `resource`",
Record => "keyword `record`",
Flags => "keyword `flags`",
Variant => "keyword `variant`",
Enum => "keyword `enum`",
Bool => "keyword `bool`",
String_ => "keyword `string`",
Option_ => "keyword `option`",
Result_ => "keyword `result`",
Future => "keyword `future`",
Stream => "keyword `stream`",
ErrorContext => "keyword `error-context`",
List => "keyword `list`",
Map => "keyword `map`",
Underscore => "keyword `_`",
Id => "an identifier",
ExplicitId => "an '%' identifier",
RArrow => "`->`",
Star => "`*`",
At => "`@`",
Slash => "`/`",
Plus => "`+`",
Minus => "`-`",
As => "keyword `as`",
From_ => "keyword `from`",
Static => "keyword `static`",
Interface => "keyword `interface`",
Tuple => "keyword `tuple`",
Import => "keyword `import`",
Export => "keyword `export`",
World => "keyword `world`",
Package => "keyword `package`",
Constructor => "keyword `constructor`",
Integer => "an integer",
Include => "keyword `include`",
With => "keyword `with`",
Async => "keyword `async`",
}
}
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Unexpected(_, ch) => write!(f, "unexpected character {ch:?}"),
Error::UnterminatedComment(_) => write!(f, "unterminated block comment"),
Error::Wanted {
expected, found, ..
} => write!(f, "expected {expected}, found {found}"),
Error::InvalidCharInId(_, ch) => write!(f, "invalid character in identifier {ch:?}"),
Error::IdPartEmpty(_) => write!(f, "identifiers must have characters between '-'s"),
Error::InvalidEscape(_, ch) => write!(f, "invalid escape in string {ch:?}"),
}
}
}
#[test]
fn test_validate_id() {
validate_id(0, "apple").unwrap();
validate_id(0, "apple-pear").unwrap();
validate_id(0, "apple-pear-grape").unwrap();
validate_id(0, "a0").unwrap();
validate_id(0, "a").unwrap();
validate_id(0, "a-a").unwrap();
validate_id(0, "bool").unwrap();
validate_id(0, "APPLE").unwrap();
validate_id(0, "APPLE-PEAR").unwrap();
validate_id(0, "APPLE-PEAR-GRAPE").unwrap();
validate_id(0, "apple-PEAR-grape").unwrap();
validate_id(0, "APPLE-pear-GRAPE").unwrap();
validate_id(0, "ENOENT").unwrap();
validate_id(0, "is-XML").unwrap();
validate_id(0, "apple-0").unwrap();
validate_id(0, "a0-000-3d4a-54FF").unwrap();
assert!(validate_id(0, "").is_err());
assert!(validate_id(0, "0").is_err());
assert!(validate_id(0, "%").is_err());
assert!(validate_id(0, "$").is_err());
assert!(validate_id(0, "0a").is_err());
assert!(validate_id(0, ".").is_err());
assert!(validate_id(0, "·").is_err());
assert!(validate_id(0, "a a").is_err());
assert!(validate_id(0, "_").is_err());
assert!(validate_id(0, "-").is_err());
assert!(validate_id(0, "a-").is_err());
assert!(validate_id(0, "-a").is_err());
assert!(validate_id(0, "Apple").is_err());
assert!(validate_id(0, "applE").is_err());
assert!(validate_id(0, "-apple-pear").is_err());
assert!(validate_id(0, "apple-pear-").is_err());
assert!(validate_id(0, "apple_pear").is_err());
assert!(validate_id(0, "apple.pear").is_err());
assert!(validate_id(0, "apple pear").is_err());
assert!(validate_id(0, "apple/pear").is_err());
assert!(validate_id(0, "apple|pear").is_err());
assert!(validate_id(0, "apple-Pear").is_err());
assert!(validate_id(0, "()()").is_err());
assert!(validate_id(0, "").is_err());
assert!(validate_id(0, "*").is_err());
assert!(validate_id(0, "apple\u{5f3}pear").is_err());
assert!(validate_id(0, "apple\u{200c}pear").is_err());
assert!(validate_id(0, "apple\u{200d}pear").is_err());
assert!(validate_id(0, "apple--pear").is_err());
assert!(validate_id(0, "_apple").is_err());
assert!(validate_id(0, "apple_").is_err());
assert!(validate_id(0, "_Znwj").is_err());
assert!(validate_id(0, "__i386").is_err());
assert!(validate_id(0, "__i386__").is_err());
assert!(validate_id(0, "Москва").is_err());
assert!(validate_id(0, "garçon-hühnervögel-Москва-東京").is_err());
assert!(validate_id(0, "a0-000-3d4A-54Ff").is_err());
assert!(validate_id(0, "😼").is_err(), "non-identifier");
assert!(validate_id(0, "\u{212b}").is_err(), "non-ascii");
}
#[test]
fn test_tokenizer() {
fn collect(s: &str) -> Result<Vec<Token>> {
let mut t = Tokenizer::new(s, 0, None)?;
let mut tokens = Vec::new();
while let Some(token) = t.next()? {
tokens.push(token.1);
}
Ok(tokens)
}
assert_eq!(collect("").unwrap(), vec![]);
assert_eq!(collect("_").unwrap(), vec![Token::Underscore]);
assert_eq!(collect("apple").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple-pear").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple--pear").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple-Pear").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple-pear-grape").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple pear").unwrap(), vec![Token::Id, Token::Id]);
assert_eq!(collect("_a_p_p_l_e_").unwrap(), vec![Token::Id]);
assert_eq!(collect("garçon").unwrap(), vec![Token::Id]);
assert_eq!(collect("hühnervögel").unwrap(), vec![Token::Id]);
assert_eq!(collect("москва").unwrap(), vec![Token::Id]);
assert_eq!(collect("東京").unwrap(), vec![Token::Id]);
assert_eq!(
collect("garçon-hühnervögel-москва-東京").unwrap(),
vec![Token::Id]
);
assert_eq!(collect("a0").unwrap(), vec![Token::Id]);
assert_eq!(collect("a").unwrap(), vec![Token::Id]);
assert_eq!(collect("%a").unwrap(), vec![Token::ExplicitId]);
assert_eq!(collect("%a-a").unwrap(), vec![Token::ExplicitId]);
assert_eq!(collect("%bool").unwrap(), vec![Token::ExplicitId]);
assert_eq!(collect("%").unwrap(), vec![Token::ExplicitId]);
assert_eq!(collect("APPLE").unwrap(), vec![Token::Id]);
assert_eq!(collect("APPLE-PEAR").unwrap(), vec![Token::Id]);
assert_eq!(collect("APPLE-PEAR-GRAPE").unwrap(), vec![Token::Id]);
assert_eq!(collect("apple-PEAR-grape").unwrap(), vec![Token::Id]);
assert_eq!(collect("APPLE-pear-GRAPE").unwrap(), vec![Token::Id]);
assert_eq!(collect("ENOENT").unwrap(), vec![Token::Id]);
assert_eq!(collect("is-XML").unwrap(), vec![Token::Id]);
assert_eq!(collect("func").unwrap(), vec![Token::Func]);
assert_eq!(
collect("a: func()").unwrap(),
vec![
Token::Id,
Token::Colon,
Token::Func,
Token::LeftParen,
Token::RightParen
]
);
assert_eq!(collect("resource").unwrap(), vec![Token::Resource]);
assert_eq!(collect("own").unwrap(), vec![Token::Own]);
assert_eq!(
collect("own<some-id>").unwrap(),
vec![Token::Own, Token::LessThan, Token::Id, Token::GreaterThan]
);
assert_eq!(collect("borrow").unwrap(), vec![Token::Borrow]);
assert_eq!(
collect("borrow<some-id>").unwrap(),
vec![
Token::Borrow,
Token::LessThan,
Token::Id,
Token::GreaterThan
]
);
assert!(collect("\u{149}").is_err(), "strongly discouraged");
assert!(collect("\u{673}").is_err(), "strongly discouraged");
assert!(collect("\u{17a3}").is_err(), "strongly discouraged");
assert!(collect("\u{17a4}").is_err(), "strongly discouraged");
assert!(collect("\u{202a}").is_err(), "bidirectional override");
assert!(collect("\u{2068}").is_err(), "bidirectional override");
assert!(collect("\u{0}").is_err(), "control code");
assert!(collect("\u{b}").is_err(), "control code");
assert!(collect("\u{c}").is_err(), "control code");
assert!(collect("\u{85}").is_err(), "control code");
}

1813
vendor/wit-parser/src/ast/resolve.rs vendored Normal file

File diff suppressed because it is too large Load Diff

249
vendor/wit-parser/src/ast/toposort.rs vendored Normal file
View File

@@ -0,0 +1,249 @@
use crate::ast::{Id, Span};
use anyhow::Result;
use indexmap::IndexMap;
use std::collections::BinaryHeap;
use std::fmt;
use std::mem;
#[derive(Default, Clone)]
struct State {
/// Number of outbound edges from this node which have still not been
/// processed into the topological ordering.
outbound_remaining: usize,
/// Indices of nodes that depend on this one, used when this node is added
/// to the binary heap to decrement `outbound_remaining`.
reverse_deps: Vec<usize>,
}
/// Performs a topological sort of the `deps` provided, returning the order in
/// which to visit the nodes in reverse-dep order.
///
/// This sort goes one level further as well to produce a stable ordering
/// regardless of the input edges so long as the structure of the graph has
/// changed. Notably the nodes are sorted, by name, in the output in addition to
/// being sorted in dependency order. This is done to assist with round-tripping
/// documents where new edges are discovered during world elaboration that
/// doesn't change the dependency graph but can change the dependency listings
/// between serializations.
///
/// The algorithm chosen here to do this is:
///
/// * Build some metadata about all nodes including their count of outbound
/// edges remaining to be added to the order and a reverse dependency list.
/// * Collect all nodes with 0 outbound edges into a binary heap.
/// * Pop from the binary heap and decrement outbound edges that depend on
/// this node.
/// * Iterate until the dependency ordering is the same size as the dependency
/// array.
///
/// This sort will also detect when dependencies are missing or when cycles are
/// present and return an error.
pub fn toposort<'a>(
kind: &str,
deps: &IndexMap<&'a str, Vec<Id<'a>>>,
) -> Result<Vec<&'a str>, Error> {
// Initialize a `State` per-node with the number of outbound edges and
// additionally filling out the `reverse_deps` array.
let mut states = vec![State::default(); deps.len()];
for (i, (_, edges)) in deps.iter().enumerate() {
states[i].outbound_remaining = edges.len();
for edge in edges {
let (j, _, _) = deps
.get_full(edge.name)
.ok_or_else(|| Error::NonexistentDep {
span: edge.span,
name: edge.name.to_string(),
kind: kind.to_string(),
highlighted: None,
})?;
states[j].reverse_deps.push(i);
}
}
let mut order = Vec::new();
let mut heap = BinaryHeap::new();
// Seed the `heap` with edges that have no outbound edges
//
// The heap here is keyed by `(usize, &str, usize)` where the first `usize`
// is unique which is what determines the order of the heap. The other two
// fields are metadata used when pulling from the heap. The first `usize` is
// the index of the item within the original dependency map which should
// reflect the original source order of the item. Note that this is stored
// in reverse order to ensure that when there are multiple items in the heap
// the first item in the original order is popped first.
for (i, dep) in deps.keys().enumerate() {
if states[i].outbound_remaining == 0 {
heap.push((deps.len() - i, *dep, i));
}
}
// Drain the binary heap which represents all nodes that have had all their
// dependencies processed. Iteratively add to the heap as well as nodes are
// removed.
while let Some((_order, node, i)) = heap.pop() {
order.push(node);
for i in mem::take(&mut states[i].reverse_deps) {
states[i].outbound_remaining -= 1;
if states[i].outbound_remaining == 0 {
let (dep, _) = deps.get_index(i).unwrap();
heap.push((deps.len() - i, *dep, i));
}
}
}
// If all nodes are present in order then a topological ordering was
// achieved and it can be returned.
if order.len() == deps.len() {
return Ok(order);
}
// ... otherwise there are still dependencies with remaining edges which
// means that a cycle must be present, so find the cycle and report the
// error.
for (i, state) in states.iter().enumerate() {
if state.outbound_remaining == 0 {
continue;
}
let (_, edges) = deps.get_index(i).unwrap();
for dep in edges {
let (j, _, _) = deps.get_full(dep.name).unwrap();
if states[j].outbound_remaining == 0 {
continue;
}
return Err(Error::Cycle {
span: dep.span,
name: dep.name.to_string(),
kind: kind.to_string(),
highlighted: None,
});
}
}
unreachable!()
}
#[derive(Debug)]
pub enum Error {
NonexistentDep {
span: Span,
name: String,
kind: String,
highlighted: Option<String>,
},
Cycle {
span: Span,
name: String,
kind: String,
highlighted: Option<String>,
},
}
impl Error {
pub(crate) fn highlighted(&self) -> Option<&str> {
match self {
Error::NonexistentDep { highlighted, .. } | Error::Cycle { highlighted, .. } => {
highlighted.as_deref()
}
}
}
pub(crate) fn set_highlighted(&mut self, string: String) {
match self {
Error::NonexistentDep { highlighted, .. } | Error::Cycle { highlighted, .. } => {
*highlighted = Some(string);
}
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(s) = self.highlighted() {
return f.write_str(s);
}
match self {
Error::NonexistentDep { kind, name, .. } => {
write!(f, "{kind} `{name}` does not exist")
}
Error::Cycle { kind, name, .. } => {
write!(f, "{kind} `{name}` depends on itself")
}
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
fn id(name: &str) -> Id<'_> {
Id {
name,
span: Span { start: 0, end: 0 },
}
}
#[test]
fn smoke() {
let empty: Vec<&str> = Vec::new();
assert_eq!(toposort("", &IndexMap::new()).unwrap(), empty);
let mut nonexistent = IndexMap::new();
nonexistent.insert("a", vec![id("b")]);
assert!(matches!(
toposort("", &nonexistent),
Err(Error::NonexistentDep { .. })
));
let mut one = IndexMap::new();
one.insert("a", vec![]);
assert_eq!(toposort("", &one).unwrap(), ["a"]);
let mut two = IndexMap::new();
two.insert("a", vec![]);
two.insert("b", vec![id("a")]);
assert_eq!(toposort("", &two).unwrap(), ["a", "b"]);
let mut two = IndexMap::new();
two.insert("a", vec![id("b")]);
two.insert("b", vec![]);
assert_eq!(toposort("", &two).unwrap(), ["b", "a"]);
}
#[test]
fn cycles() {
let mut cycle = IndexMap::new();
cycle.insert("a", vec![id("a")]);
assert!(matches!(toposort("", &cycle), Err(Error::Cycle { .. })));
let mut cycle = IndexMap::new();
cycle.insert("a", vec![id("b")]);
cycle.insert("b", vec![id("c")]);
cycle.insert("c", vec![id("a")]);
assert!(matches!(toposort("", &cycle), Err(Error::Cycle { .. })));
}
#[test]
fn depend_twice() {
let mut two = IndexMap::new();
two.insert("b", vec![id("a"), id("a")]);
two.insert("a", vec![]);
assert_eq!(toposort("", &two).unwrap(), ["a", "b"]);
}
#[test]
fn preserve_order() {
let mut order = IndexMap::new();
order.insert("a", vec![]);
order.insert("b", vec![]);
assert_eq!(toposort("", &order).unwrap(), ["a", "b"]);
let mut order = IndexMap::new();
order.insert("b", vec![]);
order.insert("a", vec![]);
assert_eq!(toposort("", &order).unwrap(), ["b", "a"]);
}
}

1864
vendor/wit-parser/src/decoding.rs vendored Normal file

File diff suppressed because it is too large Load Diff

1413
vendor/wit-parser/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

264
vendor/wit-parser/src/live.rs vendored Normal file
View File

@@ -0,0 +1,264 @@
use crate::{
Function, FunctionKind, InterfaceId, Resolve, Type, TypeDef, TypeDefKind, TypeId, WorldId,
WorldItem,
};
use indexmap::IndexSet;
#[derive(Default)]
pub struct LiveTypes {
set: IndexSet<TypeId>,
}
impl LiveTypes {
pub fn iter(&self) -> impl Iterator<Item = TypeId> + '_ {
self.set.iter().copied()
}
pub fn len(&self) -> usize {
self.set.len()
}
pub fn contains(&self, id: TypeId) -> bool {
self.set.contains(&id)
}
pub fn add_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
self.visit_interface(resolve, iface);
}
pub fn add_world(&mut self, resolve: &Resolve, world: WorldId) {
self.visit_world(resolve, world);
}
pub fn add_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
self.visit_world_item(resolve, item);
}
pub fn add_func(&mut self, resolve: &Resolve, func: &Function) {
self.visit_func(resolve, func);
}
pub fn add_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
self.visit_type_id(resolve, ty);
}
pub fn add_type(&mut self, resolve: &Resolve, ty: &Type) {
self.visit_type(resolve, ty);
}
}
impl TypeIdVisitor for LiveTypes {
fn before_visit_type_id(&mut self, id: TypeId) -> bool {
!self.set.contains(&id)
}
fn after_visit_type_id(&mut self, id: TypeId) {
assert!(self.set.insert(id));
}
}
/// Helper trait to walk the structure of a type and visit all `TypeId`s that
/// it refers to, possibly transitively.
pub trait TypeIdVisitor {
/// Callback invoked just before a type is visited.
///
/// If this function returns `false` the type is not visited, otherwise it's
/// recursed into.
fn before_visit_type_id(&mut self, id: TypeId) -> bool {
let _ = id;
true
}
/// Callback invoked once a type is finished being visited.
fn after_visit_type_id(&mut self, id: TypeId) {
let _ = id;
}
fn visit_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
let iface = &resolve.interfaces[iface];
for (_, id) in iface.types.iter() {
self.visit_type_id(resolve, *id);
}
for (_, func) in iface.functions.iter() {
self.visit_func(resolve, func);
}
}
fn visit_world(&mut self, resolve: &Resolve, world: WorldId) {
let world = &resolve.worlds[world];
for (_, item) in world.imports.iter().chain(world.exports.iter()) {
self.visit_world_item(resolve, item);
}
}
fn visit_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
match item {
WorldItem::Interface { id, .. } => self.visit_interface(resolve, *id),
WorldItem::Function(f) => self.visit_func(resolve, f),
WorldItem::Type(t) => self.visit_type_id(resolve, *t),
}
}
fn visit_func(&mut self, resolve: &Resolve, func: &Function) {
match func.kind {
// This resource is live as it's attached to a static method but
// it's not guaranteed to be present in either params or results, so
// be sure to attach it here.
FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {
self.visit_type_id(resolve, id)
}
// The resource these are attached to is in the params/results, so
// no need to re-add it here.
FunctionKind::Method(_)
| FunctionKind::AsyncMethod(_)
| FunctionKind::Constructor(_) => {}
FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
}
for (_, ty) in func.params.iter() {
self.visit_type(resolve, ty);
}
if let Some(ty) = &func.result {
self.visit_type(resolve, ty);
}
}
fn visit_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
if self.before_visit_type_id(ty) {
self.visit_type_def(resolve, &resolve.types[ty]);
self.after_visit_type_id(ty);
}
}
fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) {
match &ty.kind {
TypeDefKind::Type(t)
| TypeDefKind::List(t)
| TypeDefKind::FixedSizeList(t, ..)
| TypeDefKind::Option(t)
| TypeDefKind::Future(Some(t))
| TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
TypeDefKind::Map(k, v) => {
self.visit_type(resolve, k);
self.visit_type(resolve, v);
}
TypeDefKind::Handle(handle) => match handle {
crate::Handle::Own(ty) => self.visit_type_id(resolve, *ty),
crate::Handle::Borrow(ty) => self.visit_type_id(resolve, *ty),
},
TypeDefKind::Resource => {}
TypeDefKind::Record(r) => {
for field in r.fields.iter() {
self.visit_type(resolve, &field.ty);
}
}
TypeDefKind::Tuple(r) => {
for ty in r.types.iter() {
self.visit_type(resolve, ty);
}
}
TypeDefKind::Variant(v) => {
for case in v.cases.iter() {
if let Some(ty) = &case.ty {
self.visit_type(resolve, ty);
}
}
}
TypeDefKind::Result(r) => {
if let Some(ty) = &r.ok {
self.visit_type(resolve, ty);
}
if let Some(ty) = &r.err {
self.visit_type(resolve, ty);
}
}
TypeDefKind::Flags(_)
| TypeDefKind::Enum(_)
| TypeDefKind::Future(None)
| TypeDefKind::Stream(None) => {}
TypeDefKind::Unknown => unreachable!(),
}
}
fn visit_type(&mut self, resolve: &Resolve, ty: &Type) {
match ty {
Type::Id(id) => self.visit_type_id(resolve, *id),
_ => {}
}
}
}
#[cfg(test)]
mod tests {
use super::{LiveTypes, Resolve};
fn live(wit: &str, ty: &str) -> Vec<String> {
let mut resolve = Resolve::default();
resolve.push_str("test.wit", wit).unwrap();
let (_, interface) = resolve.interfaces.iter().next_back().unwrap();
let ty = interface.types[ty];
let mut live = LiveTypes::default();
live.add_type_id(&resolve, ty);
live.iter()
.filter_map(|ty| resolve.types[ty].name.clone())
.collect()
}
#[test]
fn no_deps() {
let types = live(
"
package foo:bar;
interface foo {
type t = u32;
}
",
"t",
);
assert_eq!(types, ["t"]);
}
#[test]
fn one_dep() {
let types = live(
"
package foo:bar;
interface foo {
type t = u32;
type u = t;
}
",
"u",
);
assert_eq!(types, ["t", "u"]);
}
#[test]
fn chain() {
let types = live(
"
package foo:bar;
interface foo {
resource t1;
record t2 {
x: t1,
}
variant t3 {
x(t2),
}
flags t4 { a }
enum t5 { a }
type t6 = tuple<t5, t4, t3>;
}
",
"t6",
);
assert_eq!(types, ["t5", "t4", "t1", "t2", "t3", "t6"]);
}
}

772
vendor/wit-parser/src/metadata.rs vendored Normal file
View File

@@ -0,0 +1,772 @@
//! Implementation of encoding/decoding package metadata (docs/stability) in a
//! custom section.
//!
//! This module contains the particulars for how this custom section is encoded
//! and decoded at this time. As of the time of this writing the component model
//! binary format does not have any means of storing documentation and/or item
//! stability inline with items themselves. These are important to preserve when
//! round-tripping WIT through the WebAssembly binary format, however, so this
//! module implements this with a custom section.
//!
//! The custom section, named `SECTION_NAME`, is stored within the component
//! that encodes a WIT package. This section is itself JSON-encoded with a small
//! version header to help forwards/backwards compatibility. The hope is that
//! one day this custom section will be obsoleted by extensions to the binary
//! format to store this information inline.
use crate::{
Docs, Function, InterfaceId, PackageId, Resolve, Stability, TypeDefKind, TypeId, WorldId,
WorldItem, WorldKey,
};
use anyhow::{Result, bail};
use indexmap::IndexMap;
#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
type StringMap<V> = IndexMap<String, V>;
/// Current supported format of the custom section.
///
/// This byte is a prefix byte intended to be a general version marker for the
/// entire custom section. This is bumped when backwards-incompatible changes
/// are made to prevent older implementations from loading newer versions.
///
/// The history of this is:
///
/// * [????/??/??] 0 - the original format added
/// * [2024/04/19] 1 - extensions were added for item stability and
/// additionally having world imports/exports have the same name.
#[cfg(feature = "serde")]
const PACKAGE_DOCS_SECTION_VERSION: u8 = 1;
/// At this time the v1 format was just written. For compatibility with older
/// tools we'll still try to emit the v0 format by default, if the input is
/// compatible. This will be turned off in the future once enough published
/// versions support the v1 format.
const TRY_TO_EMIT_V0_BY_DEFAULT: bool = false;
/// Represents serializable doc comments parsed from a WIT package.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct PackageMetadata {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
docs: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
worlds: StringMap<WorldMetadata>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
interfaces: StringMap<InterfaceMetadata>,
}
impl PackageMetadata {
pub const SECTION_NAME: &'static str = "package-docs";
/// Extract package docs for the given package.
pub fn extract(resolve: &Resolve, package: PackageId) -> Self {
let package = &resolve.packages[package];
let worlds = package
.worlds
.iter()
.map(|(name, id)| (name.to_string(), WorldMetadata::extract(resolve, *id)))
.filter(|(_, item)| !item.is_empty())
.collect();
let interfaces = package
.interfaces
.iter()
.map(|(name, id)| (name.to_string(), InterfaceMetadata::extract(resolve, *id)))
.filter(|(_, item)| !item.is_empty())
.collect();
Self {
docs: package.docs.contents.as_deref().map(Into::into),
worlds,
interfaces,
}
}
/// Inject package docs for the given package.
///
/// This will override any existing docs in the [`Resolve`].
pub fn inject(&self, resolve: &mut Resolve, package: PackageId) -> Result<()> {
for (name, docs) in &self.worlds {
let Some(&id) = resolve.packages[package].worlds.get(name) else {
bail!("missing world {name:?}");
};
docs.inject(resolve, id)?;
}
for (name, docs) in &self.interfaces {
let Some(&id) = resolve.packages[package].interfaces.get(name) else {
bail!("missing interface {name:?}");
};
docs.inject(resolve, id)?;
}
if let Some(docs) = &self.docs {
resolve.packages[package].docs.contents = Some(docs.to_string());
}
Ok(())
}
/// Encode package docs as a package-docs custom section.
#[cfg(feature = "serde")]
pub fn encode(&self) -> Result<Vec<u8>> {
// Version byte, followed by JSON encoding of docs.
//
// Note that if this document is compatible with the v0 format then
// that's preferred to keep older tools working at this time.
// Eventually this branch will be removed and v1 will unconditionally
// be used.
let mut data = vec![
if TRY_TO_EMIT_V0_BY_DEFAULT && self.is_compatible_with_v0() {
0
} else {
PACKAGE_DOCS_SECTION_VERSION
},
];
serde_json::to_writer(&mut data, self)?;
Ok(data)
}
/// Decode package docs from package-docs custom section content.
#[cfg(feature = "serde")]
pub fn decode(data: &[u8]) -> Result<Self> {
match data.first().copied() {
// Our serde structures transparently support v0 and the current
// version, so allow either here.
Some(0) | Some(PACKAGE_DOCS_SECTION_VERSION) => {}
version => {
bail!(
"expected package-docs version {PACKAGE_DOCS_SECTION_VERSION}, got {version:?}"
);
}
}
Ok(serde_json::from_slice(&data[1..])?)
}
#[cfg(feature = "serde")]
fn is_compatible_with_v0(&self) -> bool {
self.worlds.iter().all(|(_, w)| w.is_compatible_with_v0())
&& self
.interfaces
.iter()
.all(|(_, w)| w.is_compatible_with_v0())
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
struct WorldMetadata {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
docs: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Stability::is_unknown")
)]
stability: Stability,
/// Metadata for named interface, e.g.:
///
/// ```wit
/// world foo {
/// import x: interface {}
/// }
/// ```
///
/// In the v0 format this was called "interfaces", hence the
/// `serde(rename)`. When support was originally added here imports/exports
/// could not overlap in their name, but now they can. This map has thus
/// been repurposed as:
///
/// * If an interface is imported, it goes here.
/// * If an interface is exported, and no interface was imported with the
/// same name, it goes here.
///
/// Otherwise exports go inside the `interface_exports` map.
///
/// In the future when v0 support is dropped this should become only
/// imports, not either imports-or-exports.
#[cfg_attr(
feature = "serde",
serde(
default,
rename = "interfaces",
skip_serializing_if = "StringMap::is_empty"
)
)]
interface_imports_or_exports: StringMap<InterfaceMetadata>,
/// All types in this interface.
///
/// Note that at this time types are only imported, never exported.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
types: StringMap<TypeMetadata>,
/// Same as `interface_imports_or_exports`, but for functions.
#[cfg_attr(
feature = "serde",
serde(default, rename = "funcs", skip_serializing_if = "StringMap::is_empty")
)]
func_imports_or_exports: StringMap<FunctionMetadata>,
/// The "export half" of `interface_imports_or_exports`.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
interface_exports: StringMap<InterfaceMetadata>,
/// The "export half" of `func_imports_or_exports`.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
func_exports: StringMap<FunctionMetadata>,
/// Stability annotations for interface imports that aren't inline, for
/// example:
///
/// ```wit
/// world foo {
/// @since(version = 1.0.0)
/// import an-interface;
/// }
/// ```
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
interface_import_stability: StringMap<Stability>,
/// Same as `interface_import_stability`, but for exports.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
interface_export_stability: StringMap<Stability>,
}
impl WorldMetadata {
fn extract(resolve: &Resolve, id: WorldId) -> Self {
let world = &resolve.worlds[id];
let mut interface_imports_or_exports = StringMap::default();
let mut types = StringMap::default();
let mut func_imports_or_exports = StringMap::default();
let mut interface_exports = StringMap::default();
let mut func_exports = StringMap::default();
let mut interface_import_stability = StringMap::default();
let mut interface_export_stability = StringMap::default();
for ((key, item), import) in world
.imports
.iter()
.map(|p| (p, true))
.chain(world.exports.iter().map(|p| (p, false)))
{
match key {
// For all named imports with kebab-names extract their
// docs/stability and insert it into one of our maps.
WorldKey::Name(name) => match item {
WorldItem::Interface { id, .. } => {
let data = InterfaceMetadata::extract(resolve, *id);
if data.is_empty() {
continue;
}
let map = if import {
&mut interface_imports_or_exports
} else if !TRY_TO_EMIT_V0_BY_DEFAULT
|| interface_imports_or_exports.contains_key(name)
{
&mut interface_exports
} else {
&mut interface_imports_or_exports
};
let prev = map.insert(name.to_string(), data);
assert!(prev.is_none());
}
WorldItem::Type(id) => {
let data = TypeMetadata::extract(resolve, *id);
if !data.is_empty() {
types.insert(name.to_string(), data);
}
}
WorldItem::Function(f) => {
let data = FunctionMetadata::extract(f);
if data.is_empty() {
continue;
}
let map = if import {
&mut func_imports_or_exports
} else if !TRY_TO_EMIT_V0_BY_DEFAULT
|| func_imports_or_exports.contains_key(name)
{
&mut func_exports
} else {
&mut func_imports_or_exports
};
let prev = map.insert(name.to_string(), data);
assert!(prev.is_none());
}
},
// For interface imports/exports extract the stability and
// record it if necessary.
WorldKey::Interface(_) => {
let stability = match item {
WorldItem::Interface { stability, .. } => stability,
_ => continue,
};
if stability.is_unknown() {
continue;
}
let map = if import {
&mut interface_import_stability
} else {
&mut interface_export_stability
};
let name = resolve.name_world_key(key);
map.insert(name, stability.clone());
}
}
}
Self {
docs: world.docs.contents.clone(),
stability: world.stability.clone(),
interface_imports_or_exports,
types,
func_imports_or_exports,
interface_exports,
func_exports,
interface_import_stability,
interface_export_stability,
}
}
fn inject(&self, resolve: &mut Resolve, id: WorldId) -> Result<()> {
// Inject docs/stability for all kebab-named interfaces, both imports
// and exports.
for ((name, data), only_export) in self
.interface_imports_or_exports
.iter()
.map(|p| (p, false))
.chain(self.interface_exports.iter().map(|p| (p, true)))
{
let key = WorldKey::Name(name.to_string());
let world = &mut resolve.worlds[id];
let item = if only_export {
world.exports.get_mut(&key)
} else {
match world.imports.get_mut(&key) {
Some(item) => Some(item),
None => world.exports.get_mut(&key),
}
};
let Some(WorldItem::Interface { id, stability }) = item else {
bail!("missing interface {name:?}");
};
*stability = data.stability.clone();
let id = *id;
data.inject(resolve, id)?;
}
// Process all types, which are always imported, for this world.
for (name, data) in &self.types {
let key = WorldKey::Name(name.to_string());
let Some(WorldItem::Type(id)) = resolve.worlds[id].imports.get(&key) else {
bail!("missing type {name:?}");
};
data.inject(resolve, *id)?;
}
// Build a map of `name_world_key` for interface imports/exports to the
// actual key. This map is then consluted in the next loop.
let world = &resolve.worlds[id];
let stabilities = world
.imports
.iter()
.map(|i| (i, true))
.chain(world.exports.iter().map(|i| (i, false)))
.filter_map(|((key, item), import)| match item {
WorldItem::Interface { .. } => {
Some(((resolve.name_world_key(key), import), key.clone()))
}
_ => None,
})
.collect::<IndexMap<_, _>>();
let world = &mut resolve.worlds[id];
// Update the stability of an interface imports/exports that aren't
// kebab-named.
for ((name, stability), import) in self
.interface_import_stability
.iter()
.map(|p| (p, true))
.chain(self.interface_export_stability.iter().map(|p| (p, false)))
{
let key = match stabilities.get(&(name.clone(), import)) {
Some(key) => key.clone(),
None => bail!("missing interface `{name}`"),
};
let item = if import {
world.imports.get_mut(&key)
} else {
world.exports.get_mut(&key)
};
match item {
Some(WorldItem::Interface { stability: s, .. }) => *s = stability.clone(),
_ => bail!("item `{name}` wasn't an interface"),
}
}
// Update the docs/stability of all functions imported/exported from
// this world.
for ((name, data), only_export) in self
.func_imports_or_exports
.iter()
.map(|p| (p, false))
.chain(self.func_exports.iter().map(|p| (p, true)))
{
let key = WorldKey::Name(name.to_string());
let item = if only_export {
world.exports.get_mut(&key)
} else {
match world.imports.get_mut(&key) {
Some(item) => Some(item),
None => world.exports.get_mut(&key),
}
};
match item {
Some(WorldItem::Function(f)) => data.inject(f)?,
_ => bail!("missing func {name:?}"),
}
}
if let Some(docs) = &self.docs {
world.docs.contents = Some(docs.to_string());
}
world.stability = self.stability.clone();
Ok(())
}
fn is_empty(&self) -> bool {
self.docs.is_none()
&& self.interface_imports_or_exports.is_empty()
&& self.types.is_empty()
&& self.func_imports_or_exports.is_empty()
&& self.stability.is_unknown()
&& self.interface_exports.is_empty()
&& self.func_exports.is_empty()
&& self.interface_import_stability.is_empty()
&& self.interface_export_stability.is_empty()
}
#[cfg(feature = "serde")]
fn is_compatible_with_v0(&self) -> bool {
self.stability.is_unknown()
&& self
.interface_imports_or_exports
.iter()
.all(|(_, w)| w.is_compatible_with_v0())
&& self
.func_imports_or_exports
.iter()
.all(|(_, w)| w.is_compatible_with_v0())
&& self.types.iter().all(|(_, w)| w.is_compatible_with_v0())
// These maps weren't present in v0, so we're only compatible if
// they're empty.
&& self.interface_exports.is_empty()
&& self.func_exports.is_empty()
&& self.interface_import_stability.is_empty()
&& self.interface_export_stability.is_empty()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
struct InterfaceMetadata {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
docs: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Stability::is_unknown")
)]
stability: Stability,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
funcs: StringMap<FunctionMetadata>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
types: StringMap<TypeMetadata>,
}
impl InterfaceMetadata {
fn extract(resolve: &Resolve, id: InterfaceId) -> Self {
let interface = &resolve.interfaces[id];
let funcs = interface
.functions
.iter()
.map(|(name, func)| (name.to_string(), FunctionMetadata::extract(func)))
.filter(|(_, item)| !item.is_empty())
.collect();
let types = interface
.types
.iter()
.map(|(name, id)| (name.to_string(), TypeMetadata::extract(resolve, *id)))
.filter(|(_, item)| !item.is_empty())
.collect();
Self {
docs: interface.docs.contents.clone(),
stability: interface.stability.clone(),
funcs,
types,
}
}
fn inject(&self, resolve: &mut Resolve, id: InterfaceId) -> Result<()> {
for (name, data) in &self.types {
let Some(&id) = resolve.interfaces[id].types.get(name) else {
bail!("missing type {name:?}");
};
data.inject(resolve, id)?;
}
let interface = &mut resolve.interfaces[id];
for (name, data) in &self.funcs {
let Some(f) = interface.functions.get_mut(name) else {
bail!("missing func {name:?}");
};
data.inject(f)?;
}
if let Some(docs) = &self.docs {
interface.docs.contents = Some(docs.to_string());
}
interface.stability = self.stability.clone();
Ok(())
}
fn is_empty(&self) -> bool {
self.docs.is_none()
&& self.funcs.is_empty()
&& self.types.is_empty()
&& self.stability.is_unknown()
}
#[cfg(feature = "serde")]
fn is_compatible_with_v0(&self) -> bool {
self.stability.is_unknown()
&& self.funcs.iter().all(|(_, w)| w.is_compatible_with_v0())
&& self.types.iter().all(|(_, w)| w.is_compatible_with_v0())
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged, deny_unknown_fields))]
enum FunctionMetadata {
/// In the v0 format function metadata was only a string so this variant
/// is preserved for the v0 format. In the future this can be removed
/// entirely in favor of just the below struct variant.
///
/// Note that this is an untagged enum so the name `JustDocs` is just for
/// rust.
JustDocs(Option<String>),
/// In the v1+ format we're tracking at least docs but also the stability
/// of functions.
DocsAndStabilty {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
docs: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Stability::is_unknown")
)]
stability: Stability,
},
}
impl FunctionMetadata {
fn extract(func: &Function) -> Self {
if TRY_TO_EMIT_V0_BY_DEFAULT && func.stability.is_unknown() {
FunctionMetadata::JustDocs(func.docs.contents.clone())
} else {
FunctionMetadata::DocsAndStabilty {
docs: func.docs.contents.clone(),
stability: func.stability.clone(),
}
}
}
fn inject(&self, func: &mut Function) -> Result<()> {
match self {
FunctionMetadata::JustDocs(docs) => {
func.docs.contents = docs.clone();
}
FunctionMetadata::DocsAndStabilty { docs, stability } => {
func.docs.contents = docs.clone();
func.stability = stability.clone();
}
}
Ok(())
}
fn is_empty(&self) -> bool {
match self {
FunctionMetadata::JustDocs(docs) => docs.is_none(),
FunctionMetadata::DocsAndStabilty { docs, stability } => {
docs.is_none() && stability.is_unknown()
}
}
}
#[cfg(feature = "serde")]
fn is_compatible_with_v0(&self) -> bool {
match self {
FunctionMetadata::JustDocs(_) => true,
FunctionMetadata::DocsAndStabilty { .. } => false,
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
struct TypeMetadata {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
docs: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Stability::is_unknown")
)]
stability: Stability,
// record fields, variant cases, etc.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "StringMap::is_empty")
)]
items: StringMap<String>,
}
impl TypeMetadata {
fn extract(resolve: &Resolve, id: TypeId) -> Self {
fn extract_items<T>(items: &[T], f: impl Fn(&T) -> (&String, &Docs)) -> StringMap<String> {
items
.iter()
.flat_map(|item| {
let (name, docs) = f(item);
Some((name.to_string(), docs.contents.clone()?))
})
.collect()
}
let ty = &resolve.types[id];
let items = match &ty.kind {
TypeDefKind::Record(record) => {
extract_items(&record.fields, |item| (&item.name, &item.docs))
}
TypeDefKind::Flags(flags) => {
extract_items(&flags.flags, |item| (&item.name, &item.docs))
}
TypeDefKind::Variant(variant) => {
extract_items(&variant.cases, |item| (&item.name, &item.docs))
}
TypeDefKind::Enum(enum_) => {
extract_items(&enum_.cases, |item| (&item.name, &item.docs))
}
// other types don't have inner items
_ => IndexMap::default(),
};
Self {
docs: ty.docs.contents.clone(),
stability: ty.stability.clone(),
items,
}
}
fn inject(&self, resolve: &mut Resolve, id: TypeId) -> Result<()> {
let ty = &mut resolve.types[id];
if !self.items.is_empty() {
match &mut ty.kind {
TypeDefKind::Record(record) => {
self.inject_items(&mut record.fields, |item| (&item.name, &mut item.docs))?
}
TypeDefKind::Flags(flags) => {
self.inject_items(&mut flags.flags, |item| (&item.name, &mut item.docs))?
}
TypeDefKind::Variant(variant) => {
self.inject_items(&mut variant.cases, |item| (&item.name, &mut item.docs))?
}
TypeDefKind::Enum(enum_) => {
self.inject_items(&mut enum_.cases, |item| (&item.name, &mut item.docs))?
}
_ => {
bail!("got 'items' for unexpected type {ty:?}");
}
}
}
if let Some(docs) = &self.docs {
ty.docs.contents = Some(docs.to_string());
}
ty.stability = self.stability.clone();
Ok(())
}
fn inject_items<T: std::fmt::Debug>(
&self,
items: &mut [T],
f: impl Fn(&mut T) -> (&String, &mut Docs),
) -> Result<()> {
let mut unused_docs = self.items.len();
for item in items.iter_mut() {
let (name, item_docs) = f(item);
if let Some(docs) = self.items.get(name.as_str()) {
item_docs.contents = Some(docs.to_string());
unused_docs -= 1;
}
}
if unused_docs > 0 {
bail!(
"not all 'items' match type items; {item_docs:?} vs {items:?}",
item_docs = self.items
);
}
Ok(())
}
fn is_empty(&self) -> bool {
self.docs.is_none() && self.items.is_empty() && self.stability.is_unknown()
}
#[cfg(feature = "serde")]
fn is_compatible_with_v0(&self) -> bool {
self.stability.is_unknown()
}
}

4636
vendor/wit-parser/src/resolve.rs vendored Normal file

File diff suppressed because it is too large Load Diff

227
vendor/wit-parser/src/resolve/clone.rs vendored Normal file
View File

@@ -0,0 +1,227 @@
//! A helper, non public, module to assist with cloning items within a
//! `Resolve`.
//!
//! Cloning items is not as simple as calling `Clone` due to the nature of how
//! `TypeId` tracks relationships between interfaces and types. A full deep
//! clone requires walking the full structure and allocating new id links. This
//! is akin to, for example, creating a deep copy of an `Rc<T>` by calling
//! `Clone for T`.
//!
//! This is currently used when merging worlds together to help copy anonymously
//! named items from one world to another.
//!
//! The general structure of this module is that each method takes a mutable
//! reference to an AST item and updates it as necessary internally, delegating
//! to other methods for internal AST items.
//!
//! This module does not at the time of this writing have full support for
//! cloning everything within a `Resolve`.
use crate::*;
use std::collections::HashMap;
/// Represents the results of cloning types and/or interfaces as part of a
/// `Resolve::merge_worlds` operation.
#[derive(Default)]
pub struct CloneMaps {
pub(super) types: HashMap<TypeId, TypeId>,
pub(super) interfaces: HashMap<InterfaceId, InterfaceId>,
}
impl CloneMaps {
/// The types cloned during a `Resolve::merge_worlds` operation.
///
/// The key is the original type, and the value is the clone.
pub fn types(&self) -> &HashMap<TypeId, TypeId> {
&self.types
}
/// The interfaces cloned during a `Resolve::merge_worlds` operation.
///
/// The key is the original interface, and the value is the clone.
pub fn interfaces(&self) -> &HashMap<InterfaceId, InterfaceId> {
&self.interfaces
}
}
pub struct Cloner<'a> {
pub resolve: &'a mut Resolve,
prev_owner: TypeOwner,
new_owner: TypeOwner,
/// This map keeps track, in the current scope of types, of all copied
/// types. This deduplicates copying types to ensure that they're only
/// copied at most once.
pub types: HashMap<TypeId, TypeId>,
/// If `None` then it's inferred from `self.new_owner`.
pub new_package: Option<PackageId>,
}
impl<'a> Cloner<'a> {
pub fn new(
resolve: &'a mut Resolve,
prev_owner: TypeOwner,
new_owner: TypeOwner,
) -> Cloner<'a> {
Cloner {
prev_owner,
new_owner,
resolve,
types: Default::default(),
new_package: None,
}
}
pub fn register_world_type_overlap(&mut self, from: WorldId, into: WorldId) {
let into = &self.resolve.worlds[into];
let from = &self.resolve.worlds[from];
for (name, into_import) in into.imports.iter() {
let WorldKey::Name(_) = name else { continue };
let WorldItem::Type(into_id) = into_import else {
continue;
};
let Some(WorldItem::Type(from_id)) = from.imports.get(name) else {
continue;
};
self.types.insert(*from_id, *into_id);
}
}
pub fn world_item(&mut self, key: &WorldKey, item: &mut WorldItem, clone_maps: &mut CloneMaps) {
match key {
WorldKey::Name(_) => {}
WorldKey::Interface(_) => return,
}
match item {
WorldItem::Type(t) => {
self.type_id(t);
}
WorldItem::Function(f) => {
self.function(f);
}
WorldItem::Interface { id, .. } => {
let old = *id;
self.interface(id, &mut clone_maps.types);
clone_maps.interfaces.insert(old, *id);
}
}
}
fn type_id(&mut self, ty: &mut TypeId) {
if !self.types.contains_key(ty) {
let mut new = self.resolve.types[*ty].clone();
self.type_def(&mut new);
let id = self.resolve.types.alloc(new);
self.types.insert(*ty, id);
}
*ty = self.types[ty];
}
fn type_def(&mut self, def: &mut TypeDef) {
if def.owner != TypeOwner::None {
assert_eq!(def.owner, self.prev_owner);
def.owner = self.new_owner;
}
match &mut def.kind {
TypeDefKind::Type(Type::Id(id)) => {
if self.resolve.types[*id].owner == self.prev_owner {
self.type_id(id);
} else {
// ..
}
}
TypeDefKind::Type(_)
| TypeDefKind::Resource
| TypeDefKind::Flags(_)
| TypeDefKind::Enum(_) => {}
TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
self.type_id(ty);
}
TypeDefKind::Option(ty)
| TypeDefKind::List(ty)
| TypeDefKind::FixedSizeList(ty, ..) => {
self.ty(ty);
}
TypeDefKind::Map(k, v) => {
self.ty(k);
self.ty(v);
}
TypeDefKind::Tuple(list) => {
for ty in list.types.iter_mut() {
self.ty(ty);
}
}
TypeDefKind::Record(r) => {
for field in r.fields.iter_mut() {
self.ty(&mut field.ty);
}
}
TypeDefKind::Variant(r) => {
for case in r.cases.iter_mut() {
if let Some(ty) = &mut case.ty {
self.ty(ty);
}
}
}
TypeDefKind::Result(r) => {
if let Some(ok) = &mut r.ok {
self.ty(ok);
}
if let Some(err) = &mut r.err {
self.ty(err);
}
}
TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
if let Some(ty) = ty {
self.ty(ty);
}
}
TypeDefKind::Unknown => {}
}
}
fn ty(&mut self, ty: &mut Type) {
match ty {
Type::Id(id) => self.type_id(id),
_ => {}
}
}
fn function(&mut self, func: &mut Function) {
if let Some(id) = func.kind.resource_mut() {
self.type_id(id);
}
for (_, ty) in func.params.iter_mut() {
self.ty(ty);
}
if let Some(ty) = &mut func.result {
self.ty(ty);
}
}
fn interface(&mut self, id: &mut InterfaceId, cloned_types: &mut HashMap<TypeId, TypeId>) {
let mut new = self.resolve.interfaces[*id].clone();
let next_id = self.resolve.interfaces.next_id();
let mut clone = Cloner::new(
self.resolve,
TypeOwner::Interface(*id),
TypeOwner::Interface(next_id),
);
for id in new.types.values_mut() {
clone.type_id(id);
}
for func in new.functions.values_mut() {
clone.function(func);
}
cloned_types.extend(clone.types);
new.package = Some(self.new_package.unwrap_or_else(|| match self.new_owner {
TypeOwner::Interface(id) => self.resolve.interfaces[id].package.unwrap(),
TypeOwner::World(id) => self.resolve.worlds[id].package.unwrap(),
TypeOwner::None => unreachable!(),
}));
*id = self.resolve.interfaces.alloc(new);
assert_eq!(*id, next_id);
}
}

140
vendor/wit-parser/src/serde_.rs vendored Normal file
View File

@@ -0,0 +1,140 @@
use crate::Type;
use id_arena::{Arena, Id};
use indexmap::IndexMap;
use semver::Version;
use serde::ser::{SerializeMap, SerializeSeq, Serializer};
use serde::{Deserialize, Serialize, de::Error};
pub fn serialize_none<S>(serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_none()
}
pub fn serialize_arena<T, S>(arena: &Arena<T>, serializer: S) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(arena.len()))?;
for (_, item) in arena.iter() {
seq.serialize_element(&item)?;
}
seq.end()
}
pub fn serialize_id<T, S>(id: &Id<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(id.index() as u64)
}
pub fn serialize_optional_id<T, S>(id: &Option<Id<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match id {
Some(id) => serialize_id(&id, serializer),
None => serializer.serialize_none(),
}
}
pub fn serialize_id_map<K, T, S>(map: &IndexMap<K, Id<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
K: Serialize,
S: Serializer,
{
let mut s = serializer.serialize_map(Some(map.len()))?;
for (key, id) in map.iter() {
s.serialize_entry(key, &(id.index() as u64))?;
}
s.end()
}
impl Serialize for Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Type::Bool => serializer.serialize_str("bool"),
Type::U8 => serializer.serialize_str("u8"),
Type::U16 => serializer.serialize_str("u16"),
Type::U32 => serializer.serialize_str("u32"),
Type::U64 => serializer.serialize_str("u64"),
Type::S8 => serializer.serialize_str("s8"),
Type::S16 => serializer.serialize_str("s16"),
Type::S32 => serializer.serialize_str("s32"),
Type::S64 => serializer.serialize_str("s64"),
Type::F32 => serializer.serialize_str("f32"),
Type::F64 => serializer.serialize_str("f64"),
Type::Char => serializer.serialize_str("char"),
Type::String => serializer.serialize_str("string"),
Type::ErrorContext => serializer.serialize_str("error-context"),
Type::Id(type_id) => serializer.serialize_u64(type_id.index() as u64),
}
}
}
pub fn serialize_params<S>(params: &[(String, Type)], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(params.len()))?;
for (name, typ) in params.iter() {
let param = Param {
name: name.to_string(),
typ: *typ,
};
seq.serialize_element(&param)?;
}
seq.end()
}
#[derive(Debug, Clone, PartialEq, serde_derive::Serialize)]
struct Param {
#[serde(skip_serializing_if = "String::is_empty")]
pub name: String,
#[serde(rename = "type")]
pub typ: Type,
}
pub fn serialize_version<S>(version: &Version, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
version.to_string().serialize(serializer)
}
pub fn deserialize_version<'de, D>(deserializer: D) -> Result<Version, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let version: String = String::deserialize(deserializer)?;
version.parse().map_err(|e| D::Error::custom(e))
}
pub fn serialize_optional_version<S>(
version: &Option<Version>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
version
.as_ref()
.map(|s| s.to_string())
.serialize(serializer)
}
pub fn deserialize_optional_version<'de, D>(deserializer: D) -> Result<Option<Version>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
match <Option<String>>::deserialize(deserializer)? {
Some(version) => Ok(Some(version.parse().map_err(|e| D::Error::custom(e))?)),
None => Ok(None),
}
}

626
vendor/wit-parser/src/sizealign.rs vendored Normal file
View File

@@ -0,0 +1,626 @@
use std::{
cmp::Ordering,
num::NonZeroUsize,
ops::{Add, AddAssign},
};
use crate::{FlagsRepr, Int, Resolve, Type, TypeDef, TypeDefKind};
/// Architecture specific alignment
#[derive(Eq, PartialEq, Clone, Copy)]
pub enum Alignment {
/// This represents 4 byte alignment on 32bit and 8 byte alignment on 64bit architectures
Pointer,
/// This alignment is architecture independent (derived from integer or float types)
Bytes(NonZeroUsize),
}
impl Default for Alignment {
fn default() -> Self {
Alignment::Bytes(NonZeroUsize::new(1).unwrap())
}
}
impl std::fmt::Debug for Alignment {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Alignment::Pointer => f.write_str("ptr"),
Alignment::Bytes(b) => f.write_fmt(format_args!("{}", b.get())),
}
}
}
impl PartialOrd for Alignment {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Alignment {
/// Needed for determining the max alignment of an object from its parts.
/// The ordering is: Bytes(1) < Bytes(2) < Bytes(4) < Pointer < Bytes(8)
/// as a Pointer is either four or eight byte aligned, depending on the architecture
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Alignment::Pointer, Alignment::Pointer) => std::cmp::Ordering::Equal,
(Alignment::Pointer, Alignment::Bytes(b)) => {
if b.get() > 4 {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
}
}
(Alignment::Bytes(b), Alignment::Pointer) => {
if b.get() > 4 {
std::cmp::Ordering::Greater
} else {
std::cmp::Ordering::Less
}
}
(Alignment::Bytes(a), Alignment::Bytes(b)) => a.cmp(b),
}
}
}
impl Alignment {
/// for easy migration this gives you the value for wasm32
pub fn align_wasm32(&self) -> usize {
match self {
Alignment::Pointer => 4,
Alignment::Bytes(bytes) => bytes.get(),
}
}
pub fn align_wasm64(&self) -> usize {
match self {
Alignment::Pointer => 8,
Alignment::Bytes(bytes) => bytes.get(),
}
}
pub fn format(&self, ptrsize_expr: &str) -> String {
match self {
Alignment::Pointer => ptrsize_expr.into(),
Alignment::Bytes(bytes) => format!("{}", bytes.get()),
}
}
}
/// Architecture specific measurement of position,
/// the combined amount in bytes is
/// `bytes + pointers * core::mem::size_of::<*const u8>()`
#[derive(Default, Clone, Copy, Eq, PartialEq)]
pub struct ArchitectureSize {
/// architecture independent bytes
pub bytes: usize,
/// amount of pointer sized units to add
pub pointers: usize,
}
impl Add<ArchitectureSize> for ArchitectureSize {
type Output = ArchitectureSize;
fn add(self, rhs: ArchitectureSize) -> Self::Output {
ArchitectureSize::new(self.bytes + rhs.bytes, self.pointers + rhs.pointers)
}
}
impl AddAssign<ArchitectureSize> for ArchitectureSize {
fn add_assign(&mut self, rhs: ArchitectureSize) {
self.bytes += rhs.bytes;
self.pointers += rhs.pointers;
}
}
impl From<Alignment> for ArchitectureSize {
fn from(align: Alignment) -> Self {
match align {
Alignment::Bytes(bytes) => ArchitectureSize::new(bytes.get(), 0),
Alignment::Pointer => ArchitectureSize::new(0, 1),
}
}
}
impl std::fmt::Debug for ArchitectureSize {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.format("ptrsz"))
}
}
impl ArchitectureSize {
pub fn new(bytes: usize, pointers: usize) -> Self {
Self { bytes, pointers }
}
pub fn max<B: std::borrow::Borrow<Self>>(&self, other: B) -> Self {
let other = other.borrow();
let self32 = self.size_wasm32();
let self64 = self.size_wasm64();
let other32 = other.size_wasm32();
let other64 = other.size_wasm64();
if self32 >= other32 && self64 >= other64 {
*self
} else if self32 <= other32 && self64 <= other64 {
*other
} else {
// we can assume a combination of bytes and pointers, so align to at least pointer size
let new32 = align_to(self32.max(other32), 4);
let new64 = align_to(self64.max(other64), 8);
ArchitectureSize::new(new32 + new32 - new64, (new64 - new32) / 4)
}
}
pub fn add_bytes(&self, b: usize) -> Self {
Self::new(self.bytes + b, self.pointers)
}
/// The effective offset/size is
/// `constant_bytes() + core::mem::size_of::<*const u8>() * pointers_to_add()`
pub fn constant_bytes(&self) -> usize {
self.bytes
}
pub fn pointers_to_add(&self) -> usize {
self.pointers
}
/// Shortcut for compatibility with previous versions
pub fn size_wasm32(&self) -> usize {
self.bytes + self.pointers * 4
}
pub fn size_wasm64(&self) -> usize {
self.bytes + self.pointers * 8
}
/// prefer this over >0
pub fn is_empty(&self) -> bool {
self.bytes == 0 && self.pointers == 0
}
// create a suitable expression in bytes from a pointer size argument
pub fn format(&self, ptrsize_expr: &str) -> String {
self.format_term(ptrsize_expr, false)
}
// create a suitable expression in bytes from a pointer size argument,
// extended API with optional brackets around the sum
pub fn format_term(&self, ptrsize_expr: &str, suppress_brackets: bool) -> String {
if self.pointers != 0 {
if self.bytes > 0 {
// both
if suppress_brackets {
format!(
"{}+{}*{ptrsize_expr}",
self.constant_bytes(),
self.pointers_to_add()
)
} else {
format!(
"({}+{}*{ptrsize_expr})",
self.constant_bytes(),
self.pointers_to_add()
)
}
} else if self.pointers == 1 {
// one pointer
ptrsize_expr.into()
} else {
// only pointer
if suppress_brackets {
format!("{}*{ptrsize_expr}", self.pointers_to_add())
} else {
format!("({}*{ptrsize_expr})", self.pointers_to_add())
}
}
} else {
// only bytes
format!("{}", self.constant_bytes())
}
}
}
/// Information per structure element
#[derive(Default)]
pub struct ElementInfo {
pub size: ArchitectureSize,
pub align: Alignment,
}
impl From<Alignment> for ElementInfo {
fn from(align: Alignment) -> Self {
ElementInfo {
size: align.into(),
align,
}
}
}
impl ElementInfo {
fn new(size: ArchitectureSize, align: Alignment) -> Self {
Self { size, align }
}
}
/// Collect size and alignment for sub-elements of a structure
#[derive(Default)]
pub struct SizeAlign {
map: Vec<ElementInfo>,
}
impl SizeAlign {
pub fn fill(&mut self, resolve: &Resolve) {
self.map = Vec::new();
for (_, ty) in resolve.types.iter() {
let pair = self.calculate(ty);
self.map.push(pair);
}
}
fn calculate(&self, ty: &TypeDef) -> ElementInfo {
match &ty.kind {
TypeDefKind::Type(t) => ElementInfo::new(self.size(t), self.align(t)),
TypeDefKind::FixedSizeList(t, size) => {
let field_align = self.align(t);
let field_size = self.size(t);
ElementInfo::new(
ArchitectureSize::new(
field_size.bytes.checked_mul(*size as usize).unwrap(),
field_size.pointers.checked_mul(*size as usize).unwrap(),
),
field_align,
)
}
TypeDefKind::List(_) => {
ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer)
}
TypeDefKind::Map(_, _) => {
ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer)
}
TypeDefKind::Record(r) => self.record(r.fields.iter().map(|f| &f.ty)),
TypeDefKind::Tuple(t) => self.record(t.types.iter()),
TypeDefKind::Flags(f) => match f.repr() {
FlagsRepr::U8 => int_size_align(Int::U8),
FlagsRepr::U16 => int_size_align(Int::U16),
FlagsRepr::U32(n) => ElementInfo::new(
ArchitectureSize::new(n * 4, 0),
Alignment::Bytes(NonZeroUsize::new(4).unwrap()),
),
},
TypeDefKind::Variant(v) => self.variant(v.tag(), v.cases.iter().map(|c| c.ty.as_ref())),
TypeDefKind::Enum(e) => self.variant(e.tag(), []),
TypeDefKind::Option(t) => self.variant(Int::U8, [Some(t)]),
TypeDefKind::Result(r) => self.variant(Int::U8, [r.ok.as_ref(), r.err.as_ref()]),
// A resource is represented as an index.
// A future is represented as an index.
// A stream is represented as an index.
// An error is represented as an index.
TypeDefKind::Handle(_) | TypeDefKind::Future(_) | TypeDefKind::Stream(_) => {
int_size_align(Int::U32)
}
// This shouldn't be used for anything since raw resources aren't part of the ABI -- just handles to
// them.
TypeDefKind::Resource => ElementInfo::new(
ArchitectureSize::new(usize::MAX, 0),
Alignment::Bytes(NonZeroUsize::new(usize::MAX).unwrap()),
),
TypeDefKind::Unknown => unreachable!(),
}
}
pub fn size(&self, ty: &Type) -> ArchitectureSize {
match ty {
Type::Bool | Type::U8 | Type::S8 => ArchitectureSize::new(1, 0),
Type::U16 | Type::S16 => ArchitectureSize::new(2, 0),
Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::ErrorContext => {
ArchitectureSize::new(4, 0)
}
Type::U64 | Type::S64 | Type::F64 => ArchitectureSize::new(8, 0),
Type::String => ArchitectureSize::new(0, 2),
Type::Id(id) => self.map[id.index()].size,
}
}
pub fn align(&self, ty: &Type) -> Alignment {
match ty {
Type::Bool | Type::U8 | Type::S8 => Alignment::Bytes(NonZeroUsize::new(1).unwrap()),
Type::U16 | Type::S16 => Alignment::Bytes(NonZeroUsize::new(2).unwrap()),
Type::U32 | Type::S32 | Type::F32 | Type::Char | Type::ErrorContext => {
Alignment::Bytes(NonZeroUsize::new(4).unwrap())
}
Type::U64 | Type::S64 | Type::F64 => Alignment::Bytes(NonZeroUsize::new(8).unwrap()),
Type::String => Alignment::Pointer,
Type::Id(id) => self.map[id.index()].align,
}
}
pub fn field_offsets<'a>(
&self,
types: impl IntoIterator<Item = &'a Type>,
) -> Vec<(ArchitectureSize, &'a Type)> {
let mut cur = ArchitectureSize::default();
types
.into_iter()
.map(|ty| {
let ret = align_to_arch(cur, self.align(ty));
cur = ret + self.size(ty);
(ret, ty)
})
.collect()
}
pub fn payload_offset<'a>(
&self,
tag: Int,
cases: impl IntoIterator<Item = Option<&'a Type>>,
) -> ArchitectureSize {
let mut max_align = Alignment::default();
for ty in cases {
if let Some(ty) = ty {
max_align = max_align.max(self.align(ty));
}
}
let tag_size = int_size_align(tag).size;
align_to_arch(tag_size, max_align)
}
pub fn record<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo {
let mut size = ArchitectureSize::default();
let mut align = Alignment::default();
for ty in types {
let field_size = self.size(ty);
let field_align = self.align(ty);
size = align_to_arch(size, field_align) + field_size;
align = align.max(field_align);
}
ElementInfo::new(align_to_arch(size, align), align)
}
pub fn params<'a>(&self, types: impl IntoIterator<Item = &'a Type>) -> ElementInfo {
self.record(types.into_iter())
}
fn variant<'a>(
&self,
tag: Int,
types: impl IntoIterator<Item = Option<&'a Type>>,
) -> ElementInfo {
let ElementInfo {
size: discrim_size,
align: discrim_align,
} = int_size_align(tag);
let mut case_size = ArchitectureSize::default();
let mut case_align = Alignment::default();
for ty in types {
if let Some(ty) = ty {
case_size = case_size.max(&self.size(ty));
case_align = case_align.max(self.align(ty));
}
}
let align = discrim_align.max(case_align);
let discrim_aligned = align_to_arch(discrim_size, case_align);
let size_sum = discrim_aligned + case_size;
ElementInfo::new(align_to_arch(size_sum, align), align)
}
}
fn int_size_align(i: Int) -> ElementInfo {
match i {
Int::U8 => Alignment::Bytes(NonZeroUsize::new(1).unwrap()),
Int::U16 => Alignment::Bytes(NonZeroUsize::new(2).unwrap()),
Int::U32 => Alignment::Bytes(NonZeroUsize::new(4).unwrap()),
Int::U64 => Alignment::Bytes(NonZeroUsize::new(8).unwrap()),
}
.into()
}
/// Increase `val` to a multiple of `align`;
/// `align` must be a power of two
pub(crate) fn align_to(val: usize, align: usize) -> usize {
(val + align - 1) & !(align - 1)
}
/// Increase `val` to a multiple of `align`, with special handling for pointers;
/// `align` must be a power of two or `Alignment::Pointer`
pub fn align_to_arch(val: ArchitectureSize, align: Alignment) -> ArchitectureSize {
match align {
Alignment::Pointer => {
let new32 = align_to(val.bytes, 4);
if new32 != align_to(new32, 8) {
ArchitectureSize::new(new32 - 4, val.pointers + 1)
} else {
ArchitectureSize::new(new32, val.pointers)
}
}
Alignment::Bytes(align_bytes) => {
let align_bytes = align_bytes.get();
if align_bytes > 4 && (val.pointers & 1) != 0 {
let new_bytes = align_to(val.bytes, align_bytes);
if (new_bytes - val.bytes) >= 4 {
// up to four extra bytes fit together with a the extra 32 bit pointer
// and the 64 bit pointer is always 8 bytes (so no change in value)
ArchitectureSize::new(new_bytes - 8, val.pointers + 1)
} else {
// there is no room to combine, so the odd pointer aligns to 8 bytes
ArchitectureSize::new(new_bytes + 8, val.pointers - 1)
}
} else {
ArchitectureSize::new(align_to(val.bytes, align_bytes), val.pointers)
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn align() {
// u8 + ptr
assert_eq!(
align_to_arch(ArchitectureSize::new(1, 0), Alignment::Pointer),
ArchitectureSize::new(0, 1)
);
// u8 + u64
assert_eq!(
align_to_arch(
ArchitectureSize::new(1, 0),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(8, 0)
);
// u8 + u32
assert_eq!(
align_to_arch(
ArchitectureSize::new(1, 0),
Alignment::Bytes(NonZeroUsize::new(4).unwrap())
),
ArchitectureSize::new(4, 0)
);
// ptr + u64
assert_eq!(
align_to_arch(
ArchitectureSize::new(0, 1),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(8, 0)
);
// u32 + ptr
assert_eq!(
align_to_arch(ArchitectureSize::new(4, 0), Alignment::Pointer),
ArchitectureSize::new(0, 1)
);
// u32, ptr + u64
assert_eq!(
align_to_arch(
ArchitectureSize::new(0, 2),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(0, 2)
);
// ptr, u8 + u64
assert_eq!(
align_to_arch(
ArchitectureSize::new(1, 1),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(0, 2)
);
// ptr, u8 + ptr
assert_eq!(
align_to_arch(ArchitectureSize::new(1, 1), Alignment::Pointer),
ArchitectureSize::new(0, 2)
);
// ptr, ptr, u8 + u64
assert_eq!(
align_to_arch(
ArchitectureSize::new(1, 2),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(8, 2)
);
assert_eq!(
align_to_arch(
ArchitectureSize::new(30, 3),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(40, 2)
);
assert_eq!(
ArchitectureSize::new(12, 0).max(&ArchitectureSize::new(0, 2)),
ArchitectureSize::new(8, 1)
);
assert_eq!(
ArchitectureSize::new(10, 0).max(&ArchitectureSize::new(0, 2)),
ArchitectureSize::new(8, 1)
);
assert_eq!(
align_to_arch(
ArchitectureSize::new(2, 0),
Alignment::Bytes(NonZeroUsize::new(8).unwrap())
),
ArchitectureSize::new(8, 0)
);
assert_eq!(
align_to_arch(ArchitectureSize::new(2, 0), Alignment::Pointer),
ArchitectureSize::new(0, 1)
);
}
#[test]
fn resource_size() {
// keep it identical to the old behavior
let obj = SizeAlign::default();
let elem = obj.calculate(&TypeDef {
name: None,
kind: TypeDefKind::Resource,
owner: crate::TypeOwner::None,
docs: Default::default(),
stability: Default::default(),
});
assert_eq!(elem.size, ArchitectureSize::new(usize::MAX, 0));
assert_eq!(
elem.align,
Alignment::Bytes(NonZeroUsize::new(usize::MAX).unwrap())
);
}
#[test]
fn result_ptr_10() {
let mut obj = SizeAlign::default();
let mut resolve = Resolve::default();
let tuple = crate::Tuple {
types: vec![Type::U16, Type::U16, Type::U16, Type::U16, Type::U16],
};
let id = resolve.types.alloc(TypeDef {
name: None,
kind: TypeDefKind::Tuple(tuple),
owner: crate::TypeOwner::None,
docs: Default::default(),
stability: Default::default(),
});
obj.fill(&resolve);
let my_result = crate::Result_ {
ok: Some(Type::String),
err: Some(Type::Id(id)),
};
let elem = obj.calculate(&TypeDef {
name: None,
kind: TypeDefKind::Result(my_result),
owner: crate::TypeOwner::None,
docs: Default::default(),
stability: Default::default(),
});
assert_eq!(elem.size, ArchitectureSize::new(8, 2));
assert_eq!(elem.align, Alignment::Pointer);
}
#[test]
fn result_ptr_64bit() {
let obj = SizeAlign::default();
let my_record = crate::Record {
fields: vec![
crate::Field {
name: String::new(),
ty: Type::String,
docs: Default::default(),
},
crate::Field {
name: String::new(),
ty: Type::U64,
docs: Default::default(),
},
],
};
let elem = obj.calculate(&TypeDef {
name: None,
kind: TypeDefKind::Record(my_record),
owner: crate::TypeOwner::None,
docs: Default::default(),
stability: Default::default(),
});
assert_eq!(elem.size, ArchitectureSize::new(8, 2));
assert_eq!(elem.align, Alignment::Bytes(NonZeroUsize::new(8).unwrap()));
}
}

View File

@@ -0,0 +1 @@
{"name":"wit-parser","vers":"0.244.0","deps":[{"name":"anyhow","req":"^1.0.58","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"id-arena","req":"^2","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"indexmap","req":"^2.7.0","features":["std"],"optional":false,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"log","req":"^0.4.17","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"semver","req":"^1.0.0","features":[],"optional":false,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde","req":"^1.0.166","features":["alloc"],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde_derive","req":"^1.0.166","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde_json","req":"^1","features":[],"optional":true,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"unicode-xid","req":"^0.2.2","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"wasmparser","req":"^0.244.0","features":["simd","std","validate","component-model","features"],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"wat","req":"^1.244.0","features":["component-model"],"optional":true,"default_features":false,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"env_logger","req":"^0.11","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"libtest-mimic","req":"^0.8.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"pretty_assertions","req":"^1.3.0","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"serde_json","req":"^1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{"decoding":["dep:wasmparser"],"default":["serde","decoding"],"serde":["dep:serde","dep:serde_derive","indexmap/serde","serde_json"],"wat":["decoding","dep:wat"]},"features2":null,"cksum":"dacac8caca98bd42c5c95bcfbc2a527a033f6effccab34899011a9511fbd38de","yanked":null,"links":null,"rust_version":null,"v":2}

Binary file not shown.

2
vendor/wit-parser/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
!*.wasm
!*.wat

153
vendor/wit-parser/tests/all.rs vendored Normal file
View File

@@ -0,0 +1,153 @@
//! You can run this test suite with:
//!
//! cargo test --test all
//!
//! An argument can be passed as well to filter, based on filename, which test
//! to run
//!
//! cargo test --test all foo.wit
use anyhow::{Context, Result, bail};
use libtest_mimic::{Arguments, Trial};
use pretty_assertions::StrComparison;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::str;
use wit_parser::*;
fn main() {
env_logger::init();
let tests = find_tests();
let mut trials = Vec::new();
for test in tests {
let trial = Trial::test(format!("{test:?}"), move || {
Runner {}
.run(&test)
.context(format!("test {test:?} failed"))
.map_err(|e| format!("{e:?}").into())
});
trials.push(trial);
}
let mut args = Arguments::from_args();
if cfg!(target_family = "wasm") && !cfg!(target_feature = "atomics") {
args.test_threads = Some(1);
}
libtest_mimic::run(&args, trials).exit();
}
/// Recursively finds all tests in a whitelisted set of directories which we
/// then load up and test in parallel.
fn find_tests() -> Vec<PathBuf> {
let mut tests = Vec::new();
find_tests("tests/ui".as_ref(), &mut tests);
find_tests("tests/ui/parse-fail".as_ref(), &mut tests);
tests.sort();
return tests;
fn find_tests(path: &Path, tests: &mut Vec<PathBuf>) {
for f in path.read_dir().unwrap() {
let f = f.unwrap();
let path = f.path();
if path.file_name().unwrap().to_str().unwrap() == "parse-fail" {
continue;
}
if f.file_type().unwrap().is_dir() {
tests.push(path);
continue;
}
match path.extension().and_then(|s| s.to_str()) {
Some("md") | Some("wit") | Some("wat") | Some("wasm") => {}
_ => continue,
}
tests.push(path);
}
}
}
struct Runner {}
impl Runner {
fn run(&mut self, test: &Path) -> Result<()> {
let mut resolve = Resolve::new();
resolve.features.insert("active".to_string());
let result = resolve.push_path(test);
let result = if test.iter().any(|s| s == "parse-fail") {
match result {
Ok(_) => bail!("expected test to not parse but it did"),
Err(mut e) => {
if let Some(err) = e.downcast_mut::<io::Error>() {
*err = io::Error::new(
io::ErrorKind::Other,
"some generic platform-agnostic error message",
);
}
format!("{e:#}")
}
}
} else {
result?;
// format json string to human readable
let json_result = serde_json::to_string_pretty(&resolve)?;
// "foo.wit" => "foo.wit.json"
self.read_or_write_to_file(test, &json_result, "json")?;
return Ok(());
};
// "foo.wit" => "foo.wit.result"
// "foo.wit.md" => "foo.wit.md.result"
self.read_or_write_to_file(test, &result, "result")?;
return Ok(());
}
fn read_or_write_to_file(
&mut self,
test: &Path,
result: &str,
extension: &str,
) -> Result<(), anyhow::Error> {
let result_file = if test.extension() == Some(OsStr::new("md"))
&& test
.file_stem()
.and_then(|path| Path::new(path).extension())
== Some(OsStr::new("wit"))
{
test.with_extension(format!("md.{extension}"))
} else {
test.with_extension(format!("wit.{extension}"))
};
if env::var_os("BLESS").is_some() {
let normalized = normalize(&result, extension);
fs::write(&result_file, normalized)?;
} else {
let expected = fs::read_to_string(&result_file).context(format!(
"failed to read test expectation file {result_file:?}\nthis can be fixed with BLESS=1"
))?;
let expected = normalize(&expected, extension);
let result = normalize(&result, extension);
if expected != result {
bail!(
"failed test: result is not as expected:{}",
StrComparison::new(&expected, &result),
);
}
}
Ok(())
}
}
fn normalize(s: &str, extension: &str) -> String {
let s = s.trim();
match extension {
// .result files have error messages with paths, so normalize Windows \ separators to /
"result" => s.replace("\\", "/").replace("\r\n", "\n"),
// .json files escape strings with \, so leave them alone
_ => s.replace("\r\n", "\n"),
}
}

24
vendor/wit-parser/tests/ui/async.wit vendored Normal file
View File

@@ -0,0 +1,24 @@
package test:%async;
interface x {
x: async func(x: u32) -> u64;
y: func();
resource z {
constructor();
x: async func();
y: func();
static-x: static async func();
static-y: static func();
}
}
world y {
import x: async func();
import y: func();
export x: async func();
export y: func();
}

View File

@@ -0,0 +1,151 @@
{
"worlds": [
{
"name": "y",
"imports": {
"x": {
"function": {
"name": "x",
"kind": "async-freestanding",
"params": []
}
},
"y": {
"function": {
"name": "y",
"kind": "freestanding",
"params": []
}
}
},
"exports": {
"x": {
"function": {
"name": "x",
"kind": "async-freestanding",
"params": []
}
},
"y": {
"function": {
"name": "y",
"kind": "freestanding",
"params": []
}
}
},
"package": 0
}
],
"interfaces": [
{
"name": "x",
"types": {
"z": 0
},
"functions": {
"x": {
"name": "x",
"kind": "async-freestanding",
"params": [
{
"name": "x",
"type": "u32"
}
],
"result": "u64"
},
"y": {
"name": "y",
"kind": "freestanding",
"params": []
},
"[constructor]z": {
"name": "[constructor]z",
"kind": {
"constructor": 0
},
"params": [],
"result": 2
},
"[method]z.x": {
"name": "[method]z.x",
"kind": {
"async-method": 0
},
"params": [
{
"name": "self",
"type": 1
}
]
},
"[method]z.y": {
"name": "[method]z.y",
"kind": {
"method": 0
},
"params": [
{
"name": "self",
"type": 1
}
]
},
"[static]z.static-x": {
"name": "[static]z.static-x",
"kind": {
"async-static": 0
},
"params": []
},
"[static]z.static-y": {
"name": "[static]z.static-y",
"kind": {
"static": 0
},
"params": []
}
},
"package": 0
}
],
"types": [
{
"name": "z",
"kind": "resource",
"owner": {
"interface": 0
}
},
{
"name": null,
"kind": {
"handle": {
"borrow": 0
}
},
"owner": null
},
{
"name": null,
"kind": {
"handle": {
"own": 0
}
},
"owner": null
}
],
"packages": [
{
"name": "test:async",
"interfaces": {
"x": 0
},
"worlds": {
"y": 0
}
}
]
}

25
vendor/wit-parser/tests/ui/comments.wit vendored Normal file
View File

@@ -0,0 +1,25 @@
package foo:comments;
// hello
// world
// why, yes
// this is a comment
/* this too */ /* is a comment */
/* this /* is /* a */ nested */ comment */
interface foo {
type x = u32;
type /* foo */ bar /* baz */ = //
stream < //
//
//
x
>;
}

View File

@@ -0,0 +1,46 @@
{
"worlds": [],
"interfaces": [
{
"name": "foo",
"types": {
"x": 0,
"bar": 1
},
"functions": {},
"docs": {
"contents": " hello\n world\n why, yes\n this is a comment\n* this too */\n* is a comment */\n* this /* is /* a */ nested */ comment */"
},
"package": 0
}
],
"types": [
{
"name": "x",
"kind": {
"type": "u32"
},
"owner": {
"interface": 0
}
},
{
"name": "bar",
"kind": {
"stream": 0
},
"owner": {
"interface": 0
}
}
],
"packages": [
{
"name": "foo:comments",
"interfaces": {
"foo": 0
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,200 @@
{
"worlds": [
{
"name": "bar-a",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 0
},
{
"name": "baz-a",
"imports": {
"interface-2": {
"interface": {
"id": 2
}
},
"interface-3": {
"interface": {
"id": 3
}
}
},
"exports": {},
"package": 1
},
{
"name": "a",
"imports": {
"interface-4": {
"interface": {
"id": 4
}
},
"interface-5": {
"interface": {
"id": 5
}
}
},
"exports": {},
"package": 2
},
{
"name": "b",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 2
},
{
"name": "c",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 2
},
{
"name": "union-world",
"imports": {
"interface-4": {
"interface": {
"id": 4
}
},
"interface-5": {
"interface": {
"id": 5
}
},
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
},
"interface-2": {
"interface": {
"id": 2
}
},
"interface-3": {
"interface": {
"id": 3
}
}
},
"exports": {},
"package": 2
}
],
"interfaces": [
{
"name": "a",
"types": {},
"functions": {},
"package": 0
},
{
"name": "b",
"types": {},
"functions": {},
"package": 0
},
{
"name": "a",
"types": {},
"functions": {},
"package": 1
},
{
"name": "b",
"types": {},
"functions": {},
"package": 1
},
{
"name": "ai",
"types": {},
"functions": {},
"package": 2
},
{
"name": "bi",
"types": {},
"functions": {},
"package": 2
}
],
"types": [],
"packages": [
{
"name": "foo:bar",
"interfaces": {
"a": 0,
"b": 1
},
"worlds": {
"bar-a": 0
}
},
{
"name": "foo:baz",
"interfaces": {
"a": 2,
"b": 3
},
"worlds": {
"baz-a": 1
}
},
{
"name": "foo:root",
"interfaces": {
"ai": 4,
"bi": 5
},
"worlds": {
"a": 2,
"b": 3,
"c": 4,
"union-world": 5
}
}
]
}

View File

@@ -0,0 +1,9 @@
package foo:bar;
interface a {}
interface b {}
world bar-a {
import a;
import b;
}

View File

@@ -0,0 +1,9 @@
package foo:baz;
interface a {}
interface b {}
world baz-a {
import a;
import b;
}

View File

@@ -0,0 +1,26 @@
package foo:root;
interface ai {}
interface bi {}
world a {
import ai;
import bi;
}
world b {
include foo:bar/bar-a;
}
world c {
include b;
include foo:bar/bar-a;
}
world union-world {
include a;
include b;
include c;
include foo:bar/bar-a;
include foo:baz/baz-a;
}

View File

@@ -0,0 +1,67 @@
{
"worlds": [],
"interfaces": [
{
"name": "foo",
"types": {
"r": 0
},
"functions": {},
"package": 0
},
{
"name": "foo",
"types": {
"r": 1,
"t": 2
},
"functions": {},
"package": 1
}
],
"types": [
{
"name": "r",
"kind": "resource",
"owner": {
"interface": 0
}
},
{
"name": "r",
"kind": {
"type": 0
},
"owner": {
"interface": 1
}
},
{
"name": "t",
"kind": {
"handle": {
"own": 1
}
},
"owner": {
"interface": 1
}
}
],
"packages": [
{
"name": "some:dep",
"interfaces": {
"foo": 0
},
"worlds": {}
},
{
"name": "foo:bar",
"interfaces": {
"foo": 1
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,5 @@
package some:dep;
interface foo {
resource r;
}

View File

@@ -0,0 +1,7 @@
package foo:bar;
interface foo {
use some:dep/foo.{r};
type t = own<r>;
}

View File

@@ -0,0 +1,59 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 2
}
],
"interfaces": [
{
"name": "types",
"types": {},
"functions": {},
"package": 0
},
{
"name": "types",
"types": {},
"functions": {},
"package": 1
}
],
"types": [],
"packages": [
{
"name": "foo:dep1",
"interfaces": {
"types": 0
},
"worlds": {}
},
{
"name": "foo:dep2",
"interfaces": {
"types": 1
},
"worlds": {}
},
{
"name": "foo:foo",
"interfaces": {},
"worlds": {
"foo": 0
}
}
]
}

View File

@@ -0,0 +1,2 @@
package foo:dep1;
interface types {}

View File

@@ -0,0 +1,2 @@
package foo:dep2;
interface types {}

View File

@@ -0,0 +1,6 @@
package foo:foo;
world foo {
import foo:dep1/types;
import foo:dep2/types;
}

View File

@@ -0,0 +1,115 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
},
"foo": {
"interface": {
"id": 2
}
},
"interface-1": {
"interface": {
"id": 1
}
},
"bar": {
"interface": {
"id": 3
}
}
},
"exports": {},
"package": 0
}
],
"interfaces": [
{
"name": "shared1",
"types": {
"the-type": 0
},
"functions": {},
"package": 0
},
{
"name": "shared2",
"types": {
"the-type": 1
},
"functions": {},
"package": 0
},
{
"name": null,
"types": {
"the-type": 2
},
"functions": {},
"package": 0
},
{
"name": null,
"types": {
"the-type": 3
},
"functions": {},
"package": 0
}
],
"types": [
{
"name": "the-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 0
}
},
{
"name": "the-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 1
}
},
{
"name": "the-type",
"kind": {
"type": 0
},
"owner": {
"interface": 2
}
},
{
"name": "the-type",
"kind": {
"type": 1
},
"owner": {
"interface": 3
}
}
],
"packages": [
{
"name": "foo:diamond",
"interfaces": {
"shared1": 0,
"shared2": 1
},
"worlds": {
"foo": 0
}
}
]
}

View File

@@ -0,0 +1,3 @@
interface shared1 {
type the-type = u32;
}

View File

@@ -0,0 +1,3 @@
interface shared2 {
type the-type = u32;
}

View File

@@ -0,0 +1,13 @@
package foo:diamond;
world foo {
import foo: interface {
use shared1.{the-type};
}
import bar: interface {
use shared2.{the-type};
}
import shared1;
import shared2;
}

1
vendor/wit-parser/tests/ui/empty.wit vendored Normal file
View File

@@ -0,0 +1 @@
package foo:empty;

View File

@@ -0,0 +1,12 @@
{
"worlds": [],
"interfaces": [],
"types": [],
"packages": [
{
"name": "foo:empty",
"interfaces": {},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,7 @@
package foo:error-contexts;
interface error-contexts {
type t1 = error-context;
foo: func(x: error-context, y: t1) -> result<_, error-context>;
}

View File

@@ -0,0 +1,59 @@
{
"worlds": [],
"interfaces": [
{
"name": "error-contexts",
"types": {
"t1": 0
},
"functions": {
"foo": {
"name": "foo",
"kind": "freestanding",
"params": [
{
"name": "x",
"type": "error-context"
},
{
"name": "y",
"type": 0
}
],
"result": 1
}
},
"package": 0
}
],
"types": [
{
"name": "t1",
"kind": {
"type": "error-context"
},
"owner": {
"interface": 0
}
},
{
"name": null,
"kind": {
"result": {
"ok": null,
"err": "error-context"
}
},
"owner": null
}
],
"packages": [
{
"name": "foo:error-contexts",
"interfaces": {
"error-contexts": 0
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,118 @@
package a:b;
@unstable(feature = not-active)
interface gated {
}
@unstable(feature = active)
interface ungated {
@unstable(feature = not-active)
gated: func();
@unstable(feature = active)
ungated: func();
}
@unstable(feature = active)
interface ungated2 {
@unstable(feature = not-active)
type gated = u32;
@unstable(feature = not-active)
type gated2 = gated;
@unstable(feature = not-active)
type gated-with-anonymous-type = option<option<gated>>;
@unstable(feature = active)
type ungated = u32;
@unstable(feature = active)
type ungated2 = ungated;
}
@unstable(feature = inactive)
interface gated-use-target {
@unstable(feature = inactive)
type t = u32;
}
@unstable(feature = inactive)
interface gated-use {
@unstable(feature = inactive)
use gated-use-target.{t};
}
@unstable(feature = active)
interface ungated-use-target {
@unstable(feature = active)
type t = u32;
}
@unstable(feature = active)
interface ungated-use {
@unstable(feature = active)
use ungated-use-target.{t};
}
@unstable(feature = inactive)
interface gated-for-world {}
@unstable(feature = inactive)
world gated-world {
@unstable(feature = inactive)
import gated-for-world;
@unstable(feature = inactive)
export gated-for-world;
}
@unstable(feature = active)
interface ungated-for-world {}
@unstable(feature = active)
world ungated-world {
@unstable(feature = active)
import ungated-for-world;
@unstable(feature = active)
export ungated-for-world;
}
world mixed-world {
@unstable(feature = inactive)
import gated-for-world;
@unstable(feature = inactive)
export gated-for-world;
@unstable(feature = inactive)
include gated-world;
@unstable(feature = active)
import ungated-for-world;
@unstable(feature = active)
export ungated-for-world;
@unstable(feature = inactive)
include ungated-world;
}
interface with-resources {
@unstable(feature = inactive)
resource gated {
@unstable(feature = inactive)
constructor();
@unstable(feature = inactive)
x: static func();
@unstable(feature = inactive)
y: func();
}
@unstable(feature = active)
resource ungated {
@unstable(feature = active)
constructor();
@unstable(feature = active)
x: static func();
@unstable(feature = active)
y: func();
}
}

View File

@@ -0,0 +1,301 @@
{
"worlds": [
{
"name": "ungated-world",
"imports": {
"interface-4": {
"interface": {
"id": 4,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"exports": {
"interface-4": {
"interface": {
"id": 4,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"package": 0,
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "mixed-world",
"imports": {
"interface-4": {
"interface": {
"id": 4,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"exports": {
"interface-4": {
"interface": {
"id": 4,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"package": 0
}
],
"interfaces": [
{
"name": "ungated",
"types": {},
"functions": {
"ungated": {
"name": "ungated",
"kind": "freestanding",
"params": [],
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "ungated2",
"types": {
"ungated": 0,
"ungated2": 1
},
"functions": {},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "ungated-use-target",
"types": {
"t": 2
},
"functions": {},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "ungated-use",
"types": {
"t": 3
},
"functions": {},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "ungated-for-world",
"types": {},
"functions": {},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "with-resources",
"types": {
"ungated": 4
},
"functions": {
"[constructor]ungated": {
"name": "[constructor]ungated",
"kind": {
"constructor": 4
},
"params": [],
"result": 6,
"stability": {
"unstable": {
"feature": "active"
}
}
},
"[static]ungated.x": {
"name": "[static]ungated.x",
"kind": {
"static": 4
},
"params": [],
"stability": {
"unstable": {
"feature": "active"
}
}
},
"[method]ungated.y": {
"name": "[method]ungated.y",
"kind": {
"method": 4
},
"params": [
{
"name": "self",
"type": 5
}
],
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"package": 0
}
],
"types": [
{
"name": "ungated",
"kind": {
"type": "u32"
},
"owner": {
"interface": 1
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "ungated2",
"kind": {
"type": 0
},
"owner": {
"interface": 1
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "t",
"kind": {
"type": "u32"
},
"owner": {
"interface": 2
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "t",
"kind": {
"type": 2
},
"owner": {
"interface": 3
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "ungated",
"kind": "resource",
"owner": {
"interface": 5
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": null,
"kind": {
"handle": {
"borrow": 4
}
},
"owner": null,
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": null,
"kind": {
"handle": {
"own": 4
}
},
"owner": null
}
],
"packages": [
{
"name": "a:b",
"interfaces": {
"ungated": 0,
"ungated2": 1,
"ungated-use-target": 2,
"ungated-use": 3,
"ungated-for-world": 4,
"with-resources": 5
},
"worlds": {
"ungated-world": 0,
"mixed-world": 1
}
}
]
}

View File

@@ -0,0 +1,13 @@
package a:b;
interface foo {
variant bar {
x,
y
}
@unstable(feature = my-feature)
my-unstable: func(p: bar) -> result<_, bar>;
my-stable: func(p: bar) -> result<_, bar>;
}

View File

@@ -0,0 +1,66 @@
{
"worlds": [],
"interfaces": [
{
"name": "foo",
"types": {
"bar": 0
},
"functions": {
"my-stable": {
"name": "my-stable",
"kind": "freestanding",
"params": [
{
"name": "p",
"type": 0
}
],
"result": 1
}
},
"package": 0
}
],
"types": [
{
"name": "bar",
"kind": {
"variant": {
"cases": [
{
"name": "x",
"type": null
},
{
"name": "y",
"type": null
}
]
}
},
"owner": {
"interface": 0
}
},
{
"name": null,
"kind": {
"result": {
"ok": null,
"err": 0
}
},
"owner": null
}
],
"packages": [
{
"name": "a:b",
"interfaces": {
"foo": 0
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,410 @@
{
"worlds": [
{
"name": "wasi",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {},
"package": 4
},
{
"name": "my-world",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 6
},
{
"name": "my-world2",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {
"interface-9": {
"interface": {
"id": 9
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 6
},
{
"name": "bars-world",
"imports": {
"interface-6": {
"interface": {
"id": 6
}
},
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 6
},
{
"name": "unionw-world",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {
"interface-1": {
"interface": {
"id": 1
}
},
"interface-9": {
"interface": {
"id": 9
}
}
},
"package": 6
}
],
"interfaces": [
{
"name": "other-interface",
"types": {},
"functions": {},
"package": 0
},
{
"name": "saas",
"types": {},
"functions": {},
"package": 1
},
{
"name": "i",
"types": {},
"functions": {},
"package": 2
},
{
"name": "the-default",
"types": {
"some-type": 0
},
"functions": {},
"package": 3
},
{
"name": "clocks",
"types": {
"timestamp": 1
},
"functions": {},
"package": 4
},
{
"name": "filesystem",
"types": {
"stat": 2
},
"functions": {},
"package": 4
},
{
"name": "the-default",
"types": {
"from-default": 3
},
"functions": {},
"package": 5
},
{
"name": "some-interface",
"types": {
"another-type": 4
},
"functions": {},
"package": 5
},
{
"name": "another-interface",
"types": {
"yet-another-type": 5
},
"functions": {},
"package": 5
},
{
"name": "foo",
"types": {
"timestamp": 6,
"stat": 7
},
"functions": {},
"package": 6
},
{
"name": "bar",
"types": {
"from-default": 8,
"another-type": 9,
"yet-another-type": 10
},
"functions": {},
"package": 6
},
{
"name": "use1",
"types": {
"some-type": 11
},
"functions": {},
"package": 6
},
{
"name": "use2",
"types": {
"some-type": 12
},
"functions": {},
"package": 6
}
],
"types": [
{
"name": "some-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 3
}
},
{
"name": "timestamp",
"kind": {
"type": "u64"
},
"owner": {
"interface": 4
}
},
{
"name": "stat",
"kind": {
"record": {
"fields": [
{
"name": "ino",
"type": "u64"
}
]
}
},
"owner": {
"interface": 5
}
},
{
"name": "from-default",
"kind": {
"type": "string"
},
"owner": {
"interface": 6
}
},
{
"name": "another-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 7
}
},
{
"name": "yet-another-type",
"kind": {
"type": "u8"
},
"owner": {
"interface": 8
}
},
{
"name": "timestamp",
"kind": {
"type": 1
},
"owner": {
"interface": 9
}
},
{
"name": "stat",
"kind": {
"type": 2
},
"owner": {
"interface": 9
}
},
{
"name": "from-default",
"kind": {
"type": 3
},
"owner": {
"interface": 10
}
},
{
"name": "another-type",
"kind": {
"type": 4
},
"owner": {
"interface": 10
}
},
{
"name": "yet-another-type",
"kind": {
"type": 5
},
"owner": {
"interface": 10
}
},
{
"name": "some-type",
"kind": {
"type": 0
},
"owner": {
"interface": 11
}
},
{
"name": "some-type",
"kind": {
"type": 0
},
"owner": {
"interface": 12
}
}
],
"packages": [
{
"name": "foo:another-pkg",
"interfaces": {
"other-interface": 0
},
"worlds": {}
},
{
"name": "foo:corp",
"interfaces": {
"saas": 1
},
"worlds": {}
},
{
"name": "foo:different-pkg",
"interfaces": {
"i": 2
},
"worlds": {}
},
{
"name": "foo:foreign-pkg",
"interfaces": {
"the-default": 3
},
"worlds": {}
},
{
"name": "foo:wasi",
"interfaces": {
"clocks": 4,
"filesystem": 5
},
"worlds": {
"wasi": 0
}
},
{
"name": "foo:some-pkg",
"interfaces": {
"the-default": 6,
"some-interface": 7,
"another-interface": 8
},
"worlds": {}
},
{
"name": "foo:root",
"interfaces": {
"foo": 9,
"bar": 10,
"use1": 11,
"use2": 12
},
"worlds": {
"my-world": 1,
"my-world2": 2,
"bars-world": 3,
"unionw-world": 4
}
}
]
}

View File

@@ -0,0 +1,3 @@
package foo:another-pkg;
interface other-interface {}

View File

@@ -0,0 +1,4 @@
package foo:corp;
interface saas {
}

View File

@@ -0,0 +1,2 @@
package foo:different-pkg;
interface i {}

View File

@@ -0,0 +1,5 @@
package foo:foreign-pkg;
interface the-default {
type some-type = u32;
}

View File

@@ -0,0 +1,13 @@
package foo:some-pkg;
interface the-default {
type from-default = string;
}
interface some-interface {
type another-type = u32;
}
interface another-interface {
type yet-another-type = u8;
}

View File

@@ -0,0 +1,5 @@
package foo:wasi;
interface clocks {
type timestamp = u64;
}

View File

@@ -0,0 +1,7 @@
package foo:wasi;
interface filesystem {
record stat {
ino: u64
}
}

View File

@@ -0,0 +1,6 @@
package foo:wasi;
world wasi {
import filesystem;
import clocks;
}

View File

@@ -0,0 +1,50 @@
package foo:root;
interface foo {
use foo:wasi/clocks.{timestamp};
use foo:wasi/filesystem.{stat};
}
world my-world {
import foo:wasi/filesystem;
import foo:wasi/clocks;
export foo:corp/saas;
}
use foo:wasi/filesystem as filesystem;
use foo:wasi/clocks as clocks;
world my-world2 {
import filesystem;
import clocks;
export foo;
export foo:corp/saas;
}
interface bar {
use filesystem.{};
use foo:some-pkg/the-default.{from-default};
use foo:some-pkg/some-interface.{another-type};
use foo:some-pkg/some-interface.{};
use foo:some-pkg/another-interface.{yet-another-type};
use foo:different-pkg/i.{};
}
world bars-world {
import foo:some-pkg/the-default;
import foo:another-pkg/other-interface;
}
interface use1 {
use foo:foreign-pkg/the-default.{some-type};
}
interface use2 {
use foo:foreign-pkg/the-default.{some-type};
}
world unionw-world {
include my-world;
include my-world2;
include foo:wasi/wasi;
}

View File

@@ -0,0 +1,362 @@
{
"worlds": [
{
"name": "my-world",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 6
},
{
"name": "my-world2",
"imports": {
"interface-5": {
"interface": {
"id": 5
}
},
"interface-4": {
"interface": {
"id": 4
}
}
},
"exports": {
"interface-9": {
"interface": {
"id": 9
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 6
},
{
"name": "bars-world",
"imports": {
"interface-6": {
"interface": {
"id": 6
}
},
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 6
}
],
"interfaces": [
{
"name": "other-interface",
"types": {},
"functions": {},
"package": 0
},
{
"name": "saas",
"types": {},
"functions": {},
"package": 1
},
{
"name": "i",
"types": {},
"functions": {},
"package": 2
},
{
"name": "the-default",
"types": {
"some-type": 0
},
"functions": {},
"package": 3
},
{
"name": "clocks",
"types": {
"timestamp": 1
},
"functions": {},
"package": 4
},
{
"name": "filesystem",
"types": {
"stat": 2
},
"functions": {},
"package": 4
},
{
"name": "the-default",
"types": {
"from-default": 3
},
"functions": {},
"package": 5
},
{
"name": "some-interface",
"types": {
"another-type": 4
},
"functions": {},
"package": 5
},
{
"name": "another-interface",
"types": {
"yet-another-type": 5
},
"functions": {},
"package": 5
},
{
"name": "foo",
"types": {
"timestamp": 6,
"stat": 7
},
"functions": {},
"package": 6
},
{
"name": "bar",
"types": {
"from-default": 8,
"another-type": 9,
"yet-another-type": 10
},
"functions": {},
"package": 6
},
{
"name": "use1",
"types": {
"some-type": 11
},
"functions": {},
"package": 6
},
{
"name": "use2",
"types": {
"some-type": 12
},
"functions": {},
"package": 6
}
],
"types": [
{
"name": "some-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 3
}
},
{
"name": "timestamp",
"kind": {
"type": "u64"
},
"owner": {
"interface": 4
}
},
{
"name": "stat",
"kind": {
"record": {
"fields": [
{
"name": "ino",
"type": "u64"
}
]
}
},
"owner": {
"interface": 5
}
},
{
"name": "from-default",
"kind": {
"type": "string"
},
"owner": {
"interface": 6
}
},
{
"name": "another-type",
"kind": {
"type": "u32"
},
"owner": {
"interface": 7
}
},
{
"name": "yet-another-type",
"kind": {
"type": "u8"
},
"owner": {
"interface": 8
}
},
{
"name": "timestamp",
"kind": {
"type": 1
},
"owner": {
"interface": 9
}
},
{
"name": "stat",
"kind": {
"type": 2
},
"owner": {
"interface": 9
}
},
{
"name": "from-default",
"kind": {
"type": 3
},
"owner": {
"interface": 10
}
},
{
"name": "another-type",
"kind": {
"type": 4
},
"owner": {
"interface": 10
}
},
{
"name": "yet-another-type",
"kind": {
"type": 5
},
"owner": {
"interface": 10
}
},
{
"name": "some-type",
"kind": {
"type": 0
},
"owner": {
"interface": 11
}
},
{
"name": "some-type",
"kind": {
"type": 0
},
"owner": {
"interface": 12
}
}
],
"packages": [
{
"name": "foo:another-pkg",
"interfaces": {
"other-interface": 0
},
"worlds": {}
},
{
"name": "foo:corp",
"interfaces": {
"saas": 1
},
"worlds": {}
},
{
"name": "foo:different-pkg",
"interfaces": {
"i": 2
},
"worlds": {}
},
{
"name": "foo:foreign-pkg",
"interfaces": {
"the-default": 3
},
"worlds": {}
},
{
"name": "foo:wasi",
"interfaces": {
"clocks": 4,
"filesystem": 5
},
"worlds": {}
},
{
"name": "foo:some-pkg",
"interfaces": {
"the-default": 6,
"some-interface": 7,
"another-interface": 8
},
"worlds": {}
},
{
"name": "foo:root",
"interfaces": {
"foo": 9,
"bar": 10,
"use1": 11,
"use2": 12
},
"worlds": {
"my-world": 0,
"my-world2": 1,
"bars-world": 2
}
}
]
}

View File

@@ -0,0 +1,3 @@
package foo:another-pkg;
interface other-interface {}

View File

@@ -0,0 +1,4 @@
package foo:corp;
interface saas {
}

View File

@@ -0,0 +1,2 @@
package foo:different-pkg;
interface i {}

View File

@@ -0,0 +1,5 @@
package foo:foreign-pkg;
interface the-default {
type some-type = u32;
}

View File

@@ -0,0 +1,13 @@
package foo:some-pkg;
interface the-default {
type from-default = string;
}
interface some-interface {
type another-type = u32;
}
interface another-interface {
type yet-another-type = u8;
}

View File

@@ -0,0 +1,5 @@
package foo:wasi;
interface clocks {
type timestamp = u64;
}

View File

@@ -0,0 +1,7 @@
package foo:wasi;
interface filesystem {
record stat {
ino: u64
}
}

View File

@@ -0,0 +1,44 @@
package foo:root;
interface foo {
use foo:wasi/clocks.{timestamp};
use foo:wasi/filesystem.{stat};
}
world my-world {
import foo:wasi/filesystem;
import foo:wasi/clocks;
export foo:corp/saas;
}
use foo:wasi/filesystem as filesystem;
use foo:wasi/clocks as clocks;
world my-world2 {
import filesystem;
import clocks;
export foo;
export foo:corp/saas;
}
interface bar {
use filesystem.{};
use foo:some-pkg/the-default.{from-default};
use foo:some-pkg/some-interface.{another-type};
use foo:some-pkg/some-interface.{};
use foo:some-pkg/another-interface.{yet-another-type};
use foo:different-pkg/i.{};
}
world bars-world {
import foo:some-pkg/the-default;
import foo:another-pkg/other-interface;
}
interface use1 {
use foo:foreign-pkg/the-default.{some-type};
}
interface use2 {
use foo:foreign-pkg/the-default.{some-type};
}

View File

@@ -0,0 +1,17 @@
package a:b1;
world the-world {
include a:b2/the-world;
}
package a:b2 {
world the-world {
@unstable(feature = disabled)
import a:b3/thing;
}
}
package a:b3 {
@unstable(feature = disabled)
interface thing {}
}

View File

@@ -0,0 +1,39 @@
{
"worlds": [
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 1
},
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 2
}
],
"interfaces": [],
"types": [],
"packages": [
{
"name": "a:b3",
"interfaces": {},
"worlds": {}
},
{
"name": "a:b2",
"interfaces": {},
"worlds": {
"the-world": 0
}
},
{
"name": "a:b1",
"interfaces": {},
"worlds": {
"the-world": 1
}
}
]
}

View File

@@ -0,0 +1,17 @@
package a:b1;
world the-world {
include a:b2/the-world;
}
package a:b2 {
world the-world {
@unstable(feature = disabled)
import a:b3/another-world;
}
}
package a:b3 {
@unstable(feature = disabled)
world another-world {}
}

View File

@@ -0,0 +1,39 @@
{
"worlds": [
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 1
},
{
"name": "the-world",
"imports": {},
"exports": {},
"package": 2
}
],
"interfaces": [],
"types": [],
"packages": [
{
"name": "a:b3",
"interfaces": {},
"worlds": {}
},
{
"name": "a:b2",
"interfaces": {},
"worlds": {
"the-world": 0
}
},
{
"name": "a:b1",
"interfaces": {},
"worlds": {
"the-world": 1
}
}
]
}

View File

@@ -0,0 +1,11 @@
package foo:functions;
interface functions {
f1: func();
f2: func(a: u32);
f3: func(a: u32,);
f4: func() -> u32;
f6: func() -> tuple<u32, u32>;
f7: func(a: f32, b: f32) -> tuple<u32, u32>;
f8: func(a: option<u32>) -> result<u32, f32>;
}

View File

@@ -0,0 +1,115 @@
{
"worlds": [],
"interfaces": [
{
"name": "functions",
"types": {},
"functions": {
"f1": {
"name": "f1",
"kind": "freestanding",
"params": []
},
"f2": {
"name": "f2",
"kind": "freestanding",
"params": [
{
"name": "a",
"type": "u32"
}
]
},
"f3": {
"name": "f3",
"kind": "freestanding",
"params": [
{
"name": "a",
"type": "u32"
}
]
},
"f4": {
"name": "f4",
"kind": "freestanding",
"params": [],
"result": "u32"
},
"f6": {
"name": "f6",
"kind": "freestanding",
"params": [],
"result": 0
},
"f7": {
"name": "f7",
"kind": "freestanding",
"params": [
{
"name": "a",
"type": "f32"
},
{
"name": "b",
"type": "f32"
}
],
"result": 0
},
"f8": {
"name": "f8",
"kind": "freestanding",
"params": [
{
"name": "a",
"type": 1
}
],
"result": 2
}
},
"package": 0
}
],
"types": [
{
"name": null,
"kind": {
"tuple": {
"types": [
"u32",
"u32"
]
}
},
"owner": null
},
{
"name": null,
"kind": {
"option": "u32"
},
"owner": null
},
{
"name": null,
"kind": {
"result": {
"ok": "u32",
"err": "f32"
}
},
"owner": null
}
],
"packages": [
{
"name": "foo:functions",
"interfaces": {
"functions": 0
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,67 @@
package wasmtime:test@0.1.0;
interface unknown-stability-interface {
resource unknown-stability-resource {
}
stable-func: func();
}
@unstable(feature = active)
interface unstable-interface {
@unstable(feature = active)
resource unstable-resource {
}
@unstable(feature = active)
unstable-func: func();
}
@since(version = 0.1.0)
interface stable-interface {
@since(version = 0.1.0)
resource stable-resource {
}
@since(version = 0.1.0)
stable-func: func();
}
world unknown-stability {
import unknown-stability-interface;
}
world unstable {
@unstable(feature = active)
import unstable-interface;
}
world stable{
@since(version = 0.1.0)
import stable-interface;
}
world simple-include {
include unstable;
include stable;
include unknown-stability;
}
world unstable-include-in-package
{
include unstable;
}
world dup-include-in-package {
include simple-include;
include unstable-include-in-package;
}
world dup-use-package {
@unstable(feature = active)
use stable-interface.{stable-resource};
include simple-include;
}
world dup-use-package-ordered {
include simple-include;
@unstable(feature = active)
use stable-interface.{stable-resource};
}

View File

@@ -0,0 +1,346 @@
{
"worlds": [
{
"name": "unknown-stability",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 0
},
{
"name": "unstable",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"exports": {},
"package": 0
},
{
"name": "stable",
"imports": {
"interface-2": {
"interface": {
"id": 2,
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
}
},
"exports": {},
"package": 0
},
{
"name": "simple-include",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"interface-2": {
"interface": {
"id": 2,
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
},
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 0
},
{
"name": "unstable-include-in-package",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
}
},
"exports": {},
"package": 0
},
{
"name": "dup-include-in-package",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"interface-2": {
"interface": {
"id": 2,
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
},
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 0
},
{
"name": "dup-use-package",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"interface-2": {
"interface": {
"id": 2,
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
},
"interface-0": {
"interface": {
"id": 0
}
},
"stable-resource": {
"type": 3
}
},
"exports": {},
"package": 0
},
{
"name": "dup-use-package-ordered",
"imports": {
"interface-1": {
"interface": {
"id": 1,
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"interface-2": {
"interface": {
"id": 2,
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
},
"interface-0": {
"interface": {
"id": 0
}
},
"stable-resource": {
"type": 4
}
},
"exports": {},
"package": 0
}
],
"interfaces": [
{
"name": "unknown-stability-interface",
"types": {
"unknown-stability-resource": 0
},
"functions": {
"stable-func": {
"name": "stable-func",
"kind": "freestanding",
"params": []
}
},
"package": 0
},
{
"name": "unstable-interface",
"types": {
"unstable-resource": 1
},
"functions": {
"unstable-func": {
"name": "unstable-func",
"kind": "freestanding",
"params": [],
"stability": {
"unstable": {
"feature": "active"
}
}
}
},
"stability": {
"unstable": {
"feature": "active"
}
},
"package": 0
},
{
"name": "stable-interface",
"types": {
"stable-resource": 2
},
"functions": {
"stable-func": {
"name": "stable-func",
"kind": "freestanding",
"params": [],
"stability": {
"stable": {
"since": "0.1.0"
}
}
}
},
"stability": {
"stable": {
"since": "0.1.0"
}
},
"package": 0
}
],
"types": [
{
"name": "unknown-stability-resource",
"kind": "resource",
"owner": {
"interface": 0
}
},
{
"name": "unstable-resource",
"kind": "resource",
"owner": {
"interface": 1
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "stable-resource",
"kind": "resource",
"owner": {
"interface": 2
},
"stability": {
"stable": {
"since": "0.1.0"
}
}
},
{
"name": "stable-resource",
"kind": {
"type": 2
},
"owner": {
"world": 6
},
"stability": {
"unstable": {
"feature": "active"
}
}
},
{
"name": "stable-resource",
"kind": {
"type": 2
},
"owner": {
"world": 7
},
"stability": {
"unstable": {
"feature": "active"
}
}
}
],
"packages": [
{
"name": "wasmtime:test@0.1.0",
"interfaces": {
"unknown-stability-interface": 0,
"unstable-interface": 1,
"stable-interface": 2
},
"worlds": {
"unknown-stability": 0,
"unstable": 1,
"stable": 2,
"simple-include": 3,
"unstable-include-in-package": 4,
"dup-include-in-package": 5,
"dup-use-package": 6,
"dup-use-package-ordered": 7
}
}
]
}

View File

@@ -0,0 +1,13 @@
package wasmtime:test;
interface types {
@unstable(feature = inactive)
use wasi:dep2/stable@0.2.3.{unstable-resource};
}
package wasi:dep2@0.2.3 {
interface stable {
@unstable(feature = inactive)
resource unstable-resource;
}
}

View File

@@ -0,0 +1,34 @@
{
"worlds": [],
"interfaces": [
{
"name": "stable",
"types": {},
"functions": {},
"package": 0
},
{
"name": "types",
"types": {},
"functions": {},
"package": 1
}
],
"types": [],
"packages": [
{
"name": "wasi:dep2@0.2.3",
"interfaces": {
"stable": 0
},
"worlds": {}
},
{
"name": "wasmtime:test",
"interfaces": {
"types": 1
},
"worlds": {}
}
]
}

View File

@@ -0,0 +1,41 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {},
"package": 1
}
],
"interfaces": [
{
"name": "types",
"types": {},
"functions": {},
"package": 0
}
],
"types": [],
"packages": [
{
"name": "foo:bar",
"interfaces": {
"types": 0
},
"worlds": {}
},
{
"name": "foo:foo",
"interfaces": {},
"worlds": {
"foo": 0
}
}
]
}

View File

@@ -0,0 +1,2 @@
package foo:bar;
interface types {}

View File

@@ -0,0 +1 @@
this file should be ignored by the parser

View File

@@ -0,0 +1,5 @@
package foo:foo;
world foo {
import foo:bar/types;
}

View File

@@ -0,0 +1,5 @@
package foo:foo;
world foo {
import a: func();
export a: func();
}

View File

@@ -0,0 +1,37 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"exports": {
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"package": 0
}
],
"interfaces": [],
"types": [],
"packages": [
{
"name": "foo:foo",
"interfaces": {},
"worlds": {
"foo": 0
}
}
]
}

View File

@@ -0,0 +1,5 @@
package foo:foo;
world foo {
import a: func();
export a: interface {}
}

View File

@@ -0,0 +1,42 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"exports": {
"a": {
"interface": {
"id": 0
}
}
},
"package": 0
}
],
"interfaces": [
{
"name": null,
"types": {},
"functions": {},
"package": 0
}
],
"types": [],
"packages": [
{
"name": "foo:foo",
"interfaces": {},
"worlds": {
"foo": 0
}
}
]
}

View File

@@ -0,0 +1,15 @@
package foo:foo;
interface a {}
interface b {}
world bar {
import a;
export b;
}
world foo {
include bar;
include bar;
include bar;
}

View File

@@ -0,0 +1,68 @@
{
"worlds": [
{
"name": "bar",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 0
},
{
"name": "foo",
"imports": {
"interface-0": {
"interface": {
"id": 0
}
}
},
"exports": {
"interface-1": {
"interface": {
"id": 1
}
}
},
"package": 0
}
],
"interfaces": [
{
"name": "a",
"types": {},
"functions": {},
"package": 0
},
{
"name": "b",
"types": {},
"functions": {},
"package": 0
}
],
"types": [],
"packages": [
{
"name": "foo:foo",
"interfaces": {
"a": 0,
"b": 1
},
"worlds": {
"bar": 0,
"foo": 1
}
}
]
}

View File

@@ -0,0 +1,8 @@
package foo:foo;
world foo { import a: func(); }
world bar { import a: func(); }
world baz {
include foo with { a as b }
include bar;
}

View File

@@ -0,0 +1,66 @@
{
"worlds": [
{
"name": "foo",
"imports": {
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"exports": {},
"package": 0
},
{
"name": "bar",
"imports": {
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"exports": {},
"package": 0
},
{
"name": "baz",
"imports": {
"b": {
"function": {
"name": "b",
"kind": "freestanding",
"params": []
}
},
"a": {
"function": {
"name": "a",
"kind": "freestanding",
"params": []
}
}
},
"exports": {},
"package": 0
}
],
"interfaces": [],
"types": [],
"packages": [
{
"name": "foo:foo",
"interfaces": {},
"worlds": {
"foo": 0,
"bar": 1,
"baz": 2
}
}
]
}

View File

@@ -0,0 +1,95 @@
{
"worlds": [
{
"name": "a",
"imports": {
"interface-2": {
"interface": {
"id": 2
}
},
"interface-3": {
"interface": {
"id": 3
}
},
"interface-0": {
"interface": {
"id": 0
}
},
"interface-1": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 4
}
],
"interfaces": [
{
"name": "d",
"types": {},
"functions": {},
"package": 0
},
{
"name": "e",
"types": {},
"functions": {},
"package": 1
},
{
"name": "b",
"types": {},
"functions": {},
"package": 2
},
{
"name": "c",
"types": {},
"functions": {},
"package": 3
}
],
"types": [],
"packages": [
{
"name": "d:d",
"interfaces": {
"d": 0
},
"worlds": {}
},
{
"name": "e:e",
"interfaces": {
"e": 1
},
"worlds": {}
},
{
"name": "b:b",
"interfaces": {
"b": 2
},
"worlds": {}
},
{
"name": "c:c",
"interfaces": {
"c": 3
},
"worlds": {}
},
{
"name": "a:a",
"interfaces": {},
"worlds": {
"a": 0
}
}
]
}

View File

@@ -0,0 +1,8 @@
package a:a;
world a {
import b:b/b;
import c:c/c;
import d:d/d;
import e:e/e;
}

View File

@@ -0,0 +1,3 @@
package b:b;
interface b {}

View File

@@ -0,0 +1,3 @@
package c:c;
interface c {}

View File

@@ -0,0 +1,6 @@
(component
(type $d (component
(export "d:d/d" (instance))
))
(export "d" (type $d))
)

Binary file not shown.

View File

@@ -0,0 +1,42 @@
{
"worlds": [
{
"name": "name",
"imports": {
"name": {
"interface": {
"id": 1
}
}
},
"exports": {},
"package": 0
}
],
"interfaces": [
{
"name": "x",
"types": {},
"functions": {},
"package": 0
},
{
"name": null,
"types": {},
"functions": {},
"package": 0
}
],
"types": [],
"packages": [
{
"name": "foo:name",
"interfaces": {
"x": 0
},
"worlds": {
"name": 0
}
}
]
}

View File

@@ -0,0 +1,2 @@
interface x {}
use x as name;

Some files were not shown because too many files have changed in this diff Show More