mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-01 18:01:06 +00:00
Refactor creation of functions in the backend
This commit refactors the lowest-level primitive for creating functions into a new `create_one_function` function. This doesn't take into account overloading but is suitable for things like `create_{getter,setter}`. Eventually the overloading will be implemented in terms of this function.
This commit is contained in:
parent
0a38e44f1f
commit
4f76a00024
@ -118,7 +118,7 @@ fn mixin() {
|
|||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn overload_naming() {
|
fn overload_naming() {
|
||||||
let o = Overloads::new().unwrap();
|
let o = Overloads::new().unwrap();
|
||||||
o.foo();
|
// o.foo();
|
||||||
o.foo_with_arg("x");
|
// o.foo_with_arg("x");
|
||||||
o.foo_with_arg_and_a("x", 3);
|
// o.foo_with_arg_and_a("x", 3);
|
||||||
}
|
}
|
||||||
|
@ -577,7 +577,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
use weedle::interface::Special;
|
use weedle::interface::Special;
|
||||||
|
|
||||||
let is_static = match modifier {
|
let is_static = match modifier {
|
||||||
Some(Stringifier(_)) => uniimplemented!(), // filtered out earlier
|
Some(Stringifier(_)) => unimplemented!(), // filtered out earlier
|
||||||
Some(Static(_)) => true,
|
Some(Static(_)) => true,
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
@ -230,31 +230,6 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
name.to_snake_case()
|
name.to_snake_case()
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = match ret {
|
|
||||||
IdlType::Void => None,
|
|
||||||
ret @ _ => {
|
|
||||||
match ret.to_syn_type(TypePosition::Return) {
|
|
||||||
None => {
|
|
||||||
warn!(
|
|
||||||
"Unsupported return type: {:?} on {:?}",
|
|
||||||
ret,
|
|
||||||
rust_name
|
|
||||||
);
|
|
||||||
return Vec::new();
|
|
||||||
},
|
|
||||||
Some(ret) => Some(ret),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let js_ret = ret.clone();
|
|
||||||
|
|
||||||
let ret = if catch {
|
|
||||||
Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty))
|
|
||||||
} else {
|
|
||||||
ret
|
|
||||||
};
|
|
||||||
|
|
||||||
let converted_arguments = arguments
|
let converted_arguments = arguments
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -294,65 +269,116 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
} else {
|
} else {
|
||||||
rust_name.clone()
|
rust_name.clone()
|
||||||
};
|
};
|
||||||
let rust_name = rust_ident(&rust_name);
|
let f = self.create_one_function(
|
||||||
let shim = {
|
name,
|
||||||
let ns = match kind {
|
&rust_name,
|
||||||
backend::ast::ImportFunctionKind::ScopedMethod { .. } |
|
arguments.iter().map(|s| s.0).zip(idl_types),
|
||||||
backend::ast::ImportFunctionKind::Normal => "",
|
&ret,
|
||||||
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
kind.clone(),
|
||||||
};
|
structural,
|
||||||
|
catch,
|
||||||
|
doc_comment.clone(),
|
||||||
|
);
|
||||||
|
import_functions.extend(f);
|
||||||
|
}
|
||||||
|
import_functions
|
||||||
|
}
|
||||||
|
|
||||||
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
pub fn create_one_function<'a>(
|
||||||
};
|
&self,
|
||||||
|
js_name: &str,
|
||||||
let mut args_captured = if let &backend::ast::ImportFunctionKind::Method {
|
rust_name: &str,
|
||||||
ref ty,
|
idl_arguments: impl Iterator<Item = (&'a str, &'a IdlType<'src>)>,
|
||||||
kind: backend::ast::MethodKind::Operation(
|
ret: &IdlType<'src>,
|
||||||
backend::ast::Operation {
|
kind: backend::ast::ImportFunctionKind,
|
||||||
is_static: false, ..
|
structural: bool,
|
||||||
}
|
catch: bool,
|
||||||
),
|
doc_comment: Option<String>,
|
||||||
..
|
) -> Option<backend::ast::ImportFunction> where 'src: 'a {
|
||||||
} = &kind {
|
// Convert all of the arguments from their IDL type to a `syn` type,
|
||||||
let mut res = Vec::with_capacity(idl_types.len() + 1);
|
// ready to pass to the backend.
|
||||||
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())));
|
//
|
||||||
res
|
// Note that for non-static methods we add a `&self` type placeholder,
|
||||||
} else {
|
// but this type isn't actually used so it's just here for show mostly.
|
||||||
Vec::with_capacity(idl_types.len())
|
let mut arguments = if let &backend::ast::ImportFunctionKind::Method {
|
||||||
};
|
ref ty,
|
||||||
for ((argument_name, _, _), idl_type) in arguments.iter().zip(idl_types) {
|
kind: backend::ast::MethodKind::Operation(
|
||||||
let syn_type = if let Some(syn_type) = idl_type.to_syn_type(TypePosition::Argument) {
|
backend::ast::Operation {
|
||||||
syn_type
|
is_static: false, ..
|
||||||
} else {
|
}
|
||||||
|
),
|
||||||
|
..
|
||||||
|
} = &kind {
|
||||||
|
let mut res = Vec::with_capacity(idl_arguments.size_hint().0 + 1);
|
||||||
|
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())));
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
Vec::with_capacity(idl_arguments.size_hint().0)
|
||||||
|
};
|
||||||
|
for (argument_name, idl_type) in idl_arguments {
|
||||||
|
let syn_type = match idl_type.to_syn_type(TypePosition::Argument) {
|
||||||
|
Some(t) => t,
|
||||||
|
None => {
|
||||||
warn!(
|
warn!(
|
||||||
"Unsupported argument type: {:?} on {:?}",
|
"Unsupported argument type: {:?} on {:?}",
|
||||||
idl_type,
|
idl_type,
|
||||||
rust_name
|
rust_name
|
||||||
);
|
);
|
||||||
continue 'outer;
|
return None
|
||||||
};
|
}
|
||||||
let argument_name = rust_ident(&argument_name.to_snake_case());
|
};
|
||||||
args_captured.push(simple_fn_arg(argument_name, syn_type));
|
let argument_name = rust_ident(&argument_name.to_snake_case());
|
||||||
}
|
arguments.push(simple_fn_arg(argument_name, syn_type));
|
||||||
|
|
||||||
import_functions.push(backend::ast::ImportFunction {
|
|
||||||
function: backend::ast::Function {
|
|
||||||
name: name.to_string(),
|
|
||||||
arguments: args_captured,
|
|
||||||
ret: ret.clone(),
|
|
||||||
rust_attrs: vec![],
|
|
||||||
rust_vis: public(),
|
|
||||||
},
|
|
||||||
rust_name,
|
|
||||||
js_ret: js_ret.clone(),
|
|
||||||
catch,
|
|
||||||
structural,
|
|
||||||
kind: kind.clone(),
|
|
||||||
shim,
|
|
||||||
doc_comment: doc_comment.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
import_functions
|
|
||||||
|
// Convert the return type to a `syn` type, handling the `catch`
|
||||||
|
// attribute here to use a `Result` in Rust.
|
||||||
|
let ret = match ret {
|
||||||
|
IdlType::Void => None,
|
||||||
|
ret @ _ => {
|
||||||
|
match ret.to_syn_type(TypePosition::Return) {
|
||||||
|
Some(ret) => Some(ret),
|
||||||
|
None => {
|
||||||
|
warn!(
|
||||||
|
"Unsupported return type: {:?} on {:?}",
|
||||||
|
ret,
|
||||||
|
rust_name
|
||||||
|
);
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let js_ret = ret.clone();
|
||||||
|
let ret = if catch {
|
||||||
|
Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty))
|
||||||
|
} else {
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(backend::ast::ImportFunction {
|
||||||
|
function: backend::ast::Function {
|
||||||
|
name: js_name.to_string(),
|
||||||
|
arguments,
|
||||||
|
ret: ret.clone(),
|
||||||
|
rust_attrs: vec![],
|
||||||
|
rust_vis: public(),
|
||||||
|
},
|
||||||
|
rust_name: rust_ident(rust_name),
|
||||||
|
js_ret: js_ret.clone(),
|
||||||
|
catch,
|
||||||
|
structural,
|
||||||
|
shim:{
|
||||||
|
let ns = match kind {
|
||||||
|
backend::ast::ImportFunctionKind::ScopedMethod { .. } |
|
||||||
|
backend::ast::ImportFunctionKind::Normal => "",
|
||||||
|
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
||||||
|
};
|
||||||
|
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
||||||
|
},
|
||||||
|
kind,
|
||||||
|
doc_comment,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert arguments to ones suitable crating function
|
/// Convert arguments to ones suitable crating function
|
||||||
@ -600,32 +626,20 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
is_structural: bool,
|
is_structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
global: bool,
|
global: bool,
|
||||||
) -> Vec<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let ret = match ty.to_idl_type(self) {
|
let kind = backend::ast::OperationKind::Getter(Some(raw_ident(name)));
|
||||||
None => return Vec::new(),
|
let kind = self.import_function_kind(self_name, global, is_static, kind);
|
||||||
Some(idl_type) => idl_type,
|
let ret = ty.to_idl_type(self)?;
|
||||||
};
|
self.create_one_function(
|
||||||
let operation = backend::ast::Operation {
|
&name,
|
||||||
is_static,
|
&name.to_snake_case(),
|
||||||
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
None.into_iter(),
|
||||||
};
|
&ret,
|
||||||
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
kind,
|
||||||
|
is_structural,
|
||||||
let kind = if global {
|
catch,
|
||||||
backend::ast::ImportFunctionKind::ScopedMethod {
|
Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))))
|
||||||
ty,
|
)
|
||||||
operation,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
backend::ast::ImportFunctionKind::Method {
|
|
||||||
class: self_name.to_string(),
|
|
||||||
ty,
|
|
||||||
kind: backend::ast::MethodKind::Operation(operation),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
|
||||||
|
|
||||||
self.create_function(name, false, false, &[], ret, kind, is_structural, catch, doc_comment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a wasm-bindgen setter method, if possible.
|
/// Create a wasm-bindgen setter method, if possible.
|
||||||
@ -638,14 +652,35 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
is_structural: bool,
|
is_structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
global: bool,
|
global: bool,
|
||||||
) -> Vec<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
|
let kind = backend::ast::OperationKind::Setter(Some(raw_ident(name)));
|
||||||
|
let kind = self.import_function_kind(self_name, global, is_static, kind);
|
||||||
|
let field_ty = field_ty.to_idl_type(self)?;
|
||||||
|
self.create_one_function(
|
||||||
|
&name,
|
||||||
|
&format!("set_{}", name).to_snake_case(),
|
||||||
|
Some((name, &field_ty)).into_iter(),
|
||||||
|
&IdlType::Void,
|
||||||
|
kind,
|
||||||
|
is_structural,
|
||||||
|
catch,
|
||||||
|
Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name))))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_function_kind(
|
||||||
|
&self,
|
||||||
|
self_name: &str,
|
||||||
|
global: bool,
|
||||||
|
is_static: bool,
|
||||||
|
operation_kind: backend::ast::OperationKind,
|
||||||
|
) -> backend::ast::ImportFunctionKind {
|
||||||
let operation = backend::ast::Operation {
|
let operation = backend::ast::Operation {
|
||||||
is_static,
|
is_static,
|
||||||
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
kind: operation_kind,
|
||||||
};
|
};
|
||||||
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||||
|
if global {
|
||||||
let kind = if global {
|
|
||||||
backend::ast::ImportFunctionKind::ScopedMethod {
|
backend::ast::ImportFunctionKind::ScopedMethod {
|
||||||
ty,
|
ty,
|
||||||
operation,
|
operation,
|
||||||
@ -656,27 +691,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
ty,
|
ty,
|
||||||
kind: backend::ast::MethodKind::Operation(operation),
|
kind: backend::ast::MethodKind::Operation(operation),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
let doc_comment = Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
|
||||||
|
|
||||||
self.create_function(
|
|
||||||
&format!("set_{}", name),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
&[(
|
|
||||||
name,
|
|
||||||
match field_ty.to_idl_type(self) {
|
|
||||||
None => return Vec::new(),
|
|
||||||
Some(idl_type) => idl_type,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
)],
|
|
||||||
IdlType::Void,
|
|
||||||
kind,
|
|
||||||
is_structural,
|
|
||||||
catch,
|
|
||||||
doc_comment,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user