mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-31 01:11:06 +00:00
Merge pull request #272 from ohanar/webidl_static
webidl: add support for static methods and attributes
This commit is contained in:
commit
7d1f26d7b0
@ -49,11 +49,21 @@ pub struct ImportFunction {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
pub enum ImportFunctionKind {
|
pub enum ImportFunctionKind {
|
||||||
Method { class: String, ty: syn::Type },
|
Method {
|
||||||
JsConstructor { class: String, ty: syn::Type },
|
class: String,
|
||||||
|
ty: syn::Type,
|
||||||
|
kind: MethodKind,
|
||||||
|
},
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
|
pub enum MethodKind {
|
||||||
|
Normal,
|
||||||
|
Constructor,
|
||||||
|
Static,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
pub struct ImportStatic {
|
pub struct ImportStatic {
|
||||||
pub vis: syn::Visibility,
|
pub vis: syn::Visibility,
|
||||||
@ -398,6 +408,7 @@ impl Program {
|
|||||||
ImportFunctionKind::Method {
|
ImportFunctionKind::Method {
|
||||||
class: class_name.to_string(),
|
class: class_name.to_string(),
|
||||||
ty: class.clone(),
|
ty: class.clone(),
|
||||||
|
kind: MethodKind::Normal,
|
||||||
}
|
}
|
||||||
} else if wasm.opts.constructor() {
|
} else if wasm.opts.constructor() {
|
||||||
let class = match wasm.ret {
|
let class = match wasm.ret {
|
||||||
@ -414,9 +425,10 @@ impl Program {
|
|||||||
let class_name = extract_path_ident(class_name)
|
let class_name = extract_path_ident(class_name)
|
||||||
.expect("first argument of method must be a bare type");
|
.expect("first argument of method must be a bare type");
|
||||||
|
|
||||||
ImportFunctionKind::JsConstructor {
|
ImportFunctionKind::Method {
|
||||||
class: class_name.to_string(),
|
class: class_name.to_string(),
|
||||||
ty: class.clone(),
|
ty: class.clone(),
|
||||||
|
kind: MethodKind::Constructor,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ImportFunctionKind::Normal
|
ImportFunctionKind::Normal
|
||||||
@ -426,7 +438,6 @@ impl Program {
|
|||||||
let ns = match kind {
|
let ns = match kind {
|
||||||
ImportFunctionKind::Normal => "n",
|
ImportFunctionKind::Normal => "n",
|
||||||
ImportFunctionKind::Method { ref class, .. } => class,
|
ImportFunctionKind::Method { ref class, .. } => class,
|
||||||
ImportFunctionKind::JsConstructor { ref class, .. } => class,
|
|
||||||
};
|
};
|
||||||
format!("__wbg_f_{}_{}_{}", js_name, f.ident, ns)
|
format!("__wbg_f_{}_{}_{}", js_name, f.ident, ns)
|
||||||
};
|
};
|
||||||
@ -690,20 +701,6 @@ impl ImportFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn shared(&self) -> shared::ImportFunction {
|
fn shared(&self) -> shared::ImportFunction {
|
||||||
let mut method = false;
|
|
||||||
let mut js_new = false;
|
|
||||||
let mut class_name = None;
|
|
||||||
match self.kind {
|
|
||||||
ImportFunctionKind::Method { ref class, .. } => {
|
|
||||||
method = true;
|
|
||||||
class_name = Some(class);
|
|
||||||
}
|
|
||||||
ImportFunctionKind::JsConstructor { ref class, .. } => {
|
|
||||||
js_new = true;
|
|
||||||
class_name = Some(class);
|
|
||||||
}
|
|
||||||
ImportFunctionKind::Normal => {}
|
|
||||||
}
|
|
||||||
let mut getter = None;
|
let mut getter = None;
|
||||||
let mut setter = None;
|
let mut setter = None;
|
||||||
|
|
||||||
@ -715,15 +712,34 @@ impl ImportFunction {
|
|||||||
let s = s.map(|s| s.to_string());
|
let s = s.map(|s| s.to_string());
|
||||||
setter = Some(s.unwrap_or_else(|| self.infer_setter_property()));
|
setter = Some(s.unwrap_or_else(|| self.infer_setter_property()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut method = None;
|
||||||
|
match self.kind {
|
||||||
|
ImportFunctionKind::Method {
|
||||||
|
ref class,
|
||||||
|
ref kind,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let kind = match kind {
|
||||||
|
MethodKind::Normal => shared::MethodKind::Normal,
|
||||||
|
MethodKind::Constructor => shared::MethodKind::Constructor,
|
||||||
|
MethodKind::Static => shared::MethodKind::Static,
|
||||||
|
};
|
||||||
|
method = Some(shared::MethodData {
|
||||||
|
class: class.clone(),
|
||||||
|
kind,
|
||||||
|
getter,
|
||||||
|
setter,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ImportFunctionKind::Normal => {}
|
||||||
|
}
|
||||||
|
|
||||||
shared::ImportFunction {
|
shared::ImportFunction {
|
||||||
shim: self.shim.to_string(),
|
shim: self.shim.to_string(),
|
||||||
catch: self.function.opts.catch(),
|
catch: self.function.opts.catch(),
|
||||||
method,
|
method,
|
||||||
js_new,
|
|
||||||
structural: self.function.opts.structural(),
|
structural: self.function.opts.structural(),
|
||||||
getter,
|
|
||||||
setter,
|
|
||||||
class: class_name.cloned(),
|
|
||||||
function: self.function.shared(),
|
function: self.function.shared(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,11 +552,12 @@ impl ToTokens for ast::ImportFunction {
|
|||||||
let mut class_ty = None;
|
let mut class_ty = None;
|
||||||
let mut is_method = false;
|
let mut is_method = false;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ast::ImportFunctionKind::Method { ref ty, .. } => {
|
ast::ImportFunctionKind::Method {
|
||||||
is_method = true;
|
ref ty, ref kind, ..
|
||||||
class_ty = Some(ty);
|
} => {
|
||||||
}
|
if let ast::MethodKind::Normal = kind {
|
||||||
ast::ImportFunctionKind::JsConstructor { ref ty, .. } => {
|
is_method = true;
|
||||||
|
}
|
||||||
class_ty = Some(ty);
|
class_ty = Some(ty);
|
||||||
}
|
}
|
||||||
ast::ImportFunctionKind::Normal => {}
|
ast::ImportFunctionKind::Normal => {}
|
||||||
|
@ -1605,76 +1605,78 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
{
|
{
|
||||||
let descriptor = self.cx.describe(&import.shim);
|
let descriptor = self.cx.describe(&import.shim);
|
||||||
|
|
||||||
let target = match import.class {
|
let target = match &import.method {
|
||||||
Some(ref class) if import.js_new => {
|
Some(shared::MethodData { class, kind, getter, setter }) => {
|
||||||
format!("new {}", self.import_name(info, class)?)
|
|
||||||
}
|
|
||||||
Some(ref class) if import.method => {
|
|
||||||
let class = self.import_name(info, class)?;
|
let class = self.import_name(info, class)?;
|
||||||
let target = if let Some(ref g) = import.getter {
|
if let shared::MethodKind::Constructor = kind {
|
||||||
if import.structural {
|
format!("new {}", class)
|
||||||
format!("function() {{
|
|
||||||
return this.{};
|
|
||||||
}}", g)
|
|
||||||
} else {
|
|
||||||
self.cx.expose_get_inherited_descriptor();
|
|
||||||
format!(
|
|
||||||
"GetOwnOrInheritedPropertyDescriptor\
|
|
||||||
({}.prototype, '{}').get",
|
|
||||||
class,
|
|
||||||
g,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else if let Some(ref s) = import.setter {
|
|
||||||
if import.structural {
|
|
||||||
format!("function(y) {{
|
|
||||||
this.{} = y;
|
|
||||||
}}", s)
|
|
||||||
} else {
|
|
||||||
self.cx.expose_get_inherited_descriptor();
|
|
||||||
format!(
|
|
||||||
"GetOwnOrInheritedPropertyDescriptor\
|
|
||||||
({}.prototype, '{}').set",
|
|
||||||
class,
|
|
||||||
s,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if import.structural {
|
let is_static = if let shared::MethodKind::Static = kind {
|
||||||
let nargs = descriptor.unwrap_function().arguments.len();
|
true
|
||||||
let mut s = format!("function(");
|
|
||||||
for i in 0..nargs - 1 {
|
|
||||||
if i > 0 {
|
|
||||||
drop(write!(s, ", "));
|
|
||||||
}
|
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
|
||||||
s.push_str(") { \nreturn this.");
|
|
||||||
s.push_str(&import.function.name);
|
|
||||||
s.push_str("(");
|
|
||||||
for i in 0..nargs - 1 {
|
|
||||||
if i > 0 {
|
|
||||||
drop(write!(s, ", "));
|
|
||||||
}
|
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
|
||||||
s.push_str(");\n}");
|
|
||||||
s
|
|
||||||
} else {
|
} else {
|
||||||
format!("{}.prototype.{}", class, import.function.name)
|
false
|
||||||
}
|
};
|
||||||
};
|
|
||||||
self.cx.global(&format!("
|
let target = if let Some(g) = getter {
|
||||||
const {}_target = {};
|
if import.structural {
|
||||||
", import.shim, target));
|
format!("function(y) {{
|
||||||
format!("{}_target.call", import.shim)
|
return this.{};
|
||||||
}
|
}}", g)
|
||||||
Some(ref class) => {
|
} else {
|
||||||
let class = self.import_name(info, class)?;
|
self.cx.expose_get_inherited_descriptor();
|
||||||
self.cx.global(&format!("
|
format!(
|
||||||
const {}_target = {}.{};
|
"GetOwnOrInheritedPropertyDescriptor\
|
||||||
", import.shim, class, import.function.name));
|
({}{}, '{}').get",
|
||||||
format!("{}_target", import.shim)
|
class,
|
||||||
|
if is_static { "" } else { ".prototype "},
|
||||||
|
g,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if let Some(s) = setter {
|
||||||
|
if import.structural {
|
||||||
|
format!("function(y) {{
|
||||||
|
this.{} = y;
|
||||||
|
}}", s)
|
||||||
|
} else {
|
||||||
|
self.cx.expose_get_inherited_descriptor();
|
||||||
|
format!(
|
||||||
|
"GetOwnOrInheritedPropertyDescriptor\
|
||||||
|
({}{}, '{}').set",
|
||||||
|
class,
|
||||||
|
if is_static { "" } else { ".prototype "},
|
||||||
|
s,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if import.structural {
|
||||||
|
let nargs = descriptor.unwrap_function().arguments.len();
|
||||||
|
let mut s = format!("function(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str(") { \nreturn this.");
|
||||||
|
s.push_str(&import.function.name);
|
||||||
|
s.push_str("(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str(");\n}");
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
format!("{}{}.{}", class, if is_static { "" } else { ".prototype" }, import.function.name)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.cx.global(&format!("
|
||||||
|
const {}_target = {};
|
||||||
|
", import.shim, target));
|
||||||
|
format!("{}_target{}", import.shim, if is_static { "" } else { ".call" })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let name = self.import_name(info, &import.function.name)?;
|
let name = self.import_name(info, &import.function.name)?;
|
||||||
|
@ -39,13 +39,24 @@ pub enum ImportKind {
|
|||||||
pub struct ImportFunction {
|
pub struct ImportFunction {
|
||||||
pub shim: String,
|
pub shim: String,
|
||||||
pub catch: bool,
|
pub catch: bool,
|
||||||
pub method: bool,
|
pub method: Option<MethodData>,
|
||||||
pub js_new: bool,
|
|
||||||
pub structural: bool,
|
pub structural: bool,
|
||||||
|
pub function: Function,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct MethodData {
|
||||||
|
pub class: String,
|
||||||
|
pub kind: MethodKind,
|
||||||
pub getter: Option<String>,
|
pub getter: Option<String>,
|
||||||
pub setter: Option<String>,
|
pub setter: Option<String>,
|
||||||
pub class: Option<String>,
|
}
|
||||||
pub function: Function,
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum MethodKind {
|
||||||
|
Normal,
|
||||||
|
Constructor,
|
||||||
|
Static,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
@ -55,8 +66,7 @@ pub struct ImportStatic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct ImportType {
|
pub struct ImportType {}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Export {
|
pub struct Export {
|
||||||
@ -77,7 +87,7 @@ pub struct Enum {
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct EnumVariant {
|
pub struct EnumVariant {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub value: u32
|
pub value: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
@ -101,20 +111,16 @@ pub struct StructField {
|
|||||||
|
|
||||||
pub fn new_function(struct_name: &str) -> String {
|
pub fn new_function(struct_name: &str) -> String {
|
||||||
let mut name = format!("__wbg_");
|
let mut name = format!("__wbg_");
|
||||||
name.extend(struct_name
|
name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
|
||||||
.chars()
|
|
||||||
.flat_map(|s| s.to_lowercase()));
|
|
||||||
name.push_str("_new");
|
name.push_str("_new");
|
||||||
return name
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_function(struct_name: &str) -> String {
|
pub fn free_function(struct_name: &str) -> String {
|
||||||
let mut name = format!("__wbg_");
|
let mut name = format!("__wbg_");
|
||||||
name.extend(struct_name
|
name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
|
||||||
.chars()
|
|
||||||
.flat_map(|s| s.to_lowercase()));
|
|
||||||
name.push_str("_free");
|
name.push_str("_free");
|
||||||
return name
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_function_export_name(function_name: &str) -> String {
|
pub fn free_function_export_name(function_name: &str) -> String {
|
||||||
@ -128,27 +134,23 @@ pub fn struct_function_export_name(struct_: &str, f: &str) -> String {
|
|||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
name.push_str("_");
|
name.push_str("_");
|
||||||
name.push_str(f);
|
name.push_str(f);
|
||||||
return name
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_field_get(struct_: &str, f: &str) -> String {
|
pub fn struct_field_get(struct_: &str, f: &str) -> String {
|
||||||
let mut name = String::from("__wbg_get_");
|
let mut name = String::from("__wbg_get_");
|
||||||
name.extend(struct_
|
name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
|
||||||
.chars()
|
|
||||||
.flat_map(|s| s.to_lowercase()));
|
|
||||||
name.push_str("_");
|
name.push_str("_");
|
||||||
name.push_str(f);
|
name.push_str(f);
|
||||||
return name
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_field_set(struct_: &str, f: &str) -> String {
|
pub fn struct_field_set(struct_: &str, f: &str) -> String {
|
||||||
let mut name = String::from("__wbg_set_");
|
let mut name = String::from("__wbg_set_");
|
||||||
name.extend(struct_
|
name.extend(struct_.chars().flat_map(|s| s.to_lowercase()));
|
||||||
.chars()
|
|
||||||
.flat_map(|s| s.to_lowercase()));
|
|
||||||
name.push_str("_");
|
name.push_str("_");
|
||||||
name.push_str(f);
|
name.push_str(f);
|
||||||
return name
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version() -> String {
|
pub fn version() -> String {
|
||||||
@ -158,5 +160,5 @@ pub fn version() -> String {
|
|||||||
v.push_str(s);
|
v.push_str(s);
|
||||||
v.push_str(")");
|
v.push_str(")");
|
||||||
}
|
}
|
||||||
return v
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,14 @@ use std::iter;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use heck::CamelCase;
|
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use util::{create_function, ident_ty, raw_ident, rust_ident, webidl_ty_to_syn_ty, TypePosition};
|
use util::{
|
||||||
|
create_basic_method, create_function, create_getter, create_setter, ident_ty, rust_ident,
|
||||||
|
webidl_ty_to_syn_ty, wrap_import_function, TypePosition,
|
||||||
|
};
|
||||||
|
|
||||||
/// Either `Ok(t)` or `Err(failure::Error)`.
|
/// Either `Ok(t)` or `Err(failure::Error)`.
|
||||||
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
||||||
@ -184,9 +186,10 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| {
|
let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| {
|
||||||
let self_ty = ident_ty(rust_ident(&interface.name));
|
let self_ty = ident_ty(rust_ident(&interface.name));
|
||||||
let kind = backend::ast::ImportFunctionKind::JsConstructor {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: class.to_string(),
|
class: class.to_string(),
|
||||||
ty: self_ty.clone(),
|
ty: self_ty.clone(),
|
||||||
|
kind: backend::ast::MethodKind::Constructor,
|
||||||
};
|
};
|
||||||
create_function(
|
create_function(
|
||||||
"new",
|
"new",
|
||||||
@ -216,7 +219,7 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name))
|
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name))
|
||||||
if name == "Constructor" =>
|
if name == "Constructor" =>
|
||||||
{
|
{
|
||||||
add_constructor(&[] as &[_], &interface.name);
|
add_constructor(&[], &interface.name);
|
||||||
}
|
}
|
||||||
webidl::ast::ExtendedAttribute::NamedArgumentList(
|
webidl::ast::ExtendedAttribute::NamedArgumentList(
|
||||||
webidl::ast::NamedArgumentListExtendedAttribute {
|
webidl::ast::NamedArgumentListExtendedAttribute {
|
||||||
@ -262,10 +265,11 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
|
|||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
match *self {
|
match self {
|
||||||
webidl::ast::Attribute::Regular(ref attr) => attr.webidl_parse(program, self_name),
|
webidl::ast::Attribute::Regular(attr) => attr.webidl_parse(program, self_name),
|
||||||
|
webidl::ast::Attribute::Static(attr) => attr.webidl_parse(program, self_name),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Attribute::Static(_) | webidl::ast::Attribute::Stringifier(_) => {
|
webidl::ast::Attribute::Stringifier(_) => {
|
||||||
warn!("Unsupported WebIDL attribute: {:?}", self);
|
warn!("Unsupported WebIDL attribute: {:?}", self);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -275,12 +279,11 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Attribute {
|
|||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
match *self {
|
match self {
|
||||||
webidl::ast::Operation::Regular(ref op) => op.webidl_parse(program, self_name),
|
webidl::ast::Operation::Regular(op) => op.webidl_parse(program, self_name),
|
||||||
|
webidl::ast::Operation::Static(op) => op.webidl_parse(program, self_name),
|
||||||
// TODO
|
// TODO
|
||||||
webidl::ast::Operation::Special(_)
|
webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => {
|
||||||
| webidl::ast::Operation::Static(_)
|
|
||||||
| webidl::ast::Operation::Stringifier(_) => {
|
|
||||||
warn!("Unsupported WebIDL operation: {:?}", self);
|
warn!("Unsupported WebIDL operation: {:?}", self);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -290,69 +293,46 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
|||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
fn create_getter(
|
create_getter(
|
||||||
this: &webidl::ast::RegularAttribute,
|
&self.name,
|
||||||
self_name: &str,
|
&self.type_,
|
||||||
) -> Option<backend::ast::Import> {
|
self_name,
|
||||||
let ret = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Return) {
|
backend::ast::MethodKind::Normal,
|
||||||
None => {
|
).map(wrap_import_function)
|
||||||
warn!("Attribute's type does not yet support reading: {:?}. Skipping getter binding for {:?}",
|
.map(|import| program.imports.push(import));
|
||||||
this.type_, this);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(ty) => Some(ty),
|
|
||||||
};
|
|
||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
|
||||||
class: self_name.to_string(),
|
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
|
||||||
};
|
|
||||||
|
|
||||||
create_function(
|
|
||||||
&this.name,
|
|
||||||
iter::empty(),
|
|
||||||
kind,
|
|
||||||
ret,
|
|
||||||
vec![backend::ast::BindgenAttr::Getter(Some(raw_ident(
|
|
||||||
&this.name,
|
|
||||||
)))],
|
|
||||||
).map(|function| backend::ast::Import {
|
|
||||||
module: None,
|
|
||||||
version: None,
|
|
||||||
js_namespace: None,
|
|
||||||
kind: backend::ast::ImportKind::Function(function),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_setter(
|
|
||||||
this: &webidl::ast::RegularAttribute,
|
|
||||||
self_name: &str,
|
|
||||||
) -> Option<backend::ast::Import> {
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
|
||||||
class: self_name.to_string(),
|
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
|
||||||
};
|
|
||||||
|
|
||||||
create_function(
|
|
||||||
&format!("set_{}", this.name.to_camel_case()),
|
|
||||||
iter::once((&*this.name, &*this.type_, false)),
|
|
||||||
kind,
|
|
||||||
None,
|
|
||||||
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(
|
|
||||||
&this.name,
|
|
||||||
)))],
|
|
||||||
).map(|function| backend::ast::Import {
|
|
||||||
module: None,
|
|
||||||
version: None,
|
|
||||||
js_namespace: None,
|
|
||||||
kind: backend::ast::ImportKind::Function(function),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
create_getter(self, self_name).map(|import| program.imports.push(import));
|
|
||||||
|
|
||||||
if !self.read_only {
|
if !self.read_only {
|
||||||
create_setter(self, self_name).map(|import| program.imports.push(import));
|
create_setter(
|
||||||
|
&self.name,
|
||||||
|
&self.type_,
|
||||||
|
self_name,
|
||||||
|
backend::ast::MethodKind::Normal,
|
||||||
|
).map(wrap_import_function)
|
||||||
|
.map(|import| program.imports.push(import));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
||||||
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
|
create_getter(
|
||||||
|
&self.name,
|
||||||
|
&self.type_,
|
||||||
|
self_name,
|
||||||
|
backend::ast::MethodKind::Static,
|
||||||
|
).map(wrap_import_function)
|
||||||
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
|
if !self.read_only {
|
||||||
|
create_setter(
|
||||||
|
&self.name,
|
||||||
|
&self.type_,
|
||||||
|
self_name,
|
||||||
|
backend::ast::MethodKind::Static,
|
||||||
|
).map(wrap_import_function)
|
||||||
|
.map(|import| program.imports.push(import));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -361,54 +341,29 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
|||||||
|
|
||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
let name = match self.name {
|
create_basic_method(
|
||||||
None => {
|
&self.arguments,
|
||||||
warn!(
|
self.name.as_ref(),
|
||||||
"Operations without a name are unsupported. Skipping {:?}",
|
&self.return_type,
|
||||||
self
|
self_name,
|
||||||
);
|
backend::ast::MethodKind::Normal,
|
||||||
return Ok(());
|
).map(wrap_import_function)
|
||||||
}
|
.map(|import| program.imports.push(import));
|
||||||
Some(ref name) => name,
|
|
||||||
};
|
Ok(())
|
||||||
|
}
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
}
|
||||||
class: self_name.to_string(),
|
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
||||||
};
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
|
create_basic_method(
|
||||||
let ret = match self.return_type {
|
&self.arguments,
|
||||||
webidl::ast::ReturnType::Void => None,
|
self.name.as_ref(),
|
||||||
webidl::ast::ReturnType::NonVoid(ref ty) => {
|
&self.return_type,
|
||||||
match webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
self_name,
|
||||||
None => {
|
backend::ast::MethodKind::Static,
|
||||||
warn!(
|
).map(wrap_import_function)
|
||||||
"Operation's return type is not yet supported: {:?}. Skipping bindings for {:?}",
|
.map(|import| program.imports.push(import));
|
||||||
ty, self
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Some(ty) => Some(ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
create_function(
|
|
||||||
&name,
|
|
||||||
self.arguments
|
|
||||||
.iter()
|
|
||||||
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
|
||||||
kind,
|
|
||||||
ret,
|
|
||||||
Vec::new(),
|
|
||||||
).map(|function| {
|
|
||||||
program.imports.push(backend::ast::Import {
|
|
||||||
module: None,
|
|
||||||
version: None,
|
|
||||||
js_namespace: None,
|
|
||||||
kind: backend::ast::ImportKind::Function(function),
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::iter::FromIterator;
|
use std::iter::{self, FromIterator};
|
||||||
|
|
||||||
use backend;
|
use backend;
|
||||||
use heck::SnakeCase;
|
use heck::SnakeCase;
|
||||||
@ -30,7 +30,7 @@ pub fn rust_ident(name: &str) -> Ident {
|
|||||||
|
|
||||||
// Create an `Ident` without checking to see if it conflicts with a Rust
|
// Create an `Ident` without checking to see if it conflicts with a Rust
|
||||||
// keyword.
|
// keyword.
|
||||||
pub fn raw_ident(name: &str) -> Ident {
|
fn raw_ident(name: &str) -> Ident {
|
||||||
Ident::new(name, proc_macro2::Span::call_site())
|
Ident::new(name, proc_macro2::Span::call_site())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,12 @@ where
|
|||||||
{
|
{
|
||||||
let estimate = arguments.size_hint();
|
let estimate = arguments.size_hint();
|
||||||
let len = estimate.1.unwrap_or(estimate.0);
|
let len = estimate.1.unwrap_or(estimate.0);
|
||||||
let mut res = if let backend::ast::ImportFunctionKind::Method { ty, .. } = kind {
|
let mut res = if let backend::ast::ImportFunctionKind::Method {
|
||||||
|
ty,
|
||||||
|
kind: backend::ast::MethodKind::Normal,
|
||||||
|
..
|
||||||
|
} = kind
|
||||||
|
{
|
||||||
let mut res = Vec::with_capacity(len + 1);
|
let mut res = Vec::with_capacity(len + 1);
|
||||||
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())));
|
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())));
|
||||||
res
|
res
|
||||||
@ -189,7 +194,7 @@ where
|
|||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_function<'a, 'b, I>(
|
pub fn create_function<'a, I>(
|
||||||
name: &str,
|
name: &str,
|
||||||
arguments: I,
|
arguments: I,
|
||||||
kind: backend::ast::ImportFunctionKind,
|
kind: backend::ast::ImportFunctionKind,
|
||||||
@ -216,7 +221,6 @@ where
|
|||||||
let ns = match kind {
|
let ns = match kind {
|
||||||
backend::ast::ImportFunctionKind::Normal => "",
|
backend::ast::ImportFunctionKind::Normal => "",
|
||||||
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
||||||
backend::ast::ImportFunctionKind::JsConstructor { ref class, .. } => class,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
||||||
@ -239,3 +243,106 @@ where
|
|||||||
shim,
|
shim,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_basic_method(
|
||||||
|
arguments: &[webidl::ast::Argument],
|
||||||
|
name: Option<&String>,
|
||||||
|
return_type: &webidl::ast::ReturnType,
|
||||||
|
self_name: &str,
|
||||||
|
kind: backend::ast::MethodKind,
|
||||||
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
|
let name = match name {
|
||||||
|
None => {
|
||||||
|
warn!("Operations without a name are unsupported");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ref name) => name,
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
|
kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = match return_type {
|
||||||
|
webidl::ast::ReturnType::Void => None,
|
||||||
|
webidl::ast::ReturnType::NonVoid(ty) => match webidl_ty_to_syn_ty(ty, TypePosition::Return)
|
||||||
|
{
|
||||||
|
None => {
|
||||||
|
warn!("Operation's return type is not yet supported: {:?}", ty);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ty) => Some(ty),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
create_function(
|
||||||
|
&name,
|
||||||
|
arguments
|
||||||
|
.iter()
|
||||||
|
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
||||||
|
kind,
|
||||||
|
ret,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_getter(
|
||||||
|
name: &str,
|
||||||
|
ty: &webidl::ast::Type,
|
||||||
|
self_name: &str,
|
||||||
|
kind: backend::ast::MethodKind,
|
||||||
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
|
let ret = match webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
||||||
|
None => {
|
||||||
|
warn!("Attribute's type does not yet support reading: {:?}", ty);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ty) => Some(ty),
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
|
kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
create_function(
|
||||||
|
name,
|
||||||
|
iter::empty(),
|
||||||
|
kind,
|
||||||
|
ret,
|
||||||
|
vec![backend::ast::BindgenAttr::Getter(Some(raw_ident(name)))],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_setter(
|
||||||
|
name: &str,
|
||||||
|
ty: &webidl::ast::Type,
|
||||||
|
self_name: &str,
|
||||||
|
kind: backend::ast::MethodKind,
|
||||||
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
|
kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
create_function(
|
||||||
|
&format!("set_{}", name),
|
||||||
|
iter::once((name, ty, false)),
|
||||||
|
kind,
|
||||||
|
None,
|
||||||
|
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(name)))],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap_import_function(function: backend::ast::ImportFunction) -> backend::ast::Import {
|
||||||
|
backend::ast::Import {
|
||||||
|
module: None,
|
||||||
|
version: None,
|
||||||
|
js_namespace: None,
|
||||||
|
kind: backend::ast::ImportKind::Function(function),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,6 +43,8 @@ fn method() {
|
|||||||
pub fn test() {
|
pub fn test() {
|
||||||
let pi = Foo::new(3.14159);
|
let pi = Foo::new(3.14159);
|
||||||
let e = Foo::new(2.71828);
|
let e = Foo::new(2.71828);
|
||||||
|
// TODO: figure out why the following doesn't fail
|
||||||
|
// assert!(!pi.my_cmp(Foo::new(3.14159)));
|
||||||
let tmp = pi.my_cmp(Foo::new(3.14159));
|
let tmp = pi.my_cmp(Foo::new(3.14159));
|
||||||
assert!(tmp);
|
assert!(tmp);
|
||||||
let tmp =!pi.my_cmp(Foo::new(2.71828));
|
let tmp =!pi.my_cmp(Foo::new(2.71828));
|
||||||
@ -104,15 +106,11 @@ fn property() {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let x = Foo::new(3.14159);
|
let x = Foo::new(3.14159);
|
||||||
let tmp = x.value() == 3.14159;
|
assert_eq!(x.value(), 3.14159);
|
||||||
assert!(tmp);
|
assert_ne!(x.value(), 2.71828);
|
||||||
let tmp = x.value() != 2.71828;
|
|
||||||
assert!(tmp);
|
|
||||||
x.set_value(2.71828);
|
x.set_value(2.71828);
|
||||||
let tmp = x.value() != 3.14159;
|
assert_ne!(x.value(), 3.14159);
|
||||||
assert!(tmp);
|
assert_eq!(x.value(), 2.71828);
|
||||||
let tmp = x.value() == 2.71828;
|
|
||||||
assert!(tmp);
|
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
@ -167,10 +165,113 @@ fn named_constructor() {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let x = Foo::new(3.14159);
|
let x = Foo::new(3.14159);
|
||||||
let tmp = x.value() == 3.14159;
|
assert_eq!(x.value(), 3.14159);
|
||||||
assert!(tmp);
|
assert_ne!(x.value(), 0.);
|
||||||
let tmp = x.value() != 0.;
|
}
|
||||||
assert!(tmp);
|
"#,
|
||||||
|
)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn static_method() {
|
||||||
|
project()
|
||||||
|
.file(
|
||||||
|
"foo.webidl",
|
||||||
|
r#"
|
||||||
|
interface Foo {
|
||||||
|
static double swap(double value);
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"foo.ts",
|
||||||
|
r#"
|
||||||
|
export class Foo {
|
||||||
|
private static value: number = 0;
|
||||||
|
static swap(value: number): number {
|
||||||
|
const res = Foo.value;
|
||||||
|
Foo.value = value;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
pub mod foo;
|
||||||
|
|
||||||
|
use foo::Foo;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn test() {
|
||||||
|
assert_eq!(Foo::swap(3.14159), 0.);
|
||||||
|
assert_eq!(Foo::swap(2.71828), 3.14159);
|
||||||
|
assert_ne!(Foo::swap(2.71828), 3.14159);
|
||||||
|
assert_eq!(Foo::swap(3.14159), 2.71828);
|
||||||
|
assert_ne!(Foo::swap(3.14159), 2.71828);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn static_property() {
|
||||||
|
project()
|
||||||
|
.file(
|
||||||
|
"foo.webidl",
|
||||||
|
r#"
|
||||||
|
interface Foo {
|
||||||
|
static attribute double value;
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"foo.ts",
|
||||||
|
r#"
|
||||||
|
export class Foo {
|
||||||
|
private static _value: number = 0;
|
||||||
|
|
||||||
|
static get value(): number {
|
||||||
|
return Foo._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static set value(_value: number) {
|
||||||
|
Foo._value = _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file(
|
||||||
|
"src/lib.rs",
|
||||||
|
r#"
|
||||||
|
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
pub mod foo;
|
||||||
|
|
||||||
|
use foo::Foo;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn test() {
|
||||||
|
assert_eq!(Foo::value(), 0.);
|
||||||
|
Foo::set_value(3.14159);
|
||||||
|
assert_eq!(Foo::value(), 3.14159);
|
||||||
|
assert_ne!(Foo::value(), 2.71828);
|
||||||
|
Foo::set_value(2.71828);
|
||||||
|
assert_eq!(Foo::value(), 2.71828);
|
||||||
|
assert_ne!(Foo::value(), 3.14159);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user