feat: add a histrical wit-bindgen

This commit is contained in:
2023-01-01 00:25:48 +08:00
parent 01e8f5a959
commit aa50d63aec
419 changed files with 45283 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
[package]
name = "wit-bindgen-wasmtime-impl"
version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
edition = "2018"
[lib]
proc-macro = true
doctest = false
test = false
[dependencies]
proc-macro2 = "1.0"
syn = "1.0"
wit-bindgen-gen-core = { path = "../gen-core", version = "0.1" }
wit-bindgen-gen-wasmtime = { path = "../gen-wasmtime", version = "0.1" }
[features]
tracing = []
async = []

View File

@@ -0,0 +1,179 @@
use std::path::{Path, PathBuf};
use proc_macro::TokenStream;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::{token, Token};
use wit_bindgen_gen_core::{wit_parser::Interface, Direction, Files, Generator};
use wit_bindgen_gen_wasmtime::Async;
/// Generate code to support consuming the given interfaces, importaing them
/// from wasm modules.
#[proc_macro]
pub fn import(input: TokenStream) -> TokenStream {
run(input, Direction::Import)
}
/// Generate code to support implementing the given interfaces and exporting
/// them to wasm modules.
#[proc_macro]
pub fn export(input: TokenStream) -> TokenStream {
run(input, Direction::Export)
}
fn run(input: TokenStream, dir: Direction) -> TokenStream {
let input = syn::parse_macro_input!(input as Opts);
let mut gen = input.opts.build();
let mut files = Files::default();
let (imports, exports) = match dir {
Direction::Import => (input.interfaces, vec![]),
Direction::Export => (vec![], input.interfaces),
};
gen.generate_all(&imports, &exports, &mut files);
let (_, contents) = files.iter().next().unwrap();
let contents = std::str::from_utf8(contents).unwrap();
let mut contents = contents.parse::<TokenStream>().unwrap();
// Include a dummy `include_str!` for any files we read so rustc knows that
// we depend on the contents of those files.
let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap();
for file in input.files.iter() {
contents.extend(
format!(
"const _: &str = include_str!(r#\"{}\"#);\n",
Path::new(&cwd).join(file).display()
)
.parse::<TokenStream>()
.unwrap(),
);
}
return contents;
}
struct Opts {
opts: wit_bindgen_gen_wasmtime::Opts,
interfaces: Vec<Interface>,
files: Vec<String>,
}
mod kw {
syn::custom_keyword!(src);
syn::custom_keyword!(paths);
syn::custom_keyword!(custom_error);
}
impl Parse for Opts {
fn parse(input: ParseStream<'_>) -> Result<Opts> {
let call_site = proc_macro2::Span::call_site();
let mut opts = wit_bindgen_gen_wasmtime::Opts::default();
let mut files = Vec::new();
opts.tracing = cfg!(feature = "tracing");
let interfaces = if input.peek(token::Brace) {
let content;
syn::braced!(content in input);
let mut interfaces = Vec::new();
let fields = Punctuated::<ConfigField, Token![,]>::parse_terminated(&content)?;
for field in fields.into_pairs() {
match field.into_value() {
ConfigField::Interfaces(v) => interfaces = v,
ConfigField::Async(v) => opts.async_ = v,
ConfigField::CustomError(v) => opts.custom_error = v,
}
}
if interfaces.is_empty() {
return Err(Error::new(
call_site,
"must either specify `src` or `paths` keys",
));
}
interfaces
} else {
while !input.is_empty() {
let s = input.parse::<syn::LitStr>()?;
files.push(s.value());
}
let mut interfaces = Vec::new();
let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
for path in files.iter() {
let path = manifest_dir.join(path);
let iface = Interface::parse_file(path).map_err(|e| Error::new(call_site, e))?;
interfaces.push(iface);
}
interfaces
};
Ok(Opts {
opts,
interfaces,
files,
})
}
}
enum ConfigField {
Interfaces(Vec<Interface>),
Async(wit_bindgen_gen_wasmtime::Async),
CustomError(bool),
}
impl Parse for ConfigField {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let l = input.lookahead1();
if l.peek(kw::src) {
input.parse::<kw::src>()?;
let name;
syn::bracketed!(name in input);
let name = name.parse::<syn::LitStr>()?;
input.parse::<Token![:]>()?;
let s = input.parse::<syn::LitStr>()?;
let interface =
Interface::parse(&name.value(), &s.value()).map_err(|e| Error::new(s.span(), e))?;
Ok(ConfigField::Interfaces(vec![interface]))
} else if l.peek(kw::paths) {
input.parse::<kw::paths>()?;
input.parse::<Token![:]>()?;
let paths;
let bracket = syn::bracketed!(paths in input);
let paths = Punctuated::<syn::LitStr, Token![,]>::parse_terminated(&paths)?;
let values = paths.iter().map(|s| s.value()).collect::<Vec<_>>();
let mut interfaces = Vec::new();
let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
for value in &values {
let value = manifest_dir.join(value);
let interface =
Interface::parse_file(value).map_err(|e| Error::new(bracket.span, e))?;
interfaces.push(interface);
}
Ok(ConfigField::Interfaces(interfaces))
} else if l.peek(token::Async) {
if !cfg!(feature = "async") {
return Err(
input.error("async support not enabled in the `wit-bindgen-wasmtime` crate")
);
}
input.parse::<token::Async>()?;
input.parse::<Token![:]>()?;
let val = if input.parse::<Option<Token![*]>>()?.is_some() {
Async::All
} else {
let names;
syn::bracketed!(names in input);
let paths = Punctuated::<syn::LitStr, Token![,]>::parse_terminated(&names)?;
let values = paths.iter().map(|s| s.value()).collect();
Async::Only(values)
};
Ok(ConfigField::Async(val))
} else if l.peek(kw::custom_error) {
input.parse::<kw::custom_error>()?;
input.parse::<Token![:]>()?;
Ok(ConfigField::CustomError(
input.parse::<syn::LitBool>()?.value,
))
} else {
Err(l.error())
}
}
}