2018-08-03 14:39:33 -07:00
|
|
|
use std::iter::FromIterator;
|
2018-06-14 02:03:52 -07:00
|
|
|
|
|
|
|
use backend;
|
2018-08-04 15:16:02 -07:00
|
|
|
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
|
2018-07-10 22:59:59 -07:00
|
|
|
use heck::{CamelCase, SnakeCase};
|
2018-06-25 10:41:33 -07:00
|
|
|
use proc_macro2::Ident;
|
2018-06-14 02:03:52 -07:00
|
|
|
use syn;
|
2018-08-03 14:39:33 -07:00
|
|
|
use weedle;
|
|
|
|
use weedle::attribute::{ExtendedAttributeList, ExtendedAttribute};
|
|
|
|
use weedle::argument::{Argument, SingleArgument};
|
|
|
|
use weedle::common::Identifier;
|
|
|
|
use weedle::types::*;
|
|
|
|
use weedle::literal::{ConstValue, FloatLit, IntegerLit};
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2018-07-13 21:46:36 -07:00
|
|
|
use first_pass::FirstPassRecord;
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Take a type and create an immutable shared reference to that type.
|
2018-06-14 02:03:52 -07:00
|
|
|
fn shared_ref(ty: syn::Type) -> syn::Type {
|
|
|
|
syn::TypeReference {
|
|
|
|
and_token: Default::default(),
|
|
|
|
lifetime: None,
|
|
|
|
mutability: None,
|
|
|
|
elem: Box::new(ty),
|
|
|
|
}.into()
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:57:24 +01:00
|
|
|
/// Fix camelcase of identifiers like HTMLBRElement
|
|
|
|
pub fn camel_case_ident(identifier: &str) -> String {
|
|
|
|
identifier.replace("HTML", "HTML_").to_camel_case()
|
|
|
|
}
|
|
|
|
|
2018-07-29 17:12:36 +01:00
|
|
|
// Returns a link to MDN
|
|
|
|
pub fn mdn_doc(class: &str, method: Option<&str>) -> String {
|
|
|
|
let mut link = format!("https://developer.mozilla.org/en-US/docs/Web/API/{}", class);
|
|
|
|
if let Some(method) = method {
|
|
|
|
link.push_str(&format!("/{}", method));
|
|
|
|
}
|
|
|
|
format!("[Documentation]({})", link).into()
|
|
|
|
}
|
2018-07-27 17:57:24 +01:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
pub(crate) trait ToSynType<'src> {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src, T: ToSynType<'src>> ToSynType<'src> for MayBeNull<T> {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
let ty = self.type_.to_syn_type(record, pos)?;
|
|
|
|
if self.q_mark.is_some() {
|
|
|
|
Some(option_ty(ty))
|
|
|
|
} else {
|
|
|
|
Some(ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for ConstType<'src> {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
ConstType::Integer(l) => l.to_syn_type(record, pos),
|
|
|
|
ConstType::FloatingPoint(l) => l.to_syn_type(record, pos),
|
|
|
|
ConstType::Boolean(l) => l.to_syn_type(record, pos),
|
|
|
|
ConstType::Byte(l) => l.to_syn_type(record, pos),
|
|
|
|
ConstType::Octet(l) => l.to_syn_type(record, pos),
|
|
|
|
ConstType::Identifier(l) => l.to_syn_type(record, pos),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for IntegerType {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
IntegerType::LongLong(l) => l.to_syn_type(record, pos),
|
|
|
|
IntegerType::Long(l) => l.to_syn_type(record, pos),
|
|
|
|
IntegerType::Short(l) => l.to_syn_type(record, pos),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for ShortType {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
if self.unsigned.is_some() {
|
|
|
|
Some(ident_ty(raw_ident("u16")))
|
|
|
|
} else {
|
|
|
|
Some(ident_ty(raw_ident("i16")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for LongType {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
if self.unsigned.is_some() {
|
|
|
|
Some(ident_ty(raw_ident("u32")))
|
|
|
|
} else {
|
|
|
|
Some(ident_ty(raw_ident("i32")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-13 06:04:40 +02:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> ToSynType<'src> for LongLongType {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
if self.unsigned.is_some() {
|
|
|
|
Some(ident_ty(raw_ident("u64")))
|
|
|
|
} else {
|
|
|
|
Some(ident_ty(raw_ident("i64")))
|
|
|
|
}
|
2018-07-13 06:04:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> ToSynType<'src> for FloatingPointType {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
FloatingPointType::Float(_) => Some(ident_ty(raw_ident("f32"))),
|
|
|
|
FloatingPointType::Double(_) => Some(ident_ty(raw_ident("f64"))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Boolean {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(ident_ty(raw_ident("bool")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Byte {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(ident_ty(raw_ident("i8")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Octet {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(ident_ty(raw_ident("u8")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::common::Identifier<'src> {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
if let Some(other) = record.typedefs.get(&self.0) {
|
|
|
|
return other.to_syn_type(record, pos)
|
|
|
|
}
|
|
|
|
// A reference to a type by name becomes the same thing in the
|
|
|
|
// bindings.
|
|
|
|
let ty = ident_ty(rust_ident(camel_case_ident(self.0).as_str()));
|
|
|
|
Some(if record.interfaces.contains_key(self.0) {
|
|
|
|
if pos == TypePosition::Argument {
|
|
|
|
shared_ref(ty)
|
|
|
|
} else {
|
|
|
|
ty
|
|
|
|
}
|
|
|
|
} else if record.dictionaries.contains(self.0) {
|
|
|
|
ty
|
|
|
|
} else if record.enums.contains(self.0) {
|
|
|
|
ty
|
|
|
|
} else {
|
|
|
|
warn!("unrecognized type {}", self.0);
|
|
|
|
ty
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-07-13 06:04:40 +02:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> ToSynType<'src> for weedle::term::DOMString {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
// strings -> `&str` for arguments and `String` for return
|
|
|
|
Some(match pos {
|
|
|
|
TypePosition::Argument => shared_ref(ident_ty(raw_ident("str"))),
|
|
|
|
TypePosition::Return => ident_ty(raw_ident("String")),
|
|
|
|
})
|
2018-07-13 06:04:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> ToSynType<'src> for weedle::term::ByteString {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
// ByteString maps to String in JS -
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/ByteString
|
|
|
|
weedle::term::DOMString.to_syn_type(record, pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::USVString {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
// USVString maps to String in JS -
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/USVString
|
|
|
|
weedle::term::DOMString.to_syn_type(record, pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Array type is borrowed for arguments (`&[T]`) and owned for return value (`Vec<T>`).
|
|
|
|
fn array(base_ty: &str, pos: TypePosition) -> syn::Type {
|
|
|
|
match pos {
|
|
|
|
TypePosition::Argument => {
|
|
|
|
shared_ref(slice_ty(ident_ty(raw_ident(base_ty))))
|
|
|
|
}
|
|
|
|
TypePosition::Return => {
|
|
|
|
vec_ty(ident_ty(raw_ident(base_ty)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Float32Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("f32", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Float64Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("f64", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Int8Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("i8", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Int16Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("i16", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Int32Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("i32", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Uint8Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("u8", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Uint8ClampedArray {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("u8", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Uint16Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("u16", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Uint32Array {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
Some(array("u32", pos))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::ArrayBuffer {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
let path = vec![rust_ident("js_sys"), rust_ident("ArrayBuffer")];
|
|
|
|
Some(leading_colon_path_ty(path))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::term::Object {
|
|
|
|
fn to_syn_type(&self, _record: &FirstPassRecord<'src>, _pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
let path = vec![rust_ident("js_sys"), rust_ident("Object")];
|
|
|
|
Some(leading_colon_path_ty(path))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> ToSynType<'src> for weedle::types::Type<'src> {
|
|
|
|
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
|
|
|
|
-> Option<syn::Type>
|
|
|
|
{
|
|
|
|
use weedle::types::NonAnyType::*;
|
|
|
|
let single = match self {
|
|
|
|
Type::Single(s) => s,
|
|
|
|
Type::Union(_) => return None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let ty = match single {
|
|
|
|
// `any` becomes `::wasm_bindgen::JsValue`.
|
|
|
|
SingleType::Any(_) => {
|
|
|
|
let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")];
|
|
|
|
return Some(leading_colon_path_ty(path))
|
|
|
|
}
|
|
|
|
SingleType::NonAny(other) => other,
|
|
|
|
};
|
|
|
|
|
|
|
|
match ty {
|
|
|
|
Boolean(s) => s.to_syn_type(record, pos),
|
|
|
|
Octet(s) => s.to_syn_type(record, pos),
|
|
|
|
Byte(s) => s.to_syn_type(record, pos),
|
|
|
|
Identifier(s) => s.to_syn_type(record, pos),
|
|
|
|
Integer(s) => s.to_syn_type(record, pos),
|
|
|
|
FloatingPoint(s) => s.to_syn_type(record, pos),
|
|
|
|
|
|
|
|
Float32Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Float64Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Int8Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Int16Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Int32Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Uint8Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Uint8ClampedArray(s) => s.to_syn_type(record, pos),
|
|
|
|
Uint16Array(s) => s.to_syn_type(record, pos),
|
|
|
|
Uint32Array(s) => s.to_syn_type(record, pos),
|
|
|
|
|
|
|
|
DOMString(s) => s.to_syn_type(record, pos),
|
|
|
|
ByteString(s) => s.to_syn_type(record, pos),
|
|
|
|
USVString(s) => s.to_syn_type(record, pos),
|
|
|
|
ArrayBuffer(b) => b.to_syn_type(record, pos),
|
|
|
|
Object(o) => o.to_syn_type(record, pos),
|
|
|
|
|
|
|
|
// Support for these types is not yet implemented, so skip
|
|
|
|
// generating any bindings for this function.
|
|
|
|
| DataView(_)
|
|
|
|
| Error(_)
|
|
|
|
| FrozenArrayType(_)
|
|
|
|
| Promise(_)
|
|
|
|
| RecordType(..)
|
|
|
|
| Sequence(_)
|
|
|
|
| Symbol(_) => {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Map a webidl const value to the correct wasm-bindgen const value
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> backend::ast::ConstValue {
|
|
|
|
use std::f64::{NEG_INFINITY, INFINITY, NAN};
|
|
|
|
use backend::ast;
|
|
|
|
|
2018-07-13 06:04:40 +02:00
|
|
|
match *v {
|
2018-08-03 14:39:33 -07:00
|
|
|
ConstValue::Boolean(b) => ast::ConstValue::BooleanLiteral(b.0),
|
|
|
|
ConstValue::Float(FloatLit::NegInfinity(_)) => {
|
|
|
|
ast::ConstValue::FloatLiteral(NEG_INFINITY)
|
|
|
|
}
|
|
|
|
ConstValue::Float(FloatLit::Infinity(_)) => {
|
|
|
|
ast::ConstValue::FloatLiteral(INFINITY)
|
|
|
|
}
|
|
|
|
ConstValue::Float(FloatLit::NaN(_)) => {
|
|
|
|
ast::ConstValue::FloatLiteral(NAN)
|
|
|
|
}
|
|
|
|
ConstValue::Float(FloatLit::Value(s)) => {
|
|
|
|
ast::ConstValue::FloatLiteral(s.0.parse().unwrap())
|
|
|
|
}
|
|
|
|
ConstValue::Integer(lit) => {
|
|
|
|
let mklit = |orig_text: &str, base: u32, offset: usize| {
|
|
|
|
let (negative, text) = if orig_text.starts_with("-") {
|
|
|
|
(true, &orig_text[1..])
|
|
|
|
} else {
|
|
|
|
(false, orig_text)
|
|
|
|
};
|
|
|
|
if text == "0" {
|
|
|
|
return ast::ConstValue::SignedIntegerLiteral(0)
|
|
|
|
}
|
|
|
|
let text = &text[offset..];
|
|
|
|
let n = u64::from_str_radix(text, base)
|
|
|
|
.unwrap_or_else(|_| panic!("literal too big: {}", orig_text));
|
|
|
|
if negative {
|
|
|
|
let n = if n > (i64::min_value() as u64).wrapping_neg() {
|
|
|
|
panic!("literal too big: {}", orig_text)
|
|
|
|
} else {
|
|
|
|
n.wrapping_neg() as i64
|
|
|
|
};
|
|
|
|
ast::ConstValue::SignedIntegerLiteral(n)
|
|
|
|
} else {
|
|
|
|
ast::ConstValue::UnsignedIntegerLiteral(n)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match lit {
|
|
|
|
IntegerLit::Hex(h) => mklit(h.0, 16, 2), // leading 0x
|
|
|
|
IntegerLit::Oct(h) => mklit(h.0, 8, 1), // leading 0
|
|
|
|
IntegerLit::Dec(h) => mklit(h.0, 10, 0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ConstValue::Null(_) => ast::ConstValue::Null,
|
2018-07-13 06:04:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `ident` and `Ty`, create `ident: Ty` for use in e.g. `fn(ident: Ty)`.
|
2018-06-14 02:03:52 -07:00
|
|
|
fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
|
|
|
|
syn::ArgCaptured {
|
|
|
|
pat: syn::Pat::Ident(syn::PatIdent {
|
|
|
|
by_ref: None,
|
|
|
|
mutability: None,
|
|
|
|
ident,
|
|
|
|
subpat: None,
|
|
|
|
}),
|
|
|
|
colon_token: Default::default(),
|
|
|
|
ty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create `()`.
|
2018-07-11 11:07:03 -07:00
|
|
|
fn unit_ty() -> syn::Type {
|
|
|
|
syn::Type::Tuple(syn::TypeTuple {
|
|
|
|
paren_token: Default::default(),
|
|
|
|
elems: syn::punctuated::Punctuated::new(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `T` create `Result<T, ::wasm_bindgen::JsValue>`.
|
2018-07-11 11:07:03 -07:00
|
|
|
fn result_ty(t: syn::Type) -> syn::Type {
|
|
|
|
let js_value = leading_colon_path_ty(vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]);
|
|
|
|
|
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
|
|
|
args: FromIterator::from_iter(vec![
|
|
|
|
syn::GenericArgument::Type(t),
|
|
|
|
syn::GenericArgument::Type(js_value),
|
|
|
|
]),
|
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Result");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `T` create `[T]`.
|
2018-07-18 17:59:24 -05:00
|
|
|
fn slice_ty(t: syn::Type) -> syn::Type {
|
|
|
|
syn::TypeSlice {
|
|
|
|
bracket_token: Default::default(),
|
|
|
|
elem: Box::new(t),
|
|
|
|
}.into()
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// From `T` create `Vec<T>`.
|
2018-07-18 17:59:24 -05:00
|
|
|
fn vec_ty(t: syn::Type) -> syn::Type {
|
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
|
|
|
args: FromIterator::from_iter(vec![
|
|
|
|
syn::GenericArgument::Type(t),
|
|
|
|
]),
|
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Vec");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
/// From `T` create `Option<T>`
|
|
|
|
fn option_ty(t: syn::Type) -> syn::Type {
|
|
|
|
let arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
|
|
|
colon2_token: None,
|
|
|
|
lt_token: Default::default(),
|
|
|
|
args: FromIterator::from_iter(vec![syn::GenericArgument::Type(t)]),
|
|
|
|
gt_token: Default::default(),
|
|
|
|
});
|
|
|
|
|
|
|
|
let ident = raw_ident("Option");
|
|
|
|
let seg = syn::PathSegment { ident, arguments };
|
|
|
|
let path: syn::Path = seg.into();
|
|
|
|
let ty = syn::TypePath { qself: None, path };
|
|
|
|
ty.into()
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Possible positions for a type in a function signature.
|
2018-07-10 22:59:59 -07:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum TypePosition {
|
|
|
|
Argument,
|
|
|
|
Return,
|
|
|
|
}
|
2018-06-14 02:03:52 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
/// Implemented on an AST type node to generate a snake case name.
|
|
|
|
trait TypeToString {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: TypeToString> TypeToString for MayBeNull<T> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
if self.q_mark.is_some() {
|
|
|
|
dst.push_str("opt_");
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
2018-08-03 14:39:33 -07:00
|
|
|
self.type_.type_to_string(record, dst);
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> TypeToString for weedle::types::ReturnType<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
2018-08-04 14:01:35 +03:00
|
|
|
match self {
|
2018-08-03 14:39:33 -07:00
|
|
|
weedle::types::ReturnType::Type(ty) => (*ty).type_to_string(record, dst),
|
|
|
|
weedle::types::ReturnType::Void(_) => dst.push_str("void"),
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::types::StringType {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
match self {
|
|
|
|
weedle::types::StringType::Byte(_) => dst.push_str("byte_str"),
|
|
|
|
weedle::types::StringType::DOM(_) => dst.push_str("dom_str"),
|
|
|
|
weedle::types::StringType::USV(_) => dst.push_str("usv_str"),
|
|
|
|
}
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Byte {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("i8");
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Octet {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("u8");
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Boolean {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("bool");
|
2018-08-04 14:01:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::USVString {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("usv_str");
|
|
|
|
}
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::ByteString {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("byte_str");
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::DOMString {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("dom_str");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Float32Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("f32_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Float64Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("f64_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Int8Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("i8_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Int16Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("i16_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Int32Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("i32_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Uint8Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("u8_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Uint8ClampedArray {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("u8_clamped_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Uint16Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("u16_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeToString for weedle::term::Uint32Array {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("u32_array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> TypeToString for weedle::common::Identifier<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
match record.typedefs.get(self.0) {
|
|
|
|
Some(other) => other.type_to_string(record, dst),
|
|
|
|
None => dst.push_str(&self.0.to_snake_case()),
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for IntegerType {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
2018-07-30 17:41:22 +03:00
|
|
|
match self {
|
2018-08-03 14:39:33 -07:00
|
|
|
IntegerType::LongLong(l) if l.unsigned.is_some() => dst.push_str("u64"),
|
|
|
|
IntegerType::LongLong(_) => dst.push_str("i64"),
|
|
|
|
IntegerType::Long(l) if l.unsigned.is_some() => dst.push_str("u32"),
|
|
|
|
IntegerType::Long(_) => dst.push_str("i32"),
|
|
|
|
IntegerType::Short(l) if l.unsigned.is_some() => dst.push_str("u16"),
|
|
|
|
IntegerType::Short(_) => dst.push_str("i16"),
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for FloatingPointType {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
2018-07-30 17:41:22 +03:00
|
|
|
match self {
|
2018-08-03 14:39:33 -07:00
|
|
|
FloatingPointType::Float(_) => dst.push_str("f32"),
|
|
|
|
FloatingPointType::Double(_) => dst.push_str("f64"),
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::ArrayBuffer {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("array_buffer");
|
|
|
|
}
|
|
|
|
}
|
2018-07-19 08:45:08 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Symbol {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("symbol");
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 22:59:59 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Object {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("object");
|
|
|
|
}
|
|
|
|
}
|
2018-07-10 22:59:59 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::DataView {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("data_view");
|
|
|
|
}
|
|
|
|
}
|
2018-07-18 17:59:24 -05:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl TypeToString for weedle::term::Error {
|
|
|
|
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("error");
|
|
|
|
}
|
|
|
|
}
|
2018-08-04 13:51:22 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> TypeToString for weedle::types::SequenceType<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("seq_");
|
|
|
|
self.generics.body.type_to_string(record, dst);
|
|
|
|
}
|
|
|
|
}
|
2018-08-04 15:05:31 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> TypeToString for weedle::types::PromiseType<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("promise_");
|
|
|
|
self.generics.body.type_to_string(record, dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> TypeToString for weedle::types::FrozenArrayType<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("frozen_array_");
|
|
|
|
self.generics.body.type_to_string(record, dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> TypeToString for weedle::types::RecordType<'src> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
dst.push_str("record_from_");
|
|
|
|
self.generics.body.0.type_to_string(record, dst);
|
|
|
|
dst.push_str("_to_");
|
|
|
|
self.generics.body.2.type_to_string(record, dst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TypeToString for weedle::types::Type<'a> {
|
|
|
|
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) {
|
|
|
|
use weedle::types::NonAnyType::*;
|
|
|
|
|
|
|
|
let single = match self {
|
|
|
|
Type::Single(s) => s,
|
|
|
|
Type::Union(_) => panic!("unions not supported"),
|
2018-07-19 14:44:23 -05:00
|
|
|
};
|
2018-07-25 11:42:01 +01:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
let ty = match single {
|
|
|
|
SingleType::Any(_) => return dst.push_str("any"),
|
|
|
|
SingleType::NonAny(other) => other,
|
|
|
|
};
|
|
|
|
|
|
|
|
match ty {
|
|
|
|
Boolean(s) => s.type_to_string(record, dst),
|
|
|
|
Octet(s) => s.type_to_string(record, dst),
|
|
|
|
Byte(s) => s.type_to_string(record, dst),
|
|
|
|
Identifier(s) => s.type_to_string(record, dst),
|
|
|
|
Integer(s) => s.type_to_string(record, dst),
|
|
|
|
FloatingPoint(s) => s.type_to_string(record, dst),
|
|
|
|
|
|
|
|
Float32Array(s) => s.type_to_string(record, dst),
|
|
|
|
Float64Array(s) => s.type_to_string(record, dst),
|
|
|
|
Int8Array(s) => s.type_to_string(record, dst),
|
|
|
|
Int16Array(s) => s.type_to_string(record, dst),
|
|
|
|
Int32Array(s) => s.type_to_string(record, dst),
|
|
|
|
Uint8Array(s) => s.type_to_string(record, dst),
|
|
|
|
Uint8ClampedArray(s) => s.type_to_string(record, dst),
|
|
|
|
Uint16Array(s) => s.type_to_string(record, dst),
|
|
|
|
Uint32Array(s) => s.type_to_string(record, dst),
|
|
|
|
|
|
|
|
DOMString(s) => s.type_to_string(record, dst),
|
|
|
|
ByteString(s) => s.type_to_string(record, dst),
|
|
|
|
USVString(s) => s.type_to_string(record, dst),
|
|
|
|
ArrayBuffer(s) => s.type_to_string(record, dst),
|
|
|
|
|
|
|
|
DataView(s) => s.type_to_string(record, dst),
|
|
|
|
Error(s) => s.type_to_string(record, dst),
|
|
|
|
FrozenArrayType(s) => s.type_to_string(record, dst),
|
|
|
|
Object(s) => s.type_to_string(record, dst),
|
|
|
|
Promise(s) => s.type_to_string(record, dst),
|
|
|
|
RecordType(s) => s.type_to_string(record, dst),
|
|
|
|
Sequence(s) => s.type_to_string(record, dst),
|
|
|
|
Symbol(s) => s.type_to_string(record, dst),
|
2018-07-19 14:44:23 -05:00
|
|
|
}
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
2018-08-03 14:39:33 -07:00
|
|
|
}
|
2018-06-14 19:21:33 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
impl<'src> FirstPassRecord<'src> {
|
2018-07-25 11:42:01 +01:00
|
|
|
/// 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.
|
2018-08-03 14:39:33 -07:00
|
|
|
fn webidl_arguments_to_syn_arg_captured(
|
2018-07-10 22:59:59 -07:00
|
|
|
&self,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments: &[Argument],
|
2018-07-10 22:59:59 -07:00
|
|
|
kind: &backend::ast::ImportFunctionKind,
|
|
|
|
) -> Option<Vec<syn::ArgCaptured>>
|
|
|
|
{
|
|
|
|
let mut res = if let backend::ast::ImportFunctionKind::Method {
|
|
|
|
ty,
|
|
|
|
kind:
|
|
|
|
backend::ast::MethodKind::Operation(backend::ast::Operation {
|
|
|
|
is_static: false, ..
|
|
|
|
}),
|
|
|
|
..
|
|
|
|
} = kind
|
2018-06-14 19:21:33 -07:00
|
|
|
{
|
2018-08-03 14:39:33 -07:00
|
|
|
let mut res = Vec::with_capacity(arguments.len() + 1);
|
2018-07-10 22:59:59 -07:00
|
|
|
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())));
|
|
|
|
res
|
|
|
|
} else {
|
2018-08-03 14:39:33 -07:00
|
|
|
Vec::with_capacity(arguments.len())
|
2018-07-10 22:59:59 -07:00
|
|
|
};
|
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
for argument in arguments {
|
|
|
|
let argument = match argument {
|
|
|
|
Argument::Single(arg) => arg,
|
|
|
|
Argument::Variadic(_) => return None,
|
|
|
|
};
|
|
|
|
match argument.type_.type_.to_syn_type(self, TypePosition::Argument) {
|
2018-07-10 22:59:59 -07:00
|
|
|
None => {
|
2018-08-03 14:39:33 -07:00
|
|
|
warn!("Argument's type is not yet supported: {:?}", argument);
|
2018-07-10 22:59:59 -07:00
|
|
|
return None;
|
|
|
|
}
|
2018-08-03 14:39:33 -07:00
|
|
|
Some(ty) => {
|
|
|
|
let name = argument.identifier.0.to_snake_case();
|
|
|
|
res.push(simple_fn_arg(rust_ident(&name), ty))
|
|
|
|
}
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen function, if possible.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn create_function(
|
2018-07-10 22:59:59 -07:00
|
|
|
&self,
|
|
|
|
name: &str,
|
2018-07-30 17:41:22 +03:00
|
|
|
overloaded: bool,
|
|
|
|
same_argument_names: bool,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments: &[Argument],
|
2018-07-10 22:59:59 -07:00
|
|
|
mut ret: Option<syn::Type>,
|
|
|
|
kind: backend::ast::ImportFunctionKind,
|
|
|
|
structural: bool,
|
|
|
|
catch: bool,
|
2018-07-29 17:12:36 +01:00
|
|
|
doc_comment: Option<String>,
|
2018-07-10 22:59:59 -07:00
|
|
|
) -> Option<backend::ast::ImportFunction>
|
|
|
|
{
|
2018-08-03 14:39:33 -07:00
|
|
|
let ast_arguments = self.webidl_arguments_to_syn_arg_captured(arguments, &kind)?;
|
|
|
|
|
2018-07-30 17:41:22 +03:00
|
|
|
let rust_name = rust_ident(
|
|
|
|
&if overloaded && !arguments.is_empty() {
|
2018-08-03 14:39:33 -07:00
|
|
|
let mut argument_type_names = String::new();
|
|
|
|
for arg in arguments {
|
|
|
|
let arg = match arg {
|
|
|
|
Argument::Single(single) => single,
|
|
|
|
Argument::Variadic(_) => return None,
|
|
|
|
};
|
|
|
|
if argument_type_names.len() > 0 {
|
|
|
|
argument_type_names.push_str("_and_");
|
|
|
|
}
|
|
|
|
if same_argument_names {
|
|
|
|
arg.type_.type_.type_to_string(self, &mut argument_type_names);
|
|
|
|
} else {
|
|
|
|
argument_type_names.push_str(&arg.identifier.0.to_snake_case());
|
|
|
|
}
|
|
|
|
}
|
2018-07-30 17:41:22 +03:00
|
|
|
if name == "new" {
|
|
|
|
"with_".to_owned() + &argument_type_names
|
|
|
|
} else {
|
|
|
|
name.to_snake_case() + "_with_" + &argument_type_names
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
name.to_snake_case()
|
|
|
|
}
|
|
|
|
);
|
2018-08-05 00:17:30 +02:00
|
|
|
let name = name.to_string();
|
2018-07-10 22:59:59 -07:00
|
|
|
|
|
|
|
let js_ret = ret.clone();
|
|
|
|
|
|
|
|
if catch {
|
2018-07-15 12:43:55 -04:00
|
|
|
ret = Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty))
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let shim = {
|
|
|
|
let ns = match kind {
|
|
|
|
backend::ast::ImportFunctionKind::Normal => "",
|
|
|
|
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
|
|
|
};
|
|
|
|
|
|
|
|
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns))
|
|
|
|
};
|
|
|
|
|
|
|
|
Some(backend::ast::ImportFunction {
|
|
|
|
function: backend::ast::Function {
|
|
|
|
name,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments: ast_arguments,
|
2018-07-10 22:59:59 -07:00
|
|
|
ret,
|
|
|
|
rust_attrs: vec![],
|
|
|
|
rust_vis: public(),
|
|
|
|
},
|
|
|
|
rust_name,
|
|
|
|
js_ret,
|
|
|
|
catch,
|
|
|
|
structural,
|
|
|
|
kind,
|
|
|
|
shim,
|
2018-07-29 17:12:36 +01:00
|
|
|
doc_comment,
|
2018-07-10 22:59:59 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen method, if possible.
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn create_basic_method(
|
|
|
|
&self,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments: &[weedle::argument::Argument],
|
2018-08-05 23:32:31 +03:00
|
|
|
operation_id: ::first_pass::OperationId,
|
2018-08-03 14:39:33 -07:00
|
|
|
return_type: &weedle::types::ReturnType,
|
2018-07-10 22:59:59 -07:00
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
2018-08-05 23:32:31 +03:00
|
|
|
structural: bool,
|
2018-07-10 22:59:59 -07:00
|
|
|
catch: bool,
|
|
|
|
) -> Option<backend::ast::ImportFunction> {
|
2018-07-30 17:41:22 +03:00
|
|
|
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
|
|
|
arguments,
|
2018-08-05 23:32:31 +03:00
|
|
|
&operation_id,
|
2018-07-30 17:41:22 +03:00
|
|
|
self_name,
|
|
|
|
);
|
|
|
|
|
2018-08-05 23:32:31 +03:00
|
|
|
let name = match &operation_id {
|
|
|
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
|
|
|
::first_pass::OperationId::Operation(name) => match name {
|
|
|
|
None => {
|
|
|
|
warn!("Operations without a name are unsupported");
|
|
|
|
return None;
|
|
|
|
}
|
2018-08-06 22:07:36 +03:00
|
|
|
Some(name) => name.to_string(),
|
2018-08-05 23:32:31 +03:00
|
|
|
},
|
2018-08-07 00:06:04 +03:00
|
|
|
::first_pass::OperationId::IndexingGetter => "get".to_string(),
|
|
|
|
::first_pass::OperationId::IndexingSetter => "set".to_string(),
|
|
|
|
::first_pass::OperationId::IndexingDeleter => "delete".to_string(),
|
2018-07-10 22:59:59 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
let kind = backend::ast::ImportFunctionKind::Method {
|
|
|
|
class: self_name.to_string(),
|
2018-07-27 17:57:24 +01:00
|
|
|
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
2018-07-10 22:59:59 -07:00
|
|
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
|
|
|
is_static,
|
2018-08-05 23:32:31 +03:00
|
|
|
kind: match &operation_id {
|
|
|
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
|
|
|
::first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
2018-08-07 00:06:04 +03:00
|
|
|
::first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
|
|
|
::first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
|
|
|
::first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
2018-08-05 23:32:31 +03:00
|
|
|
},
|
2018-07-10 22:59:59 -07:00
|
|
|
}),
|
|
|
|
};
|
|
|
|
|
|
|
|
let ret = match return_type {
|
2018-08-03 14:39:33 -07:00
|
|
|
weedle::types::ReturnType::Void(_) => None,
|
|
|
|
weedle::types::ReturnType::Type(ty) => {
|
|
|
|
match ty.to_syn_type(self, TypePosition::Return) {
|
2018-07-10 22:59:59 -07:00
|
|
|
None => {
|
|
|
|
warn!("Operation's return type is not yet supported: {:?}", ty);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(ty) => Some(ty),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2018-08-05 23:32:31 +03:00
|
|
|
let doc_comment = match &operation_id {
|
|
|
|
::first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
|
|
|
::first_pass::OperationId::Operation(_) => Some(
|
|
|
|
format!(
|
|
|
|
"The `{}()` method\n\n{}",
|
|
|
|
name,
|
|
|
|
mdn_doc(self_name, Some(&name))
|
|
|
|
)
|
|
|
|
),
|
2018-08-07 02:40:55 +03:00
|
|
|
::first_pass::OperationId::IndexingGetter => Some("The indexing getter\n\n".to_string()),
|
|
|
|
::first_pass::OperationId::IndexingSetter => Some("The indexing setter\n\n".to_string()),
|
|
|
|
::first_pass::OperationId::IndexingDeleter => Some("The indexing deleter\n\n".to_string()),
|
2018-08-05 23:32:31 +03:00
|
|
|
};
|
2018-07-10 22:59:59 -07:00
|
|
|
|
|
|
|
self.create_function(
|
|
|
|
&name,
|
2018-07-30 17:41:22 +03:00
|
|
|
overloaded,
|
|
|
|
same_argument_names,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments,
|
2018-07-10 22:59:59 -07:00
|
|
|
ret,
|
|
|
|
kind,
|
2018-08-05 23:32:31 +03:00
|
|
|
structural,
|
2018-07-10 22:59:59 -07:00
|
|
|
catch,
|
2018-07-29 17:12:36 +01:00
|
|
|
doc_comment,
|
2018-07-10 22:59:59 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-07-30 17:41:22 +03:00
|
|
|
/// Whether operation is overloaded and
|
|
|
|
/// whether there overloads with same argument names for given argument types
|
|
|
|
pub fn get_operation_overloading(
|
|
|
|
&self,
|
2018-08-03 14:39:33 -07:00
|
|
|
arguments: &[weedle::argument::Argument],
|
2018-08-05 23:32:31 +03:00
|
|
|
id: &::first_pass::OperationId,
|
2018-07-30 17:41:22 +03:00
|
|
|
self_name: &str,
|
|
|
|
) -> (bool, bool) {
|
2018-08-03 14:39:33 -07:00
|
|
|
let data = match self.interfaces.get(self_name) {
|
|
|
|
Some(data) => data,
|
|
|
|
None => return (false, false),
|
|
|
|
};
|
2018-08-06 22:07:36 +03:00
|
|
|
let data = match data.operations.get(id) {
|
2018-08-03 14:39:33 -07:00
|
|
|
Some(data) => data,
|
|
|
|
None => return (false, false),
|
|
|
|
};
|
|
|
|
let mut names = Vec::with_capacity(arguments.len());
|
|
|
|
for arg in arguments {
|
|
|
|
match arg {
|
|
|
|
Argument::Single(arg) => names.push(arg.identifier.0),
|
|
|
|
Argument::Variadic(_) => return (false, false),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(
|
|
|
|
data.overloaded,
|
|
|
|
*data
|
|
|
|
.argument_names_same
|
|
|
|
.get(&names)
|
|
|
|
.unwrap_or(&false)
|
|
|
|
)
|
2018-07-30 17:41:22 +03:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen getter method, if possible.
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn create_getter(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
2018-08-03 14:39:33 -07:00
|
|
|
ty: &weedle::types::Type,
|
2018-07-10 22:59:59 -07:00
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
|
|
|
is_structural: bool,
|
|
|
|
catch: bool,
|
|
|
|
) -> Option<backend::ast::ImportFunction> {
|
2018-08-03 14:39:33 -07:00
|
|
|
let ret = match ty.to_syn_type(self, TypePosition::Return) {
|
2018-07-10 22:59:59 -07:00
|
|
|
None => {
|
|
|
|
warn!("Attribute's type does not yet support reading: {:?}", ty);
|
2018-06-14 19:21:33 -07:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(ty) => Some(ty),
|
2018-07-10 22:59:59 -07:00
|
|
|
};
|
2018-06-14 19:21:33 -07:00
|
|
|
|
2018-07-10 22:59:59 -07:00
|
|
|
let kind = backend::ast::ImportFunctionKind::Method {
|
|
|
|
class: self_name.to_string(),
|
2018-07-27 17:57:24 +01:00
|
|
|
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
2018-07-10 22:59:59 -07:00
|
|
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
|
|
|
is_static,
|
|
|
|
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
|
|
|
}),
|
|
|
|
};
|
2018-07-29 17:12:36 +01:00
|
|
|
let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
2018-06-14 22:48:32 -07:00
|
|
|
|
2018-08-03 14:39:33 -07:00
|
|
|
self.create_function(name, false, false, &[], ret, kind, is_structural, catch, doc_comment)
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
2018-06-14 22:48:32 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a wasm-bindgen setter method, if possible.
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn create_setter(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
2018-08-03 14:39:33 -07:00
|
|
|
ty: weedle::types::Type,
|
2018-07-10 22:59:59 -07:00
|
|
|
self_name: &str,
|
|
|
|
is_static: bool,
|
|
|
|
is_structural: bool,
|
|
|
|
catch: bool,
|
|
|
|
) -> Option<backend::ast::ImportFunction> {
|
|
|
|
let kind = backend::ast::ImportFunctionKind::Method {
|
|
|
|
class: self_name.to_string(),
|
2018-07-27 17:57:24 +01:00
|
|
|
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
2018-07-10 22:59:59 -07:00
|
|
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
|
|
|
is_static,
|
|
|
|
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
|
|
|
}),
|
|
|
|
};
|
2018-07-29 17:12:36 +01:00
|
|
|
let doc_comment = Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
2018-07-10 22:59:59 -07:00
|
|
|
|
|
|
|
self.create_function(
|
|
|
|
&format!("set_{}", name),
|
2018-07-30 17:41:22 +03:00
|
|
|
false,
|
|
|
|
false,
|
2018-08-03 14:39:33 -07:00
|
|
|
&[Argument::Single(SingleArgument {
|
|
|
|
attributes: None,
|
|
|
|
optional: None,
|
|
|
|
type_: AttributedType {
|
|
|
|
attributes: None,
|
|
|
|
type_: ty,
|
|
|
|
},
|
|
|
|
identifier: Identifier(name),
|
|
|
|
default: None,
|
|
|
|
})],
|
2018-07-10 22:59:59 -07:00
|
|
|
None,
|
|
|
|
kind,
|
|
|
|
is_structural,
|
|
|
|
catch,
|
2018-07-29 17:12:36 +01:00
|
|
|
doc_comment,
|
2018-07-10 22:59:59 -07:00
|
|
|
)
|
|
|
|
}
|
2018-06-14 22:48:32 -07:00
|
|
|
}
|
2018-07-02 20:35:05 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Search for an attribute by name in some webidl object's attributes.
|
2018-08-03 14:39:33 -07:00
|
|
|
fn has_named_attribute(list: &Option<ExtendedAttributeList>, attribute: &str) -> bool {
|
|
|
|
let list = match list {
|
|
|
|
Some(list) => list,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
list.body.list.iter().any(|attr| match attr {
|
|
|
|
ExtendedAttribute::NoArgs(name) => (name.0).0 == attribute,
|
2018-07-10 22:59:59 -07:00
|
|
|
_ => false,
|
2018-07-02 20:35:05 -07:00
|
|
|
})
|
2018-07-07 10:20:31 -07:00
|
|
|
}
|
2018-07-09 16:35:25 -07:00
|
|
|
|
2018-07-17 22:23:17 -07:00
|
|
|
/// ChromeOnly is for things that are only exposed to privileged code in Firefox.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn is_chrome_only(ext_attrs: &Option<ExtendedAttributeList>) -> bool {
|
2018-07-17 22:23:17 -07:00
|
|
|
has_named_attribute(ext_attrs, "ChromeOnly")
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as a no interface object.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn is_no_interface_object(ext_attrs: &Option<ExtendedAttributeList>) -> bool {
|
2018-07-17 22:23:17 -07:00
|
|
|
has_named_attribute(ext_attrs, "NoInterfaceObject")
|
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as structural.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn is_structural(attrs: &Option<ExtendedAttributeList>) -> bool {
|
|
|
|
has_named_attribute(attrs, "Unforgeable")
|
2018-07-09 16:35:25 -07:00
|
|
|
}
|
2018-07-11 11:07:03 -07:00
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Whether a webidl object is marked as throwing.
|
2018-08-03 14:39:33 -07:00
|
|
|
pub fn throws(attrs: &Option<ExtendedAttributeList>) -> bool {
|
|
|
|
has_named_attribute(attrs, "Throws")
|
2018-07-10 22:59:59 -07:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:42:01 +01:00
|
|
|
/// Create a syn `pub` token
|
2018-07-10 22:59:59 -07:00
|
|
|
pub fn public() -> syn::Visibility {
|
|
|
|
syn::Visibility::Public(syn::VisPublic {
|
|
|
|
pub_token: Default::default(),
|
2018-07-11 11:07:03 -07:00
|
|
|
})
|
|
|
|
}
|