mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 18:20:51 +00:00
Migrate to IdlType
This commit is contained in:
parent
2c0e13a033
commit
e92374a8c8
675
crates/webidl/src/idl_type.rs
Normal file
675
crates/webidl/src/idl_type.rs
Normal file
@ -0,0 +1,675 @@
|
||||
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
|
||||
use heck::SnakeCase;
|
||||
use syn;
|
||||
use weedle::common::Identifier;
|
||||
use weedle::term;
|
||||
use weedle::types::*;
|
||||
|
||||
use first_pass::FirstPassRecord;
|
||||
use util::{TypePosition, camel_case_ident, shared_ref, option_ty, array};
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
||||
pub(crate) enum IdlType<'a> {
|
||||
Boolean,
|
||||
Byte,
|
||||
Octet,
|
||||
Short,
|
||||
UnsignedShort,
|
||||
Long,
|
||||
UnsignedLong,
|
||||
LongLong,
|
||||
UnsignedLongLong,
|
||||
Float,
|
||||
UnrestrictedFloat,
|
||||
Double,
|
||||
UnrestrictedDouble,
|
||||
DomString,
|
||||
ByteString,
|
||||
UsvString,
|
||||
Object,
|
||||
Symbol,
|
||||
Error,
|
||||
|
||||
ArrayBuffer,
|
||||
DataView,
|
||||
Int8Array,
|
||||
Uint8Array,
|
||||
Uint8ClampedArray,
|
||||
Int16Array,
|
||||
Uint16Array,
|
||||
Int32Array,
|
||||
Uint32Array,
|
||||
Float32Array,
|
||||
Float64Array,
|
||||
|
||||
Interface(&'a str),
|
||||
Dictionary(&'a str),
|
||||
Enum(&'a str),
|
||||
|
||||
Nullable(Box<IdlType<'a>>),
|
||||
FrozenArray(Box<IdlType<'a>>),
|
||||
Sequence(Box<IdlType<'a>>),
|
||||
Promise(Box<IdlType<'a>>),
|
||||
Record(Box<IdlType<'a>>, Box<IdlType<'a>>),
|
||||
Union(Vec<IdlType<'a>>),
|
||||
|
||||
Any,
|
||||
Void,
|
||||
}
|
||||
|
||||
pub(crate) trait ToIdlType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>>;
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for UnionType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
let mut idl_types = Vec::with_capacity(self.body.list.len());
|
||||
for t in &self.body.list {
|
||||
idl_types.push(t.to_idl_type(record)?);
|
||||
}
|
||||
Some(IdlType::Union(idl_types))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for Type<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
Type::Single(t) => t.to_idl_type(record),
|
||||
Type::Union(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for SingleType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
SingleType::Any(t) => t.to_idl_type(record),
|
||||
SingleType::NonAny(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for NonAnyType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
NonAnyType::Promise(t) => t.to_idl_type(record),
|
||||
NonAnyType::Integer(t) => t.to_idl_type(record),
|
||||
NonAnyType::FloatingPoint(t) => t.to_idl_type(record),
|
||||
NonAnyType::Boolean(t) => t.to_idl_type(record),
|
||||
NonAnyType::Byte(t) => t.to_idl_type(record),
|
||||
NonAnyType::Octet(t) => t.to_idl_type(record),
|
||||
NonAnyType::ByteString(t) => t.to_idl_type(record),
|
||||
NonAnyType::DOMString(t) => t.to_idl_type(record),
|
||||
NonAnyType::USVString(t) => t.to_idl_type(record),
|
||||
NonAnyType::Sequence(t) => t.to_idl_type(record),
|
||||
NonAnyType::Object(t) => t.to_idl_type(record),
|
||||
NonAnyType::Symbol(t) => t.to_idl_type(record),
|
||||
NonAnyType::Error(t) => t.to_idl_type(record),
|
||||
NonAnyType::ArrayBuffer(t) => t.to_idl_type(record),
|
||||
NonAnyType::DataView(t) => t.to_idl_type(record),
|
||||
NonAnyType::Int8Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Int16Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Int32Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Uint8Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Uint16Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Uint32Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Uint8ClampedArray(t) => t.to_idl_type(record),
|
||||
NonAnyType::Float32Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::Float64Array(t) => t.to_idl_type(record),
|
||||
NonAnyType::FrozenArrayType(t) => t.to_idl_type(record),
|
||||
NonAnyType::RecordType(t) => t.to_idl_type(record),
|
||||
NonAnyType::Identifier(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for SequenceType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
Some(IdlType::Sequence(Box::new(self.generics.body.to_idl_type(record)?)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for FrozenArrayType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
Some(IdlType::FrozenArray(Box::new(self.generics.body.to_idl_type(record)?)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ToIdlType<'a>> ToIdlType<'a> for MayBeNull<T> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
let inner_idl_type = self.type_.to_idl_type(record)?;
|
||||
if self.q_mark.is_some() {
|
||||
Some(IdlType::Nullable(Box::new(inner_idl_type)))
|
||||
} else {
|
||||
Some(inner_idl_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for PromiseType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
Some(IdlType::Promise(Box::new(self.generics.body.to_idl_type(record)?)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for IntegerType {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
IntegerType::LongLong(t) => t.to_idl_type(record),
|
||||
IntegerType::Long(t) => t.to_idl_type(record),
|
||||
IntegerType::Short(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for LongLongType {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if self.unsigned.is_some() {
|
||||
Some(IdlType::UnsignedLongLong)
|
||||
} else {
|
||||
Some(IdlType::LongLong)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for LongType {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if self.unsigned.is_some() {
|
||||
Some(IdlType::UnsignedLong)
|
||||
} else {
|
||||
Some(IdlType::Long)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for ShortType {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if self.unsigned.is_some() {
|
||||
Some(IdlType::UnsignedShort)
|
||||
} else {
|
||||
Some(IdlType::Short)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for FloatingPointType {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
FloatingPointType::Float(t) => t.to_idl_type(record),
|
||||
FloatingPointType::Double(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for FloatType {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if self.unrestricted.is_some() {
|
||||
Some(IdlType::UnrestrictedFloat)
|
||||
} else {
|
||||
Some(IdlType::Float)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for DoubleType {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if self.unrestricted.is_some() {
|
||||
Some(IdlType::UnrestrictedDouble)
|
||||
} else {
|
||||
Some(IdlType::Double)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for RecordType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
Some(
|
||||
IdlType::Record(
|
||||
Box::new(self.generics.body.0.to_idl_type(record)?),
|
||||
Box::new(self.generics.body.2.to_idl_type(record)?)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for StringType {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
StringType::Byte(t) => t.to_idl_type(record),
|
||||
StringType::DOM(t) => t.to_idl_type(record),
|
||||
StringType::USV(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for UnionMemberType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
UnionMemberType::Single(t) => t.to_idl_type(record),
|
||||
UnionMemberType::Union(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for ConstType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
ConstType::Integer(t) => t.to_idl_type(record),
|
||||
ConstType::FloatingPoint(t) => t.to_idl_type(record),
|
||||
ConstType::Boolean(t) => t.to_idl_type(record),
|
||||
ConstType::Byte(t) => t.to_idl_type(record),
|
||||
ConstType::Octet(t) => t.to_idl_type(record),
|
||||
ConstType::Identifier(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for ReturnType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
match self {
|
||||
ReturnType::Void(t) => t.to_idl_type(record),
|
||||
ReturnType::Type(t) => t.to_idl_type(record),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for AttributedType<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
self.type_.to_idl_type(record)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToIdlType<'a> for Identifier<'a> {
|
||||
fn to_idl_type(&self, record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
if let Some(idl_type) = record.typedefs.get(&self.0) {
|
||||
idl_type.to_idl_type(record)
|
||||
} else if record.interfaces.contains_key(self.0) {
|
||||
Some(IdlType::Interface(self.0))
|
||||
} else if record.dictionaries.contains(self.0) {
|
||||
Some(IdlType::Dictionary(self.0))
|
||||
} else if record.enums.contains(self.0) {
|
||||
Some(IdlType::Enum(self.0))
|
||||
} else {
|
||||
warn!("unrecognized type {}", self.0);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! terms_to_idl_type {
|
||||
($($t:tt => $r:tt)*) => ($(
|
||||
impl<'a> ToIdlType<'a> for term::$t {
|
||||
fn to_idl_type(&self, _record: &FirstPassRecord<'a>) -> Option<IdlType<'a>> {
|
||||
Some(IdlType::$r)
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
terms_to_idl_type! {
|
||||
Symbol => Symbol
|
||||
ByteString => ByteString
|
||||
DOMString => DomString
|
||||
USVString => UsvString
|
||||
Any => Any
|
||||
Boolean => Boolean
|
||||
Byte => Byte
|
||||
Double => Double
|
||||
Float => Float
|
||||
Long => Long
|
||||
Object => Object
|
||||
Octet => Octet
|
||||
Short => Short
|
||||
Void => Void
|
||||
ArrayBuffer => ArrayBuffer
|
||||
DataView => DataView
|
||||
Int8Array => Int8Array
|
||||
Int16Array => Int16Array
|
||||
Int32Array => Int32Array
|
||||
Uint8Array => Uint8Array
|
||||
Uint16Array => Uint16Array
|
||||
Uint32Array => Uint32Array
|
||||
Uint8ClampedArray => Uint8ClampedArray
|
||||
Float32Array => Float32Array
|
||||
Float64Array => Float64Array
|
||||
Error => Error
|
||||
}
|
||||
|
||||
impl<'a> IdlType<'a> {
|
||||
/// Generates a snake case type name.
|
||||
pub(crate) fn push_type_name(&self, dst: &mut String) {
|
||||
match self {
|
||||
IdlType::Boolean => dst.push_str("bool"),
|
||||
IdlType::Byte => dst.push_str("i8"),
|
||||
IdlType::Octet => dst.push_str("u8"),
|
||||
IdlType::Short => dst.push_str("i16"),
|
||||
IdlType::UnsignedShort => dst.push_str("u16"),
|
||||
IdlType::Long => dst.push_str("i32"),
|
||||
IdlType::UnsignedLong => dst.push_str("u32"),
|
||||
IdlType::LongLong => dst.push_str("i64"),
|
||||
IdlType::UnsignedLongLong => dst.push_str("u64"),
|
||||
IdlType::Float => dst.push_str("f32"),
|
||||
IdlType::UnrestrictedFloat => dst.push_str("unrestricted_f32"),
|
||||
IdlType::Double => dst.push_str("f64"),
|
||||
IdlType::UnrestrictedDouble => dst.push_str("unrestricted_f64"),
|
||||
IdlType::DomString => dst.push_str("dom_str"),
|
||||
IdlType::ByteString => dst.push_str("byte_str"),
|
||||
IdlType::UsvString => dst.push_str("usv_str"),
|
||||
IdlType::Object => dst.push_str("object"),
|
||||
IdlType::Symbol => dst.push_str("symbol"),
|
||||
IdlType::Error => dst.push_str("error"),
|
||||
|
||||
IdlType::ArrayBuffer => dst.push_str("array_buffer"),
|
||||
IdlType::DataView => dst.push_str("data_view"),
|
||||
IdlType::Int8Array => dst.push_str("i8_array"),
|
||||
IdlType::Uint8Array => dst.push_str("u8_array"),
|
||||
IdlType::Uint8ClampedArray => dst.push_str("u8_clamped_array"),
|
||||
IdlType::Int16Array => dst.push_str("i16_array"),
|
||||
IdlType::Uint16Array => dst.push_str("u16_array"),
|
||||
IdlType::Int32Array => dst.push_str("i32_array"),
|
||||
IdlType::Uint32Array => dst.push_str("u32_array"),
|
||||
IdlType::Float32Array => dst.push_str("f32_array"),
|
||||
IdlType::Float64Array => dst.push_str("f64_array"),
|
||||
|
||||
IdlType::Interface(name) => dst.push_str(&name.to_snake_case()),
|
||||
IdlType::Dictionary(name) => dst.push_str(&name.to_snake_case()),
|
||||
IdlType::Enum(name) => dst.push_str(&name.to_snake_case()),
|
||||
|
||||
IdlType::Nullable(idl_type) => {
|
||||
dst.push_str("opt_");
|
||||
idl_type.push_type_name(dst);
|
||||
},
|
||||
IdlType::FrozenArray(idl_type) => {
|
||||
idl_type.push_type_name(dst);
|
||||
dst.push_str("_frozen_array");
|
||||
},
|
||||
IdlType::Sequence(idl_type) => {
|
||||
idl_type.push_type_name(dst);
|
||||
dst.push_str("_sequence");
|
||||
},
|
||||
IdlType::Promise(idl_type) => {
|
||||
idl_type.push_type_name(dst);
|
||||
dst.push_str("_promise");
|
||||
},
|
||||
IdlType::Record(idl_type_from, idl_type_to) => {
|
||||
dst.push_str("record_from_");
|
||||
idl_type_from.push_type_name(dst);
|
||||
dst.push_str("_to_");
|
||||
idl_type_to.push_type_name(dst);
|
||||
},
|
||||
IdlType::Union(idl_types) => {
|
||||
dst.push_str("union_of_");
|
||||
let mut first = true;
|
||||
for idl_type in idl_types {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
dst.push_str("_and_");
|
||||
}
|
||||
idl_type.push_type_name(dst);
|
||||
}
|
||||
},
|
||||
|
||||
IdlType::Any => dst.push_str("any"),
|
||||
IdlType::Void => dst.push_str("void"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a snake case type name.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_type_name(&self) -> String {
|
||||
let mut string = String::new();
|
||||
self.push_type_name(&mut string);
|
||||
return string;
|
||||
}
|
||||
|
||||
/// Converts to syn type if possible.
|
||||
pub(crate) fn to_syn_type(&self, pos: TypePosition) -> Option<syn::Type> {
|
||||
match self {
|
||||
IdlType::Boolean => Some(ident_ty(raw_ident("bool"))),
|
||||
IdlType::Byte => Some(ident_ty(raw_ident("i8"))),
|
||||
IdlType::Octet => Some(ident_ty(raw_ident("u8"))),
|
||||
IdlType::Short => Some(ident_ty(raw_ident("i16"))),
|
||||
IdlType::UnsignedShort => Some(ident_ty(raw_ident("u16"))),
|
||||
IdlType::Long => Some(ident_ty(raw_ident("i32"))),
|
||||
IdlType::UnsignedLong => Some(ident_ty(raw_ident("u32"))),
|
||||
IdlType::LongLong => Some(ident_ty(raw_ident("i64"))),
|
||||
IdlType::UnsignedLongLong => Some(ident_ty(raw_ident("u64"))),
|
||||
IdlType::Float => Some(ident_ty(raw_ident("f32"))),
|
||||
IdlType::UnrestrictedFloat => Some(ident_ty(raw_ident("f32"))),
|
||||
IdlType::Double => Some(ident_ty(raw_ident("f64"))),
|
||||
IdlType::UnrestrictedDouble => Some(ident_ty(raw_ident("f64"))),
|
||||
| IdlType::DomString
|
||||
| IdlType::ByteString
|
||||
| IdlType::UsvString => match pos {
|
||||
TypePosition::Argument => Some(shared_ref(ident_ty(raw_ident("str")))),
|
||||
TypePosition::Return => Some(ident_ty(raw_ident("String"))),
|
||||
},
|
||||
IdlType::Object => {
|
||||
let path = vec![rust_ident("js_sys"), rust_ident("Object")];
|
||||
Some(leading_colon_path_ty(path))
|
||||
},
|
||||
IdlType::Symbol => None,
|
||||
IdlType::Error => None,
|
||||
|
||||
IdlType::ArrayBuffer => {
|
||||
let path = vec![rust_ident("js_sys"), rust_ident("ArrayBuffer")];
|
||||
Some(leading_colon_path_ty(path))
|
||||
},
|
||||
IdlType::DataView => None,
|
||||
IdlType::Int8Array => Some(array("i8", pos)),
|
||||
IdlType::Uint8Array => Some(array("u8", pos)),
|
||||
IdlType::Uint8ClampedArray => Some(array("u8", pos)),
|
||||
IdlType::Int16Array => Some(array("i16", pos)),
|
||||
IdlType::Uint16Array => Some(array("u16", pos)),
|
||||
IdlType::Int32Array => Some(array("i32", pos)),
|
||||
IdlType::Uint32Array => Some(array("u32", pos)),
|
||||
IdlType::Float32Array => Some(array("f32", pos)),
|
||||
IdlType::Float64Array => Some(array("f64", pos)),
|
||||
|
||||
IdlType::Interface(name) => {
|
||||
let ty = ident_ty(rust_ident(camel_case_ident(name).as_str()));
|
||||
if pos == TypePosition::Argument {
|
||||
Some(shared_ref(ty))
|
||||
} else {
|
||||
Some(ty)
|
||||
}
|
||||
},
|
||||
IdlType::Dictionary(name) => Some(ident_ty(rust_ident(camel_case_ident(name).as_str()))),
|
||||
IdlType::Enum(name) => Some(ident_ty(rust_ident(camel_case_ident(name).as_str()))),
|
||||
|
||||
IdlType::Nullable(idl_type) => Some(option_ty(idl_type.to_syn_type(pos)?)),
|
||||
IdlType::FrozenArray(_idl_type) => None,
|
||||
IdlType::Sequence(_idl_type) => None,
|
||||
IdlType::Promise(_idl_type) => None,
|
||||
IdlType::Record(_idl_type_from, _idl_type_to) => None,
|
||||
IdlType::Union(_idl_types) => None,
|
||||
|
||||
IdlType::Any => {
|
||||
let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")];
|
||||
Some(leading_colon_path_ty(path))
|
||||
},
|
||||
IdlType::Void => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Flattens unions recursively.
|
||||
///
|
||||
/// Works similarly to [flattened union member types],
|
||||
/// but also flattens unions inside generics of other types.
|
||||
///
|
||||
/// [flattened union member types]: https://heycam.github.io/webidl/#dfn-flattened-union-member-types
|
||||
pub(crate) fn flatten(&self) -> Vec<Self> {
|
||||
match self {
|
||||
IdlType::Nullable(idl_type) => idl_type
|
||||
.flatten()
|
||||
.into_iter()
|
||||
.map(Box::new)
|
||||
.map(IdlType::Nullable)
|
||||
.collect(),
|
||||
IdlType::FrozenArray(idl_type) => idl_type
|
||||
.flatten()
|
||||
.into_iter()
|
||||
.map(Box::new)
|
||||
.map(IdlType::FrozenArray)
|
||||
.collect(),
|
||||
IdlType::Sequence(idl_type) => idl_type
|
||||
.flatten()
|
||||
.into_iter()
|
||||
.map(Box::new)
|
||||
.map(IdlType::Sequence)
|
||||
.collect(),
|
||||
IdlType::Promise(idl_type) => idl_type
|
||||
.flatten()
|
||||
.into_iter()
|
||||
.map(Box::new)
|
||||
.map(IdlType::Promise)
|
||||
.collect(),
|
||||
IdlType::Record(idl_type_from, idl_type_to) => {
|
||||
let mut idl_types = Vec::new();
|
||||
for idl_type_from in idl_type_from.flatten() {
|
||||
for idl_type_to in idl_type_to.flatten() {
|
||||
idl_types.push(
|
||||
IdlType::Record(
|
||||
Box::new(idl_type_from.clone()),
|
||||
Box::new(idl_type_to.clone())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
idl_types
|
||||
},
|
||||
IdlType::Union(idl_types) => idl_types
|
||||
.iter()
|
||||
.flat_map(|idl_type| idl_type.flatten())
|
||||
.collect(),
|
||||
|
||||
idl_type @ _ => vec![idl_type.clone()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idl_type_flatten_test() {
|
||||
use self::IdlType::*;
|
||||
|
||||
assert_eq!(
|
||||
Union(vec![
|
||||
Interface("Node"),
|
||||
Union(vec![
|
||||
Sequence(
|
||||
Box::new(Long),
|
||||
),
|
||||
Interface("Event"),
|
||||
]),
|
||||
Nullable(
|
||||
Box::new(Union(vec![
|
||||
Interface("XMLHttpRequest"),
|
||||
DomString,
|
||||
])),
|
||||
),
|
||||
Sequence(
|
||||
Box::new(Union(vec![
|
||||
Sequence(
|
||||
Box::new(Double),
|
||||
),
|
||||
Interface("NodeList"),
|
||||
])),
|
||||
),
|
||||
]).flatten(),
|
||||
vec![
|
||||
Interface("Node"),
|
||||
Sequence(Box::new(Long)),
|
||||
Interface("Event"),
|
||||
Nullable(Box::new(Interface("XMLHttpRequest"))),
|
||||
Nullable(Box::new(DomString)),
|
||||
Sequence(Box::new(Sequence(Box::new(Double)))),
|
||||
Sequence(Box::new(Interface("NodeList"))),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Converts arguments into possibilities.
|
||||
///
|
||||
/// Each argument represented with a tuple of its idl type and whether it is optional.
|
||||
/// Each possibility is a vector of idl types.
|
||||
///
|
||||
/// The goal is to find equivalent possibilities of argument types each of which is not optional and
|
||||
/// does not contains union types.
|
||||
pub(crate) fn flatten<'a>(arguments: &'a [(IdlType, bool)]) -> Vec<Vec<IdlType<'a>>> {
|
||||
if arguments.is_empty() {
|
||||
return vec![Vec::new()];
|
||||
}
|
||||
let mut optional_possibilities = if arguments[0].1 { vec![Vec::new()] } else { Vec::new() };
|
||||
let mut possibilities = Vec::new();
|
||||
for idl_type in arguments[0].0.flatten() {
|
||||
possibilities.push(vec![idl_type])
|
||||
}
|
||||
for argument in arguments[1..].iter() {
|
||||
let mut new_possibilities = Vec::new();
|
||||
for old_idl_types in possibilities {
|
||||
if argument.1 {
|
||||
optional_possibilities.push(old_idl_types.clone());
|
||||
}
|
||||
for idl_type in argument.0.flatten() {
|
||||
let mut new_idl_types = old_idl_types.clone();
|
||||
new_idl_types.push(idl_type);
|
||||
new_possibilities.push(new_idl_types)
|
||||
}
|
||||
}
|
||||
possibilities = new_possibilities;
|
||||
}
|
||||
optional_possibilities.extend(possibilities.into_iter());
|
||||
optional_possibilities
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arguments_flatten_test() {
|
||||
use self::IdlType::*;
|
||||
|
||||
assert_eq!(
|
||||
flatten(
|
||||
&vec![
|
||||
(
|
||||
Union(vec![
|
||||
Short,
|
||||
Long,
|
||||
]),
|
||||
false,
|
||||
),
|
||||
(
|
||||
Union(vec![
|
||||
Sequence(Box::new(
|
||||
Union(vec![
|
||||
Byte,
|
||||
Octet,
|
||||
]),
|
||||
)),
|
||||
LongLong,
|
||||
]),
|
||||
true,
|
||||
),
|
||||
(
|
||||
DomString,
|
||||
true,
|
||||
)
|
||||
]
|
||||
),
|
||||
vec![
|
||||
vec![Short],
|
||||
vec![Long],
|
||||
vec![Short, Sequence(Box::new(Byte))],
|
||||
vec![Short, Sequence(Box::new(Octet))],
|
||||
vec![Short, LongLong],
|
||||
vec![Long, Sequence(Box::new(Byte))],
|
||||
vec![Long, Sequence(Box::new(Octet))],
|
||||
vec![Long, LongLong],
|
||||
vec![Short, Sequence(Box::new(Byte)), DomString],
|
||||
vec![Short, Sequence(Box::new(Octet)), DomString],
|
||||
vec![Short, LongLong, DomString],
|
||||
vec![Long, Sequence(Box::new(Byte)), DomString],
|
||||
vec![Long, Sequence(Box::new(Octet)), DomString],
|
||||
vec![Long, LongLong, DomString]
|
||||
],
|
||||
);
|
||||
}
|
@ -25,6 +25,7 @@ extern crate wasm_bindgen_backend as backend;
|
||||
extern crate weedle;
|
||||
|
||||
mod first_pass;
|
||||
mod idl_type;
|
||||
mod util;
|
||||
mod error;
|
||||
|
||||
@ -45,7 +46,7 @@ use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList};
|
||||
|
||||
use first_pass::{FirstPass, FirstPassRecord};
|
||||
use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc};
|
||||
use util::ToSynType;
|
||||
use idl_type::{IdlType, ToIdlType};
|
||||
|
||||
pub use error::{Error, ErrorKind, Result};
|
||||
|
||||
@ -341,23 +342,22 @@ impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for Extend
|
||||
// > exception**.
|
||||
let throws = true;
|
||||
|
||||
first_pass
|
||||
.create_function(
|
||||
"new",
|
||||
overloaded,
|
||||
same_argument_names,
|
||||
arguments,
|
||||
Some(self_ty),
|
||||
kind,
|
||||
structural,
|
||||
throws,
|
||||
None,
|
||||
)
|
||||
.map(|import_functions|
|
||||
for import_function in import_functions {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
);
|
||||
for import_function in first_pass.create_function(
|
||||
"new",
|
||||
overloaded,
|
||||
same_argument_names,
|
||||
&match first_pass.convert_arguments(arguments) {
|
||||
None => return,
|
||||
Some(arguments) => arguments
|
||||
},
|
||||
IdlType::Interface(interface.identifier.0),
|
||||
kind,
|
||||
structural,
|
||||
throws,
|
||||
None,
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
};
|
||||
|
||||
match self {
|
||||
@ -566,36 +566,28 @@ fn member_attribute<'src>(
|
||||
let is_structural = util::is_structural(attrs);
|
||||
let throws = util::throws(attrs);
|
||||
|
||||
first_pass
|
||||
.create_getter(
|
||||
for import_function in first_pass.create_getter(
|
||||
identifier,
|
||||
&type_.type_,
|
||||
self_name,
|
||||
is_static,
|
||||
is_structural,
|
||||
throws,
|
||||
)
|
||||
.map(|import_functions|
|
||||
for import_function in import_functions {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
);
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
|
||||
if !readonly {
|
||||
first_pass
|
||||
.create_setter(
|
||||
identifier,
|
||||
type_.type_.clone(),
|
||||
self_name,
|
||||
is_static,
|
||||
is_structural,
|
||||
throws,
|
||||
)
|
||||
.map(|import_functions|
|
||||
for import_function in import_functions {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
);
|
||||
for import_function in first_pass.create_setter(
|
||||
identifier,
|
||||
type_.type_.clone(),
|
||||
self_name,
|
||||
is_static,
|
||||
is_structural,
|
||||
throws,
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -669,38 +661,34 @@ fn member_operation<'src>(
|
||||
None => false,
|
||||
};
|
||||
|
||||
first_pass
|
||||
.create_basic_method(
|
||||
args,
|
||||
match identifier.map(|s| s.0) {
|
||||
None if specials.is_empty() => ::first_pass::OperationId::Operation(None),
|
||||
None if specials.len() == 1 => match specials[0] {
|
||||
weedle::interface::Special::Getter(weedle::term::Getter) => ::first_pass::OperationId::IndexingGetter,
|
||||
weedle::interface::Special::Setter(weedle::term::Setter) => ::first_pass::OperationId::IndexingSetter,
|
||||
weedle::interface::Special::Deleter(weedle::term::Deleter) => ::first_pass::OperationId::IndexingDeleter,
|
||||
weedle::interface::Special::LegacyCaller(weedle::term::LegacyCaller) => return Ok(()),
|
||||
},
|
||||
Some(ref name) if specials.is_empty() => ::first_pass::OperationId::Operation(Some(name.clone())),
|
||||
_ => {
|
||||
warn!("Unsupported specials on type {:?}", (self_name, identifier));
|
||||
return Ok(())
|
||||
}
|
||||
for import_function in first_pass.create_basic_method(
|
||||
args,
|
||||
match identifier.map(|s| s.0) {
|
||||
None if specials.is_empty() => ::first_pass::OperationId::Operation(None),
|
||||
None if specials.len() == 1 => match specials[0] {
|
||||
weedle::interface::Special::Getter(weedle::term::Getter) => ::first_pass::OperationId::IndexingGetter,
|
||||
weedle::interface::Special::Setter(weedle::term::Setter) => ::first_pass::OperationId::IndexingSetter,
|
||||
weedle::interface::Special::Deleter(weedle::term::Deleter) => ::first_pass::OperationId::IndexingDeleter,
|
||||
weedle::interface::Special::LegacyCaller(weedle::term::LegacyCaller) => return Ok(()),
|
||||
},
|
||||
return_type,
|
||||
self_name,
|
||||
is_static,
|
||||
specials.len() == 1 || first_pass
|
||||
.interfaces
|
||||
.get(self_name)
|
||||
.map(|interface_data| interface_data.global)
|
||||
.unwrap_or(false),
|
||||
util::throws(attrs),
|
||||
)
|
||||
.map(|import_functions|
|
||||
for import_function in import_functions {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
Some(ref name) if specials.is_empty() => ::first_pass::OperationId::Operation(Some(name.clone())),
|
||||
_ => {
|
||||
warn!("Unsupported specials on type {:?}", (self_name, identifier));
|
||||
return Ok(())
|
||||
}
|
||||
);
|
||||
},
|
||||
return_type,
|
||||
self_name,
|
||||
is_static,
|
||||
specials.len() == 1 || first_pass
|
||||
.interfaces
|
||||
.get(self_name)
|
||||
.map(|interface_data| interface_data.global)
|
||||
.unwrap_or(false),
|
||||
util::throws(attrs),
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -796,9 +784,14 @@ impl<'src> WebidlParse<'src, &'src str> for weedle::interface::ConstMember<'src>
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ty = match self.const_type.to_syn_type(record, TypePosition::Return) {
|
||||
Some(s) => s,
|
||||
let idl_type = match self.const_type.to_idl_type(record) {
|
||||
None => return Ok(()),
|
||||
Some(idl_type) => idl_type,
|
||||
};
|
||||
|
||||
let ty = match idl_type.to_syn_type(TypePosition::Return) {
|
||||
None => return Ok(()),
|
||||
Some(ty) => ty,
|
||||
};
|
||||
|
||||
program.consts.push(backend::ast::Const {
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user