mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-12 12:31:22 +00:00
Store richer adapter types, don't use instructions for TypeScript (#1945)
This commit updates how TypeScript signature are generated from adapters in wasm-bindgen. A richer set of `AdapterType` types are now stored which record information about optional types and such. These direct `AdapterType` values are then used to calculate the TypeScript signature, rather than following the instructions in an adapter function (which only works anyway for wasm-bindgen generated adapters). This should be more robust since it reads the actual true signature of the adapter to generate the TypeScript signature, rather than attempting to ad-hoc-ly infer it from the various instructions, which was already broken. A number of refactorings were involved here, but the main pieces are: * The `AdapterType` type is a bit more rich now to describe more Rust-like types. * The `TypescriptArg` structure is now gone and instead return values are directly inferred from type signatures of adapters. * The `typescript_{required,optional}` methods are no longer needed. * The return of `JsBuilder::process` was enhanced to return more values, rather than storing some return values on the structure itself. Closes #1926
This commit is contained in:
@ -15,10 +15,6 @@ use walrus::Module;
|
||||
pub struct Builder<'a, 'b> {
|
||||
/// Parent context used to expose helper functions and such.
|
||||
pub cx: &'a mut Context<'b>,
|
||||
/// The TypeScript definition for each argument to this function.
|
||||
pub ts_args: Vec<TypescriptArg>,
|
||||
/// The TypeScript return value for this function.
|
||||
pub ts_ret: Option<TypescriptArg>,
|
||||
/// Whether or not this is building a constructor for a Rust class, and if
|
||||
/// so what class it's constructing.
|
||||
constructor: Option<String>,
|
||||
@ -39,10 +35,6 @@ pub struct JsBuilder<'a, 'b> {
|
||||
/// JS functions, etc.
|
||||
cx: &'a mut Context<'b>,
|
||||
|
||||
/// The list of typescript arguments that we're going to have to this
|
||||
/// function.
|
||||
typescript: Vec<TypescriptArg>,
|
||||
|
||||
/// The "prelude" of the function, or largely just the JS function we've
|
||||
/// built so far.
|
||||
prelude: String,
|
||||
@ -66,10 +58,12 @@ pub struct JsBuilder<'a, 'b> {
|
||||
stack: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct TypescriptArg {
|
||||
pub ty: String,
|
||||
pub name: String,
|
||||
pub optional: bool,
|
||||
pub struct JsFunction {
|
||||
pub code: String,
|
||||
pub ts_sig: String,
|
||||
pub js_doc: String,
|
||||
pub ts_arg_tys: Vec<String>,
|
||||
pub ts_ret_ty: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Builder<'a, 'b> {
|
||||
@ -77,8 +71,6 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
Builder {
|
||||
log_error: false,
|
||||
cx,
|
||||
ts_args: Vec::new(),
|
||||
ts_ret: None,
|
||||
constructor: None,
|
||||
method: None,
|
||||
catch: false,
|
||||
@ -106,7 +98,7 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
adapter: &Adapter,
|
||||
instructions: &[InstructionData],
|
||||
explicit_arg_names: &Option<Vec<String>>,
|
||||
) -> Result<String, Error> {
|
||||
) -> Result<JsFunction, Error> {
|
||||
if self
|
||||
.cx
|
||||
.aux
|
||||
@ -118,6 +110,7 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
|
||||
let mut params = adapter.params.iter();
|
||||
let mut function_args = Vec::new();
|
||||
let mut arg_tys = Vec::new();
|
||||
|
||||
// If this is a method then we're generating this as part of a class
|
||||
// method, so the leading parameter is the this pointer stored on
|
||||
@ -141,13 +134,14 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
for (i, _param) in params.enumerate() {
|
||||
for (i, param) in params.enumerate() {
|
||||
let arg = match explicit_arg_names {
|
||||
Some(list) => list[i].clone(),
|
||||
None => format!("arg{}", i),
|
||||
};
|
||||
js.args.push(arg.clone());
|
||||
function_args.push(arg);
|
||||
arg_tys.push(param);
|
||||
}
|
||||
|
||||
// Translate all instructions, the fun loop!
|
||||
@ -170,7 +164,6 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
match js.stack.len() {
|
||||
0 => {}
|
||||
1 => {
|
||||
self.ts_ret = js.typescript.pop();
|
||||
let val = js.pop();
|
||||
js.prelude(&format!("return {};", val));
|
||||
}
|
||||
@ -188,18 +181,17 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
// }
|
||||
}
|
||||
assert!(js.stack.is_empty());
|
||||
self.ts_args = js.typescript;
|
||||
|
||||
// Remove extraneous typescript args which were synthesized and aren't
|
||||
// part of our function shim.
|
||||
while self.ts_args.len() > function_args.len() {
|
||||
self.ts_args.remove(0);
|
||||
}
|
||||
// // Remove extraneous typescript args which were synthesized and aren't
|
||||
// // part of our function shim.
|
||||
// while self.ts_args.len() > function_args.len() {
|
||||
// self.ts_args.remove(0);
|
||||
// }
|
||||
|
||||
let mut ret = String::new();
|
||||
ret.push_str("(");
|
||||
ret.push_str(&function_args.join(", "));
|
||||
ret.push_str(") {\n");
|
||||
let mut code = String::new();
|
||||
code.push_str("(");
|
||||
code.push_str(&function_args.join(", "));
|
||||
code.push_str(") {\n");
|
||||
|
||||
let mut call = js.prelude;
|
||||
if js.finally.len() != 0 {
|
||||
@ -220,10 +212,20 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
call = format!("try {{\n{}}} catch (e) {{\n logError(e)\n}}\n", call);
|
||||
}
|
||||
|
||||
ret.push_str(&call);
|
||||
ret.push_str("}");
|
||||
code.push_str(&call);
|
||||
code.push_str("}");
|
||||
|
||||
return Ok(ret);
|
||||
let (ts_sig, ts_arg_tys, ts_ret_ty) =
|
||||
self.typescript_signature(&function_args, &arg_tys, &adapter.results);
|
||||
let js_doc = self.js_doc_comments(&function_args, &arg_tys, &ts_ret_ty);
|
||||
|
||||
Ok(JsFunction {
|
||||
code,
|
||||
ts_sig,
|
||||
js_doc,
|
||||
ts_arg_tys,
|
||||
ts_ret_ty,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the typescript signature of the binding that this has described.
|
||||
@ -231,61 +233,79 @@ impl<'a, 'b> Builder<'a, 'b> {
|
||||
///
|
||||
/// Note that the TypeScript returned here is just the argument list and the
|
||||
/// return value, it doesn't include the function name in any way.
|
||||
pub fn typescript_signature(&self) -> String {
|
||||
fn typescript_signature(
|
||||
&self,
|
||||
arg_names: &[String],
|
||||
arg_tys: &[&AdapterType],
|
||||
result_tys: &[AdapterType],
|
||||
) -> (String, Vec<String>, Option<String>) {
|
||||
// Build up the typescript signature as well
|
||||
let mut omittable = true;
|
||||
let mut ts_args = Vec::new();
|
||||
for arg in self.ts_args.iter().rev() {
|
||||
let mut ts_arg_tys = Vec::new();
|
||||
for (name, ty) in arg_names.iter().zip(arg_tys).rev() {
|
||||
// In TypeScript, we can mark optional parameters as omittable
|
||||
// using the `?` suffix, but only if they're not followed by
|
||||
// non-omittable parameters. Therefore iterate the parameter list
|
||||
// in reverse and stop using the `?` suffix for optional params as
|
||||
// soon as a non-optional parameter is encountered.
|
||||
if arg.optional {
|
||||
if omittable {
|
||||
ts_args.push(format!("{}?: {}", arg.name, arg.ty));
|
||||
} else {
|
||||
ts_args.push(format!("{}: {} | undefined", arg.name, arg.ty));
|
||||
let mut arg = name.to_string();
|
||||
let mut ts = String::new();
|
||||
match ty {
|
||||
AdapterType::Option(ty) if omittable => {
|
||||
arg.push_str("?: ");
|
||||
adapter2ts(ty, &mut ts);
|
||||
}
|
||||
ty => {
|
||||
omittable = false;
|
||||
arg.push_str(": ");
|
||||
adapter2ts(ty, &mut ts);
|
||||
}
|
||||
} else {
|
||||
omittable = false;
|
||||
ts_args.push(format!("{}: {}", arg.name, arg.ty));
|
||||
}
|
||||
arg.push_str(&ts);
|
||||
ts_arg_tys.push(ts);
|
||||
ts_args.push(arg);
|
||||
}
|
||||
ts_args.reverse();
|
||||
ts_arg_tys.reverse();
|
||||
let mut ts = format!("({})", ts_args.join(", "));
|
||||
|
||||
// Constructors have no listed return type in typescript
|
||||
let mut ts_ret = None;
|
||||
if self.constructor.is_none() {
|
||||
ts.push_str(": ");
|
||||
if let Some(ty) = &self.ts_ret {
|
||||
ts.push_str(&ty.ty);
|
||||
if ty.optional {
|
||||
ts.push_str(" | undefined");
|
||||
}
|
||||
} else {
|
||||
ts.push_str("void");
|
||||
let mut ret = String::new();
|
||||
match result_tys.len() {
|
||||
0 => ret.push_str("void"),
|
||||
1 => adapter2ts(&result_tys[0], &mut ret),
|
||||
_ => ret.push_str("[any]"),
|
||||
}
|
||||
ts.push_str(&ret);
|
||||
ts_ret = Some(ret);
|
||||
}
|
||||
return ts;
|
||||
return (ts, ts_arg_tys, ts_ret);
|
||||
}
|
||||
|
||||
/// Returns a helpful JS doc comment which lists types for all parameters
|
||||
/// and the return value.
|
||||
pub fn js_doc_comments(&self) -> String {
|
||||
let mut ret: String = self
|
||||
.ts_args
|
||||
.iter()
|
||||
.map(|a| {
|
||||
if a.optional {
|
||||
format!("@param {{{} | undefined}} {}\n", a.ty, a.name)
|
||||
} else {
|
||||
format!("@param {{{}}} {}\n", a.ty, a.name)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if let Some(ts) = &self.ts_ret {
|
||||
ret.push_str(&format!("@returns {{{}}}", ts.ty));
|
||||
fn js_doc_comments(
|
||||
&self,
|
||||
arg_names: &[String],
|
||||
arg_tys: &[&AdapterType],
|
||||
ts_ret: &Option<String>,
|
||||
) -> String {
|
||||
let mut ret = String::new();
|
||||
for (name, ty) in arg_names.iter().zip(arg_tys) {
|
||||
ret.push_str("@param {");
|
||||
adapter2ts(ty, &mut ret);
|
||||
ret.push_str("} ");
|
||||
ret.push_str(name);
|
||||
ret.push_str("\n");
|
||||
}
|
||||
if let Some(ts) = ts_ret {
|
||||
if ts != "void" {
|
||||
ret.push_str(&format!("@returns {{{}}}", ts));
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
@ -299,7 +319,6 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
|
||||
tmp: 0,
|
||||
finally: String::new(),
|
||||
prelude: String::new(),
|
||||
typescript: Vec::new(),
|
||||
stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -308,31 +327,6 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
|
||||
&self.args[idx as usize]
|
||||
}
|
||||
|
||||
pub fn typescript_required(&mut self, ty: &str) {
|
||||
let name = self.arg_name();
|
||||
self.typescript.push(TypescriptArg {
|
||||
ty: ty.to_string(),
|
||||
optional: false,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn typescript_optional(&mut self, ty: &str) {
|
||||
let name = self.arg_name();
|
||||
self.typescript.push(TypescriptArg {
|
||||
ty: ty.to_string(),
|
||||
optional: true,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
fn arg_name(&self) -> String {
|
||||
self.args
|
||||
.get(self.typescript.len())
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format!("arg{}", self.typescript.len()))
|
||||
}
|
||||
|
||||
pub fn prelude(&mut self, prelude: &str) {
|
||||
for line in prelude.trim().lines().map(|l| l.trim()) {
|
||||
if !line.is_empty() {
|
||||
@ -426,7 +420,6 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
|
||||
malloc: walrus::FunctionId,
|
||||
realloc: Option<walrus::FunctionId>,
|
||||
) -> Result<(), Error> {
|
||||
self.typescript_required("string");
|
||||
let pass = self.cx.expose_pass_string_to_wasm(mem)?;
|
||||
let val = self.pop();
|
||||
let malloc = self.cx.export_name_of(malloc);
|
||||
@ -510,7 +503,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::Standard(wit_walrus::Instruction::IntToWasm { trap: false, .. }) => {
|
||||
js.typescript_required("number");
|
||||
let val = js.pop();
|
||||
js.assert_number(&val);
|
||||
js.push(val);
|
||||
@ -524,7 +516,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
output,
|
||||
..
|
||||
}) => {
|
||||
js.typescript_required("number");
|
||||
let val = js.pop();
|
||||
match output {
|
||||
wit_walrus::ValType::U32 => js.push(format!("{} >>> 0", val)),
|
||||
@ -538,7 +529,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::Standard(wit_walrus::Instruction::MemoryToString(mem)) => {
|
||||
js.typescript_required("string");
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let get = js.cx.expose_get_string_from_wasm(*mem)?;
|
||||
@ -596,7 +586,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromBool => {
|
||||
js.typescript_required("boolean");
|
||||
let val = js.pop();
|
||||
js.assert_bool(&val);
|
||||
// JS will already coerce booleans into numbers for us
|
||||
@ -604,20 +593,17 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromStringFirstChar => {
|
||||
js.typescript_required("string");
|
||||
let val = js.pop();
|
||||
js.push(format!("{}.codePointAt(0)", val));
|
||||
}
|
||||
|
||||
Instruction::I32FromAnyrefOwned => {
|
||||
js.typescript_required("any");
|
||||
js.cx.expose_add_heap_object();
|
||||
let val = js.pop();
|
||||
js.push(format!("addHeapObject({})", val));
|
||||
}
|
||||
|
||||
Instruction::I32FromAnyrefBorrow => {
|
||||
js.typescript_required("any");
|
||||
js.cx.expose_borrowed_objects();
|
||||
js.cx.expose_global_stack_pointer();
|
||||
let val = js.pop();
|
||||
@ -626,7 +612,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromAnyrefRustOwned { class } => {
|
||||
js.typescript_required(class);
|
||||
let val = js.pop();
|
||||
js.assert_class(&val, &class);
|
||||
js.assert_not_moved(&val);
|
||||
@ -637,7 +622,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromAnyrefRustBorrow { class } => {
|
||||
js.typescript_required(class);
|
||||
let val = js.pop();
|
||||
js.assert_class(&val, &class);
|
||||
js.assert_not_moved(&val);
|
||||
@ -645,7 +629,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionRust { class } => {
|
||||
js.typescript_optional(class);
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
let i = js.tmp();
|
||||
@ -660,7 +643,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32Split64 { signed } => {
|
||||
js.typescript_required("BigInt");
|
||||
let val = js.pop();
|
||||
let f = if *signed {
|
||||
js.cx.expose_int64_cvt_shim()
|
||||
@ -683,7 +665,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32SplitOption64 { signed } => {
|
||||
js.typescript_optional("BigInt");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
let f = if *signed {
|
||||
@ -708,7 +689,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionAnyref { table_and_alloc } => {
|
||||
js.typescript_optional("any");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
match table_and_alloc {
|
||||
@ -724,7 +704,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionU32Sentinel => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
js.assert_optional_number(&val);
|
||||
@ -732,7 +711,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionBool => {
|
||||
js.typescript_optional("boolean");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
js.assert_optional_bool(&val);
|
||||
@ -740,7 +718,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionChar => {
|
||||
js.typescript_optional("string");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
js.push(format!(
|
||||
@ -750,7 +727,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::I32FromOptionEnum { hole } => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
js.assert_optional_number(&val);
|
||||
@ -758,7 +734,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::FromOptionNative { .. } => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
js.cx.expose_is_like_none();
|
||||
js.assert_optional_number(&val);
|
||||
@ -767,7 +742,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::VectorToMemory { kind, malloc, mem } => {
|
||||
js.typescript_required(kind.js_ty());
|
||||
let val = js.pop();
|
||||
let func = js.cx.pass_to_wasm_function(*kind, *mem)?;
|
||||
let malloc = js.cx.export_name_of(*malloc);
|
||||
@ -789,7 +763,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
malloc,
|
||||
realloc,
|
||||
} => {
|
||||
js.typescript_optional("string");
|
||||
let func = js.cx.expose_pass_string_to_wasm(*mem)?;
|
||||
js.cx.expose_is_like_none();
|
||||
let i = js.tmp();
|
||||
@ -813,7 +786,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionVector { kind, mem, malloc } => {
|
||||
js.typescript_optional(kind.js_ty());
|
||||
let func = js.cx.pass_to_wasm_function(*kind, *mem)?;
|
||||
js.cx.expose_is_like_none();
|
||||
let i = js.tmp();
|
||||
@ -837,7 +809,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
mem,
|
||||
free,
|
||||
} => {
|
||||
js.typescript_required(kind.js_ty());
|
||||
// First up, pass the JS value into wasm, getting out a pointer and
|
||||
// a length. These two pointer/length values get pushed onto the
|
||||
// value stack.
|
||||
@ -875,26 +846,22 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::BoolFromI32 => {
|
||||
js.typescript_required("boolean");
|
||||
let val = js.pop();
|
||||
js.push(format!("{} !== 0", val));
|
||||
}
|
||||
|
||||
Instruction::AnyrefLoadOwned => {
|
||||
js.typescript_required("any");
|
||||
js.cx.expose_take_object();
|
||||
let val = js.pop();
|
||||
js.push(format!("takeObject({})", val));
|
||||
}
|
||||
|
||||
Instruction::StringFromChar => {
|
||||
js.typescript_required("string");
|
||||
let val = js.pop();
|
||||
js.push(format!("String.fromCodePoint({})", val));
|
||||
}
|
||||
|
||||
Instruction::I64FromLoHi { signed } => {
|
||||
js.typescript_required("BigInt");
|
||||
let f = if *signed {
|
||||
js.cx.expose_int64_cvt_shim()
|
||||
} else {
|
||||
@ -918,14 +885,12 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::RustFromI32 { class } => {
|
||||
js.typescript_required(class);
|
||||
js.cx.require_class_wrap(class);
|
||||
let val = js.pop();
|
||||
js.push(format!("{}.__wrap({})", class, val));
|
||||
}
|
||||
|
||||
Instruction::OptionRustFromI32 { class } => {
|
||||
js.typescript_optional(class);
|
||||
js.cx.require_class_wrap(class);
|
||||
let val = js.pop();
|
||||
js.push(format!(
|
||||
@ -936,16 +901,10 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
|
||||
Instruction::CachedStringLoad {
|
||||
owned,
|
||||
optional,
|
||||
optional: _,
|
||||
mem,
|
||||
free,
|
||||
} => {
|
||||
if *optional {
|
||||
js.typescript_optional("string");
|
||||
} else {
|
||||
js.typescript_required("string");
|
||||
}
|
||||
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let tmp = js.tmp();
|
||||
@ -968,7 +927,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::TableGet => {
|
||||
js.typescript_required("any");
|
||||
let val = js.pop();
|
||||
js.cx.expose_get_object();
|
||||
js.push(format!("getObject({})", val));
|
||||
@ -979,7 +937,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
nargs,
|
||||
mutable,
|
||||
} => {
|
||||
js.typescript_optional("any");
|
||||
let i = js.tmp();
|
||||
let b = js.pop();
|
||||
let a = js.pop();
|
||||
@ -1025,7 +982,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::VectorLoad { kind, mem, free } => {
|
||||
js.typescript_required(kind.js_ty());
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
|
||||
@ -1043,7 +999,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionVectorLoad { kind, mem, free } => {
|
||||
js.typescript_optional(kind.js_ty());
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
|
||||
@ -1064,7 +1019,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::View { kind, mem } => {
|
||||
js.typescript_required(kind.js_ty());
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
|
||||
@ -1072,7 +1026,6 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionView { kind, mem } => {
|
||||
js.typescript_optional(kind.js_ty());
|
||||
let len = js.pop();
|
||||
let ptr = js.pop();
|
||||
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
|
||||
@ -1085,13 +1038,11 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionU32Sentinel => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
js.push(format!("{0} === 0xFFFFFF ? undefined : {0}", val));
|
||||
}
|
||||
|
||||
Instruction::ToOptionNative { ty: _, signed } => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
let present = js.pop();
|
||||
js.push(format!(
|
||||
@ -1103,13 +1054,11 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionBoolFromI32 => {
|
||||
js.typescript_optional("boolean");
|
||||
let val = js.pop();
|
||||
js.push(format!("{0} === 0xFFFFFF ? undefined : {0} !== 0", val));
|
||||
}
|
||||
|
||||
Instruction::OptionCharFromI32 => {
|
||||
js.typescript_optional("string");
|
||||
let val = js.pop();
|
||||
js.push(format!(
|
||||
"{0} === 0xFFFFFF ? undefined : String.fromCodePoint({0})",
|
||||
@ -1118,13 +1067,11 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
|
||||
}
|
||||
|
||||
Instruction::OptionEnumFromI32 { hole } => {
|
||||
js.typescript_optional("number");
|
||||
let val = js.pop();
|
||||
js.push(format!("{0} === {1} ? undefined : {0}", val, hole));
|
||||
}
|
||||
|
||||
Instruction::Option64FromI32 { signed } => {
|
||||
js.typescript_optional("BigInt");
|
||||
let f = if *signed {
|
||||
js.cx.expose_int64_cvt_shim()
|
||||
} else {
|
||||
@ -1253,3 +1200,28 @@ impl Invocation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adapter2ts(ty: &AdapterType, dst: &mut String) {
|
||||
match ty {
|
||||
AdapterType::I32
|
||||
| AdapterType::S8
|
||||
| AdapterType::S16
|
||||
| AdapterType::S32
|
||||
| AdapterType::U8
|
||||
| AdapterType::U16
|
||||
| AdapterType::U32
|
||||
| AdapterType::F32
|
||||
| AdapterType::F64 => dst.push_str("number"),
|
||||
AdapterType::I64 | AdapterType::S64 | AdapterType::U64 => dst.push_str("BigInt"),
|
||||
AdapterType::String => dst.push_str("string"),
|
||||
AdapterType::Anyref => dst.push_str("any"),
|
||||
AdapterType::Bool => dst.push_str("boolean"),
|
||||
AdapterType::Vector(kind) => dst.push_str(kind.js_ty()),
|
||||
AdapterType::Option(ty) => {
|
||||
adapter2ts(ty, dst);
|
||||
dst.push_str(" | undefined");
|
||||
}
|
||||
AdapterType::Struct(name) => dst.push_str(name),
|
||||
AdapterType::Function => dst.push_str("any"),
|
||||
}
|
||||
}
|
||||
|
@ -1950,7 +1950,13 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
|
||||
// Process the `binding` and generate a bunch of JS/TypeScript/etc.
|
||||
let js = builder
|
||||
let binding::JsFunction {
|
||||
ts_sig,
|
||||
ts_arg_tys,
|
||||
ts_ret_ty,
|
||||
js_doc,
|
||||
code,
|
||||
} = builder
|
||||
.process(&adapter, instrs, arg_names)
|
||||
.with_context(|| match kind {
|
||||
Kind::Export(e) => format!("failed to generate bindings for `{}`", e.debug_name),
|
||||
@ -1963,8 +1969,6 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
Kind::Adapter => format!("failed to generates bindings for adapter"),
|
||||
})?;
|
||||
let ts = builder.typescript_signature();
|
||||
let js_doc = builder.js_doc_comments();
|
||||
|
||||
// Once we've got all the JS then put it in the right location depending
|
||||
// on what's being exported.
|
||||
@ -1973,11 +1977,11 @@ impl<'a> Context<'a> {
|
||||
let docs = format_doc_comments(&export.comments, Some(js_doc));
|
||||
match &export.kind {
|
||||
AuxExportKind::Function(name) => {
|
||||
self.export(&name, &format!("function{}", js), Some(docs))?;
|
||||
self.export(&name, &format!("function{}", code), Some(docs))?;
|
||||
self.globals.push_str("\n");
|
||||
self.typescript.push_str("export function ");
|
||||
self.typescript.push_str(&name);
|
||||
self.typescript.push_str(&ts);
|
||||
self.typescript.push_str(&ts_sig);
|
||||
self.typescript.push_str(";\n");
|
||||
}
|
||||
AuxExportKind::Constructor(class) => {
|
||||
@ -1986,36 +1990,36 @@ impl<'a> Context<'a> {
|
||||
bail!("found duplicate constructor for class `{}`", class);
|
||||
}
|
||||
exported.has_constructor = true;
|
||||
exported.push(&docs, "constructor", "", &js, &ts);
|
||||
exported.push(&docs, "constructor", "", &code, &ts_sig);
|
||||
}
|
||||
AuxExportKind::Getter { class, field } => {
|
||||
let ret_ty = builder.ts_ret.as_ref().unwrap().ty.clone();
|
||||
let ret_ty = ts_ret_ty.unwrap();
|
||||
let exported = require_class(&mut self.exported_classes, class);
|
||||
exported.push_getter(&docs, field, &js, &ret_ty);
|
||||
exported.push_getter(&docs, field, &code, &ret_ty);
|
||||
}
|
||||
AuxExportKind::Setter { class, field } => {
|
||||
let arg_ty = builder.ts_args[0].ty.clone();
|
||||
let arg_ty = ts_arg_tys[0].clone();
|
||||
let exported = require_class(&mut self.exported_classes, class);
|
||||
exported.push_setter(&docs, field, &js, &arg_ty);
|
||||
exported.push_setter(&docs, field, &code, &arg_ty);
|
||||
}
|
||||
AuxExportKind::StaticFunction { class, name } => {
|
||||
let exported = require_class(&mut self.exported_classes, class);
|
||||
exported.push(&docs, name, "static ", &js, &ts);
|
||||
exported.push(&docs, name, "static ", &code, &ts_sig);
|
||||
}
|
||||
AuxExportKind::Method { class, name, .. } => {
|
||||
let exported = require_class(&mut self.exported_classes, class);
|
||||
exported.push(&docs, name, "", &js, &ts);
|
||||
exported.push(&docs, name, "", &code, &ts_sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
Kind::Import(core) => {
|
||||
self.wasm_import_definitions
|
||||
.insert(core, format!("function{}", js));
|
||||
.insert(core, format!("function{}", code));
|
||||
}
|
||||
Kind::Adapter => {
|
||||
self.globals.push_str("function ");
|
||||
self.globals.push_str(&self.adapter_name(id));
|
||||
self.globals.push_str(&js);
|
||||
self.globals.push_str(&code);
|
||||
self.globals.push_str("\n\n");
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ fn extract_xform<'a>(
|
||||
if let Some(Instruction::Retptr) = instructions.first().map(|e| &e.instr) {
|
||||
instructions.remove(0);
|
||||
let mut types = Vec::new();
|
||||
instructions.retain(|instruction| match instruction.instr {
|
||||
instructions.retain(|instruction| match &instruction.instr {
|
||||
Instruction::LoadRetptr { ty, .. } => {
|
||||
types.push(ty.to_wasm().unwrap());
|
||||
false
|
||||
|
@ -69,7 +69,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
}
|
||||
Descriptor::RustStruct(class) => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Struct(class.clone())],
|
||||
Instruction::I32FromAnyrefRustOwned {
|
||||
class: class.clone(),
|
||||
},
|
||||
@ -147,7 +147,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
match arg {
|
||||
Descriptor::RustStruct(class) => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Struct(class.clone())],
|
||||
Instruction::I32FromAnyrefRustBorrow {
|
||||
class: class.clone(),
|
||||
},
|
||||
@ -217,56 +217,56 @@ impl InstructionBuilder<'_, '_> {
|
||||
match arg {
|
||||
Descriptor::Anyref => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Anyref.option()],
|
||||
Instruction::I32FromOptionAnyref {
|
||||
table_and_alloc: None,
|
||||
},
|
||||
&[AdapterType::I32],
|
||||
);
|
||||
}
|
||||
Descriptor::I8 => self.in_option_sentinel(),
|
||||
Descriptor::U8 => self.in_option_sentinel(),
|
||||
Descriptor::I16 => self.in_option_sentinel(),
|
||||
Descriptor::U16 => self.in_option_sentinel(),
|
||||
Descriptor::I8 => self.in_option_sentinel(AdapterType::S8),
|
||||
Descriptor::U8 => self.in_option_sentinel(AdapterType::U8),
|
||||
Descriptor::I16 => self.in_option_sentinel(AdapterType::S16),
|
||||
Descriptor::U16 => self.in_option_sentinel(AdapterType::U16),
|
||||
Descriptor::I32 => self.in_option_native(ValType::I32),
|
||||
Descriptor::U32 => self.in_option_native(ValType::I32),
|
||||
Descriptor::F32 => self.in_option_native(ValType::F32),
|
||||
Descriptor::F64 => self.in_option_native(ValType::F64),
|
||||
Descriptor::I64 | Descriptor::U64 => {
|
||||
let signed = match arg {
|
||||
Descriptor::I64 => true,
|
||||
_ => false,
|
||||
let (signed, ty) = match arg {
|
||||
Descriptor::I64 => (true, AdapterType::S64.option()),
|
||||
_ => (false, AdapterType::U64.option()),
|
||||
};
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[ty],
|
||||
Instruction::I32SplitOption64 { signed },
|
||||
&[AdapterType::I32; 3],
|
||||
&[AdapterType::I32, AdapterType::I32, AdapterType::I32],
|
||||
);
|
||||
}
|
||||
Descriptor::Boolean => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Bool.option()],
|
||||
Instruction::I32FromOptionBool,
|
||||
&[AdapterType::I32],
|
||||
);
|
||||
}
|
||||
Descriptor::Char => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::String.option()],
|
||||
Instruction::I32FromOptionChar,
|
||||
&[AdapterType::I32],
|
||||
);
|
||||
}
|
||||
Descriptor::Enum { hole } => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::U32.option()],
|
||||
Instruction::I32FromOptionEnum { hole: *hole },
|
||||
&[AdapterType::I32],
|
||||
);
|
||||
}
|
||||
Descriptor::RustStruct(name) => {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Struct(name.clone()).option()],
|
||||
Instruction::I32FromOptionRust {
|
||||
class: name.to_string(),
|
||||
},
|
||||
@ -279,13 +279,13 @@ impl InstructionBuilder<'_, '_> {
|
||||
let mem = self.cx.memory()?;
|
||||
let realloc = self.cx.realloc();
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::String.option()],
|
||||
Instruction::OptionString {
|
||||
malloc,
|
||||
mem,
|
||||
realloc,
|
||||
},
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
);
|
||||
}
|
||||
|
||||
@ -299,9 +299,9 @@ impl InstructionBuilder<'_, '_> {
|
||||
let malloc = self.cx.malloc()?;
|
||||
let mem = self.cx.memory()?;
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Vector(kind).option()],
|
||||
Instruction::OptionVector { kind, malloc, mem },
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
);
|
||||
}
|
||||
|
||||
@ -343,7 +343,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
// fetch them from the parameters.
|
||||
if !self.return_position {
|
||||
for input in inputs {
|
||||
self.get(*input);
|
||||
self.get(input.clone());
|
||||
}
|
||||
} else {
|
||||
self.input.extend_from_slice(inputs);
|
||||
@ -385,16 +385,17 @@ impl InstructionBuilder<'_, '_> {
|
||||
}
|
||||
|
||||
fn in_option_native(&mut self, wasm: ValType) {
|
||||
let ty = AdapterType::from_wasm(wasm).unwrap();
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[ty.clone().option()],
|
||||
Instruction::FromOptionNative { ty: wasm },
|
||||
&[AdapterType::I32, AdapterType::from_wasm(wasm).unwrap()],
|
||||
&[AdapterType::I32, ty],
|
||||
);
|
||||
}
|
||||
|
||||
fn in_option_sentinel(&mut self) {
|
||||
fn in_option_sentinel(&mut self, ty: AdapterType) {
|
||||
self.instruction(
|
||||
&[AdapterType::Anyref],
|
||||
&[ty.option()],
|
||||
Instruction::I32FromOptionU32Sentinel,
|
||||
&[AdapterType::I32],
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
_ => false,
|
||||
};
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::I64FromLoHi { signed },
|
||||
&[if signed {
|
||||
AdapterType::S64
|
||||
@ -85,7 +85,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
Instruction::RustFromI32 {
|
||||
class: class.to_string(),
|
||||
},
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Struct(class.clone())],
|
||||
);
|
||||
}
|
||||
Descriptor::Ref(d) => self.outgoing_ref(false, d)?,
|
||||
@ -131,7 +131,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
let mem = self.cx.memory()?;
|
||||
let free = self.cx.free()?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::VectorLoad { kind, mem, free },
|
||||
&[AdapterType::Vector(kind)],
|
||||
);
|
||||
@ -167,7 +167,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
Descriptor::String => {
|
||||
let std = wit_walrus::Instruction::MemoryToString(self.cx.memory()?);
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::Standard(std),
|
||||
&[AdapterType::String],
|
||||
);
|
||||
@ -181,7 +181,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
})?;
|
||||
let mem = self.cx.memory()?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::View { kind, mem },
|
||||
&[AdapterType::Vector(kind)],
|
||||
);
|
||||
@ -198,13 +198,13 @@ impl InstructionBuilder<'_, '_> {
|
||||
.cx
|
||||
.table_element_adapter(descriptor.shim_idx, descriptor)?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::StackClosure {
|
||||
adapter,
|
||||
nargs,
|
||||
mutable,
|
||||
},
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Function],
|
||||
);
|
||||
}
|
||||
|
||||
@ -224,47 +224,47 @@ impl InstructionBuilder<'_, '_> {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::AnyrefLoadOwned,
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Anyref.option()],
|
||||
);
|
||||
}
|
||||
Descriptor::I8 => self.out_option_sentinel(),
|
||||
Descriptor::U8 => self.out_option_sentinel(),
|
||||
Descriptor::I16 => self.out_option_sentinel(),
|
||||
Descriptor::U16 => self.out_option_sentinel(),
|
||||
Descriptor::I8 => self.out_option_sentinel(AdapterType::S8),
|
||||
Descriptor::U8 => self.out_option_sentinel(AdapterType::U8),
|
||||
Descriptor::I16 => self.out_option_sentinel(AdapterType::S16),
|
||||
Descriptor::U16 => self.out_option_sentinel(AdapterType::U16),
|
||||
Descriptor::I32 => self.option_native(true, ValType::I32),
|
||||
Descriptor::U32 => self.option_native(false, ValType::I32),
|
||||
Descriptor::F32 => self.option_native(true, ValType::F32),
|
||||
Descriptor::F64 => self.option_native(true, ValType::F64),
|
||||
Descriptor::I64 | Descriptor::U64 => {
|
||||
let signed = match arg {
|
||||
Descriptor::I64 => true,
|
||||
_ => false,
|
||||
let (signed, ty) = match arg {
|
||||
Descriptor::I64 => (true, AdapterType::S64.option()),
|
||||
_ => (false, AdapterType::U64.option()),
|
||||
};
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 3],
|
||||
&[AdapterType::I32, AdapterType::I32, AdapterType::I32],
|
||||
Instruction::Option64FromI32 { signed },
|
||||
&[AdapterType::Anyref],
|
||||
&[ty],
|
||||
);
|
||||
}
|
||||
Descriptor::Boolean => {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::OptionBoolFromI32,
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Bool.option()],
|
||||
);
|
||||
}
|
||||
Descriptor::Char => {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::OptionCharFromI32,
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::String.option()],
|
||||
);
|
||||
}
|
||||
Descriptor::Enum { hole } => {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::OptionEnumFromI32 { hole: *hole },
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::U32.option()],
|
||||
);
|
||||
}
|
||||
Descriptor::RustStruct(name) => {
|
||||
@ -273,7 +273,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
Instruction::OptionRustFromI32 {
|
||||
class: name.to_string(),
|
||||
},
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Struct(name.clone()).option()],
|
||||
);
|
||||
}
|
||||
Descriptor::Ref(d) => self.outgoing_option_ref(false, d)?,
|
||||
@ -291,9 +291,9 @@ impl InstructionBuilder<'_, '_> {
|
||||
let mem = self.cx.memory()?;
|
||||
let free = self.cx.free()?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::OptionVectorLoad { kind, mem, free },
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Vector(kind).option()],
|
||||
);
|
||||
}
|
||||
|
||||
@ -313,7 +313,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::TableGet,
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Anyref.option()],
|
||||
);
|
||||
}
|
||||
Descriptor::CachedString => self.cached_string(true, false)?,
|
||||
@ -326,9 +326,9 @@ impl InstructionBuilder<'_, '_> {
|
||||
})?;
|
||||
let mem = self.cx.memory()?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::OptionView { kind, mem },
|
||||
&[AdapterType::Anyref],
|
||||
&[AdapterType::Vector(kind).option()],
|
||||
);
|
||||
}
|
||||
_ => bail!(
|
||||
@ -352,7 +352,7 @@ impl InstructionBuilder<'_, '_> {
|
||||
let mem = self.cx.memory()?;
|
||||
let free = self.cx.free()?;
|
||||
self.instruction(
|
||||
&[AdapterType::I32; 2],
|
||||
&[AdapterType::I32, AdapterType::I32],
|
||||
Instruction::CachedStringLoad {
|
||||
owned,
|
||||
optional,
|
||||
@ -365,18 +365,19 @@ impl InstructionBuilder<'_, '_> {
|
||||
}
|
||||
|
||||
fn option_native(&mut self, signed: bool, ty: ValType) {
|
||||
let adapter_ty = AdapterType::from_wasm(ty).unwrap();
|
||||
self.instruction(
|
||||
&[AdapterType::I32, AdapterType::from_wasm(ty).unwrap()],
|
||||
&[AdapterType::I32, adapter_ty.clone()],
|
||||
Instruction::ToOptionNative { signed, ty },
|
||||
&[AdapterType::Anyref],
|
||||
&[adapter_ty.option()],
|
||||
);
|
||||
}
|
||||
|
||||
fn out_option_sentinel(&mut self) {
|
||||
fn out_option_sentinel(&mut self, ty: AdapterType) {
|
||||
self.instruction(
|
||||
&[AdapterType::I32],
|
||||
Instruction::OptionU32Sentinel,
|
||||
&[AdapterType::Anyref],
|
||||
&[ty.option()],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ pub enum AdapterJsImportKind {
|
||||
Normal,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AdapterType {
|
||||
S8,
|
||||
S16,
|
||||
@ -82,6 +82,9 @@ pub enum AdapterType {
|
||||
I32,
|
||||
I64,
|
||||
Vector(VectorKind),
|
||||
Option(Box<AdapterType>),
|
||||
Struct(String),
|
||||
Function,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -338,11 +341,20 @@ impl AdapterType {
|
||||
AdapterType::F64 => wit_walrus::ValType::F64,
|
||||
AdapterType::String => wit_walrus::ValType::String,
|
||||
AdapterType::Anyref => wit_walrus::ValType::Anyref,
|
||||
|
||||
AdapterType::I32 => wit_walrus::ValType::I32,
|
||||
AdapterType::I64 => wit_walrus::ValType::I64,
|
||||
AdapterType::Bool | AdapterType::Vector(_) => return None,
|
||||
AdapterType::Option(_)
|
||||
| AdapterType::Function
|
||||
| AdapterType::Struct(_)
|
||||
| AdapterType::Bool
|
||||
| AdapterType::Vector(_) => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn option(self) -> AdapterType {
|
||||
AdapterType::Option(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl NonstandardWitSection {
|
||||
|
Reference in New Issue
Block a user