mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-12 04:21:21 +00:00
@ -1,3 +1,12 @@
|
||||
//! Because some WebIDL constructs are defined in multiple places
|
||||
//! (keyword `partial` is used to add to an existing construct),
|
||||
//! We need to first walk the webidl to collect all non-partial
|
||||
//! constructs so that we have containers in which to put the
|
||||
//! partial ones.
|
||||
//!
|
||||
//! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can
|
||||
//! be partial.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet}, mem,
|
||||
};
|
||||
@ -6,21 +15,30 @@ use webidl;
|
||||
|
||||
use super::Result;
|
||||
|
||||
/// Collection of constructs that may use partial.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FirstPassRecord<'a> {
|
||||
pub(crate) interfaces: BTreeSet<String>,
|
||||
pub(crate) dictionaries: BTreeSet<String>,
|
||||
pub(crate) enums: BTreeSet<String>,
|
||||
/// The mixins, mapping their name to the webidl ast node for the mixin.
|
||||
pub(crate) mixins: BTreeMap<String, MixinData<'a>>,
|
||||
}
|
||||
|
||||
/// We need to collect mixin data during the first pass, to be used later.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct MixinData<'a> {
|
||||
/// The non partial mixin, if present. If there is more than one, we are
|
||||
/// parsing is a malformed WebIDL file, but the parser will recover by
|
||||
/// using the last parsed mixin.
|
||||
pub(crate) non_partial: Option<&'a webidl::ast::NonPartialMixin>,
|
||||
/// 0 or more partial mixins.
|
||||
pub(crate) partials: Vec<&'a webidl::ast::PartialMixin>,
|
||||
}
|
||||
|
||||
/// Implemented on an AST node to populate the `FirstPassRecord` struct.
|
||||
pub(crate) trait FirstPass {
|
||||
/// Populate `record` with any constructs in `self`.
|
||||
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()>;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ pub fn compile(webidl_source: &str) -> Result<String> {
|
||||
Ok(compile_ast(ast))
|
||||
}
|
||||
|
||||
/// Run codegen on the AST to generate rust code.
|
||||
fn compile_ast(mut ast: backend::ast::Program) -> String {
|
||||
let mut defined = BTreeSet::from_iter(
|
||||
vec![
|
||||
@ -96,7 +97,9 @@ fn compile_ast(mut ast: backend::ast::Program) -> String {
|
||||
tokens.to_string()
|
||||
}
|
||||
|
||||
/// The main trait for parsing WebIDL AST into wasm-bindgen AST.
|
||||
trait WebidlParse<Ctx> {
|
||||
/// Parse `self` into wasm-bindgen AST, and insert it into `program`.
|
||||
fn webidl_parse(
|
||||
&self,
|
||||
program: &mut backend::ast::Program,
|
||||
|
@ -10,6 +10,7 @@ use webidl::ast::ExtendedAttribute;
|
||||
|
||||
use first_pass::FirstPassRecord;
|
||||
|
||||
/// Take a type and create an immutable shared reference to that type.
|
||||
fn shared_ref(ty: syn::Type) -> syn::Type {
|
||||
syn::TypeReference {
|
||||
and_token: Default::default(),
|
||||
@ -19,6 +20,7 @@ fn shared_ref(ty: syn::Type) -> syn::Type {
|
||||
}.into()
|
||||
}
|
||||
|
||||
/// For a webidl const type node, get the corresponding syn type node.
|
||||
pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type {
|
||||
use webidl::ast::ConstType::*;
|
||||
|
||||
@ -39,6 +41,7 @@ pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map a webidl const value to the correct wasm-bindgen const value
|
||||
pub fn webidl_const_v_to_backend_const_v(v: &webidl::ast::ConstValue) -> backend::ast::ConstValue {
|
||||
match *v {
|
||||
webidl::ast::ConstValue::BooleanLiteral(b) => backend::ast::ConstValue::BooleanLiteral(b),
|
||||
@ -49,6 +52,7 @@ pub fn webidl_const_v_to_backend_const_v(v: &webidl::ast::ConstValue) -> backend
|
||||
}
|
||||
}
|
||||
|
||||
/// From `ident` and `Ty`, create `ident: Ty` for use in e.g. `fn(ident: Ty)`.
|
||||
fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
|
||||
syn::ArgCaptured {
|
||||
pat: syn::Pat::Ident(syn::PatIdent {
|
||||
@ -62,6 +66,7 @@ fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create `()`.
|
||||
fn unit_ty() -> syn::Type {
|
||||
syn::Type::Tuple(syn::TypeTuple {
|
||||
paren_token: Default::default(),
|
||||
@ -69,6 +74,7 @@ fn unit_ty() -> syn::Type {
|
||||
})
|
||||
}
|
||||
|
||||
/// From `T` create `Result<T, ::wasm_bindgen::JsValue>`.
|
||||
fn result_ty(t: syn::Type) -> syn::Type {
|
||||
let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]);
|
||||
|
||||
@ -89,6 +95,7 @@ fn result_ty(t: syn::Type) -> syn::Type {
|
||||
ty.into()
|
||||
}
|
||||
|
||||
/// From `T` create `[T]`.
|
||||
fn slice_ty(t: syn::Type) -> syn::Type {
|
||||
syn::TypeSlice {
|
||||
bracket_token: Default::default(),
|
||||
@ -96,6 +103,7 @@ fn slice_ty(t: syn::Type) -> syn::Type {
|
||||
}.into()
|
||||
}
|
||||
|
||||
/// From `T` create `Vec<T>`.
|
||||
fn vec_ty(t: syn::Type) -> syn::Type {
|
||||
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
@ -113,6 +121,7 @@ fn vec_ty(t: syn::Type) -> syn::Type {
|
||||
ty.into()
|
||||
}
|
||||
|
||||
/// Possible positions for a type in a function signature.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum TypePosition {
|
||||
Argument,
|
||||
@ -120,11 +129,14 @@ pub enum TypePosition {
|
||||
}
|
||||
|
||||
impl<'a> FirstPassRecord<'a> {
|
||||
/// Use information from the first pass to work out the correct Rust type to use for
|
||||
/// a given WebIDL type.
|
||||
pub fn webidl_ty_to_syn_ty(
|
||||
&self,
|
||||
ty: &webidl::ast::Type,
|
||||
pos: TypePosition,
|
||||
) -> Option<syn::Type> {
|
||||
// Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec<T>`).
|
||||
let array = |base_ty: &str| {
|
||||
match pos {
|
||||
TypePosition::Argument => {
|
||||
@ -220,6 +232,8 @@ impl<'a> FirstPassRecord<'a> {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Map nullable to an option.
|
||||
if ty.nullable {
|
||||
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
@ -240,6 +254,10 @@ impl<'a> FirstPassRecord<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the first pass to convert webidl function arguments to rust arguments.
|
||||
///
|
||||
/// `kind` is whether the function is a method, in which case we would need a `self`
|
||||
/// parameter.
|
||||
fn webidl_arguments_to_syn_arg_captured<'b, I>(
|
||||
&self,
|
||||
arguments: I,
|
||||
@ -284,6 +302,7 @@ impl<'a> FirstPassRecord<'a> {
|
||||
Some(res)
|
||||
}
|
||||
|
||||
/// Create a wasm-bindgen function, if possible.
|
||||
pub fn create_function<'b, I>(
|
||||
&self,
|
||||
name: &str,
|
||||
@ -333,6 +352,7 @@ impl<'a> FirstPassRecord<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a wasm-bindgen method, if possible.
|
||||
pub fn create_basic_method(
|
||||
&self,
|
||||
arguments: &[webidl::ast::Argument],
|
||||
@ -384,6 +404,7 @@ impl<'a> FirstPassRecord<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a wasm-bindgen getter method, if possible.
|
||||
pub fn create_getter(
|
||||
&self,
|
||||
name: &str,
|
||||
@ -413,6 +434,7 @@ impl<'a> FirstPassRecord<'a> {
|
||||
self.create_function(name, iter::empty(), ret, kind, is_structural, catch)
|
||||
}
|
||||
|
||||
/// Create a wasm-bindgen setter method, if possible.
|
||||
pub fn create_setter(
|
||||
&self,
|
||||
name: &str,
|
||||
@ -442,6 +464,7 @@ impl<'a> FirstPassRecord<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Search for an attribute by name in some webidl object's attributes.
|
||||
fn has_named_attribute(ext_attrs: &[Box<ExtendedAttribute>], attribute: &str) -> bool {
|
||||
ext_attrs.iter().any(|attr| match &**attr {
|
||||
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
||||
@ -456,10 +479,12 @@ pub fn is_chrome_only(ext_attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
has_named_attribute(ext_attrs, "ChromeOnly")
|
||||
}
|
||||
|
||||
/// Whether a webidl object is marked as a no interface object.
|
||||
pub fn is_no_interface_object(ext_attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
has_named_attribute(ext_attrs, "NoInterfaceObject")
|
||||
}
|
||||
|
||||
/// Whether a webidl object is marked as structural.
|
||||
pub fn is_structural(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
attrs.iter().any(|attr| match &**attr {
|
||||
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
||||
@ -469,6 +494,7 @@ pub fn is_structural(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether a webidl object is marked as throwing.
|
||||
pub fn throws(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
attrs.iter().any(|attr| match &**attr {
|
||||
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => name == "Throws",
|
||||
@ -476,6 +502,7 @@ pub fn throws(attrs: &[Box<ExtendedAttribute>]) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a syn `pub` token
|
||||
pub fn public() -> syn::Visibility {
|
||||
syn::Visibility::Public(syn::VisPublic {
|
||||
pub_token: Default::default(),
|
||||
|
Reference in New Issue
Block a user