Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::Mode;
use crate::instrument::InstrumentArgs;
use crate::util::*;
use crate::wit_util::*;
use anyhow::{Result, bail};
use std::collections::{BTreeMap, BTreeSet};
use std::path::Path;
Expand Down
188 changes: 78 additions & 110 deletions src/codegen/dialog.rs
Original file line number Diff line number Diff line change
@@ -1,129 +1,97 @@
use super::State;
use crate::util::{
FullTypePath, ResourceFuncKind, constructor_resource_name, extract_arg_info, get_owned_type,
get_return_type, make_path, wit_func_name,
use super::util::{
constructor_resource_name, extract_arg_info, get_return_type, params_to_wave, wit_func_name,
};
use super::{ExportFunc, State};
use quote::quote;
use syn::{Signature, parse_quote, visit_mut::VisitMut};
use syn::{Signature, parse_quote};

impl State {
pub fn generate_dialog_func(
pub fn generate_dialog_import_func(
&self,
module_path: &[String],
sig: &Signature,
resource: &Option<String>,
resource: Option<&str>,
) -> syn::ImplItemFn {
let func_name = &sig.ident;
let is_export = module_path.join("::") == "exports::proxy::recorder::start_replay";
if !is_export {
let (kind, args) = extract_arg_info(sig);
let arg_names = args.iter().map(|arg| &arg.ident);
let display_name = wit_func_name(module_path, resource, func_name, &kind);
let ret_ty = get_return_type(&sig.output);
if let Some(ty) = ret_ty {
let init_vec = if matches!(kind, Some(ResourceFuncKind::Method)) {
quote! { vec![wasm_wave::to_string(&ToValue::to_value(&self)).unwrap()] }
} else {
quote! { Vec::new() }
};
let (ret_name, read_ret) = match constructor_resource_name(resource, &kind) {
Some(name) => (
quote! { #name },
quote! { MockedResource { name: #name.to_string(), ..Dialog::read_value(0) } },
),
None => (
quote! { <#ty as WitName>::name() },
quote! { Dialog::read_value(0) },
),
};
parse_quote! {
#sig {
let mut __params: Vec<String> = #init_vec;
#(
__params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap());
)*
proxy::util::dialog::print(0, &format!("import: {}({})", #display_name, __params.join(", ")));
proxy::util::dialog::print(0, &format!("return type: {}", #ret_name));
let ret = #read_ret;
proxy::util::dialog::print(0, &format!("ret: {}", wasm_wave::to_string(&ToValue::to_value(&ret)).unwrap()));
ret
}
}
} else {
parse_quote! {
#[allow(unused_variables)]
#sig {}
let (kind, args) = extract_arg_info(sig);
let display_name = wit_func_name(module_path, resource, func_name, kind.as_ref());
let ret_ty = get_return_type(&sig.output);
if let Some(ty) = ret_ty {
let params = params_to_wave(kind.as_ref(), &args);
let (ret_name, read_ret) = match constructor_resource_name(resource, kind.as_ref()) {
Some(name) => (
quote! { #name },
quote! { MockedResource { name: #name.to_string(), ..Dialog::read_value(0) } },
),
None => (
quote! { <#ty as WitName>::name() },
quote! { Dialog::read_value(0) },
),
};
parse_quote! {
#sig {
#params
proxy::util::dialog::print(0, &format!("import: {}({})", #display_name, __params.join(", ")));
proxy::util::dialog::print(0, &format!("return type: {}", #ret_name));
let ret = #read_ret;
proxy::util::dialog::print(0, &format!("ret: {}", wasm_wave::to_string(&ToValue::to_value(&ret)).unwrap()));
ret
}
}
} else {
assert!(func_name == "start");
let arms: Vec<_> = self
.funcs
.iter()
.filter(|(path, _)| path[0] != "exports" && path[0] != "proxy")
.flat_map(|(path, resources)| {
resources.iter().flat_map(move |(resource, sigs)| {
sigs.iter().filter_map(move |sig| {
let (kind, args) = extract_arg_info(sig);
if matches!(kind, Some(ResourceFuncKind::Method)) {
return None;
}
let arg_name: Vec<_> = args.iter().map(|arg| &arg.ident).collect();
let call_param = args.iter().map(|arg| arg.call_param());
let ty = args.iter().map(|arg| {
let mut ty = arg.ty.clone();
FullTypePath { module_path: path }.visit_type_mut(&mut ty);
if let Some(owned) = get_owned_type(&ty) {
owned
} else {
ty
}
});
let func_name = if let Some(resource) = resource {
format!("{}::{}", resource, sig.ident)
} else {
sig.ident.to_string()
};
let func = make_path(path, &func_name);
let display_name = wit_func_name(path, resource, &sig.ident, &kind);
Some((quote! {
{
proxy::util::dialog::print(0, &format!("call export func {}", #display_name));
let mut __params: Vec<String> = Vec::new();
#(
proxy::util::dialog::print(0, &format!("provide argument for {}: {}", stringify!(#arg_name), <#ty as WitName>::name()));
let #arg_name: #ty = Dialog::read_value(0);
__params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_name)).unwrap());
)*
proxy::util::dialog::print(0, &format!("export: {}({})", #display_name, __params.join(", ")));
let _ = #func(#(#call_param),*);
}
}, display_name))
})
})
})
.collect();
let (arms, display_names): (Vec<_>, Vec<_>) = arms.into_iter().unzip();
let display_names =
quote! { ["All done".to_string(), #(#display_names.to_string()),*] };
let func_len = arms.iter().len();
let idxs = 1..=func_len;
parse_quote! {
#sig {
loop {
let idx = proxy::util::dialog::read_select(0, "Select an export function to call", &#display_names) as usize;
match idx {
0 => break,
#(#idxs => #arms)*
_ => unreachable!(),
}
// clean up borrowed resources from input args
SCOPED_ALLOC.with(|alloc| {
alloc.borrow_mut().clear();
});
#[allow(unused_variables)]
#sig {}
}
}
}
pub fn generate_dialog_start_func(&self, sig: &Signature) -> syn::ImplItemFn {
let funcs = self.export_funcs();
let display_names = funcs.iter().map(|func| &func.display_name);
let display_names = quote! { ["All done".to_string(), #(#display_names.to_string()),*] };
let arms: Vec<_> = funcs
.iter()
.map(|func| {
let ExportFunc {
display_name,
func,
arg_names,
arg_tys,
call_params,
..
} = func;
quote! {
{
proxy::util::dialog::print(0, &format!("call export func {}", #display_name));
let mut __params: Vec<String> = Vec::new();
#(
proxy::util::dialog::print(0, &format!("provide argument for {}: {}", stringify!(#arg_names), <#arg_tys as WitName>::name()));
let #arg_names: #arg_tys = Dialog::read_value(0);
__params.push(wasm_wave::to_string(&ToValue::to_value(&#arg_names)).unwrap());
)*
proxy::util::dialog::print(0, &format!("export: {}({})", #display_name, __params.join(", ")));
let _ = #func(#(#call_params),*);
}
}
})
.collect();
let func_len = arms.len();
let idxs = 1..=func_len;
parse_quote! {
#sig {
loop {
let idx = proxy::util::dialog::read_select(0, "Select an export function to call", &#display_names) as usize;
match idx {
0 => break,
#(#idxs => #arms)*
_ => unreachable!(),
}
// clean up borrowed resources from input args
SCOPED_ALLOC.with(|alloc| {
alloc.borrow_mut().clear();
});
}
}
}
}
}
Loading
Loading