diff --git a/crates/generate/src/config.rs b/crates/generate/src/config.rs index 3cb1cf5c09..9e7848e82c 100644 --- a/crates/generate/src/config.rs +++ b/crates/generate/src/config.rs @@ -1,64 +1,98 @@ use std::path::PathBuf; +use proc_macro2::Span; use syn::{ - bracketed, + braced, bracketed, parse::{Parse, ParseStream}, punctuated::Punctuated, - token, LitStr, Result, Token, + Error, Ident, LitStr, Result, Token, }; +#[derive(Debug, Clone)] pub struct Config { - _bracket_token: token::Bracket, - path_lits: Punctuated, + pub witx: WitxConf, + pub ctx: CtxConf, +} + +enum ConfigField { + Witx(WitxConf), + Ctx(CtxConf), +} + +impl Parse for ConfigField { + fn parse(input: ParseStream) -> Result { + let id: Ident = input.parse()?; + let _colon: Token![:] = input.parse()?; + match id.to_string().as_ref() { + "witx" => Ok(ConfigField::Witx(input.parse()?)), + "ctx" => Ok(ConfigField::Ctx(input.parse()?)), + _ => Err(Error::new(id.span(), "expected `witx` or `ctx`")), + } + } } impl Config { - pub fn witx_paths(&self) -> Vec { - self.path_lits - .iter() - .map(|lit| PathBuf::from(lit.value())) - .collect() + fn build(fields: impl Iterator, err_loc: Span) -> Result { + let mut witx = None; + let mut ctx = None; + for f in fields { + match f { + ConfigField::Witx(c) => { + witx = Some(c); + } + ConfigField::Ctx(c) => { + ctx = Some(c); + } + } + } + Ok(Config { + witx: witx + .take() + .ok_or_else(|| Error::new(err_loc, "`witx` field required"))?, + ctx: ctx + .take() + .ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?, + }) } } impl Parse for Config { + fn parse(input: ParseStream) -> Result { + let contents; + let _lbrace = braced!(contents in input); + let fields: Punctuated = + contents.parse_terminated(ConfigField::parse)?; + Ok(Config::build(fields.into_iter(), input.span())?) + } +} + +#[derive(Debug, Clone)] +pub struct WitxConf { + pub paths: Vec, +} + +impl Parse for WitxConf { fn parse(input: ParseStream) -> Result { let content; - Ok(Config { - _bracket_token: bracketed!(content in input), - path_lits: content.parse_terminated(Parse::parse)?, + let _ = bracketed!(content in input); + let path_lits: Punctuated = content.parse_terminated(Parse::parse)?; + let paths: Vec = path_lits + .iter() + .map(|lit| PathBuf::from(lit.value())) + .collect(); + Ok(WitxConf { paths }) + } +} + +#[derive(Debug, Clone)] +pub struct CtxConf { + pub name: Ident, +} + +impl Parse for CtxConf { + fn parse(input: ParseStream) -> Result { + Ok(CtxConf { + name: input.parse()?, }) } } - -/* - let arg_strings = args - .into_iter() - .map(|arg| match arg { - TokenTree::Literal(lit) => string_literal(lit), - _ => bail!("expected string literal, got: {:?}", arg), - }) - .collect::>>()?; - - if arg_strings.is_empty() { - bail!("expected at least one argument"); - } - Ok(arg_strings) -} - -fn string_literal(literal: Literal) -> Result { - let s = literal.to_string(); - if !s.starts_with('"') || !s.ends_with('"') { - bail!("string literal must be enclosed in double quotes"); - } - - let trimmed = s[1..s.len() - 1].to_owned(); - if trimmed.contains('"') { - bail!("string literal must not contain quotes"); - } - if trimmed.contains('\\') { - bail!("string literal must not contain backslashes"); - } - Ok(trimmed) -} -*/ diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs index 15f3a8fae5..8313fe0c1c 100644 --- a/crates/generate/src/funcs.rs +++ b/crates/generate/src/funcs.rs @@ -4,11 +4,9 @@ use quote::quote; use crate::names::Names; use crate::types::struct_is_copy; -// FIXME need to template what argument is required to an import function - some context -// struct (e.g. WasiCtx) should be provided at the invocation of the `gen` proc macro. -// pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { let ident = names.func(&func.name); + let ctx_type = names.ctx_type(); let coretype = func.core_type(); let params = coretype.args.iter().map(|arg| match arg.signifies { @@ -30,7 +28,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { }); let abi_args = quote!( - ctx: &mut WasiCtx, memory: ::memory::GuestMemory, + ctx: &mut #ctx_type, memory: ::memory::GuestMemory, #(#params),* ); let abi_ret = if let Some(ret) = &coretype.ret { diff --git a/crates/generate/src/lib.rs b/crates/generate/src/lib.rs index 9b66c9e1e8..4a50d88874 100644 --- a/crates/generate/src/lib.rs +++ b/crates/generate/src/lib.rs @@ -20,9 +20,9 @@ use types::define_datatype; pub fn from_witx(args: TokenStream) -> TokenStream { let config = parse_macro_input!(args as Config); - let names = Names::new(); // TODO parse the names from the invocation of the macro, or from a file? + let doc = witx::load(&config.witx.paths).expect("loading witx"); - let doc = witx::load(&config.witx_paths()).expect("loading witx"); + let names = Names::new(config); // TODO parse the names from the invocation of the macro, or from a file? let types = doc.typenames().map(|t| define_datatype(&names, &t)); @@ -30,9 +30,10 @@ pub fn from_witx(args: TokenStream) -> TokenStream { let modname = names.module(&module.name); let fs = module.funcs().map(|f| define_func(&names, &f)); let modtrait = define_module_trait(&names, &module); + let ctx_type = names.ctx_type(); quote!( mod #modname { - use super::WasiCtx; + use super::#ctx_type; use super::types::*; #(#fs)* diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs index 558a7e28dc..c9ad2ba253 100644 --- a/crates/generate/src/names.rs +++ b/crates/generate/src/names.rs @@ -3,14 +3,19 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use witx::{AtomType, BuiltinType, Id, TypeRef}; +use crate::Config; + #[derive(Debug, Clone)] pub struct Names { - // FIXME: overrides go in here, so we can map e.g. 2big => TooBig + config: Config, } impl Names { - pub fn new() -> Names { - Names {} + pub fn new(config: Config) -> Names { + Names { config } + } + pub fn ctx_type(&self) -> Ident { + self.config.ctx.name.clone() } pub fn type_(&self, id: &Id) -> TokenStream { let ident = format_ident!("{}", id.as_str().to_camel_case()); diff --git a/src/lib.rs b/src/lib.rs index 65356c89a5..145e6ea783 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ pub mod test { // FIXME: parameterize macro on what ctx type is used here - generate::from_witx!(["test.witx"]); + generate::from_witx!({ + witx: ["test.witx"], + ctx: WasiCtx, + }); pub struct WasiCtx { guest_errors: Vec<::memory::GuestError>,