Add support for unions in arguments and for optional arguments

This commit is contained in:
Anton Danilkin 2018-08-09 19:24:33 +03:00
parent f85fd0e2ad
commit 703b1ab91d
6 changed files with 710 additions and 320 deletions

View File

@ -7,7 +7,7 @@ use Diagnostic;
/// An abstract syntax tree representing a rust program. Contains /// An abstract syntax tree representing a rust program. Contains
/// extra information for joining up this rust code with javascript. /// extra information for joining up this rust code with javascript.
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
#[derive(Default)] #[derive(Default, Clone)]
pub struct Program { pub struct Program {
/// rust -> js interfaces /// rust -> js interfaces
pub exports: Vec<Export>, pub exports: Vec<Export>,
@ -24,6 +24,7 @@ pub struct Program {
/// A rust to js interface. Allows interaction with rust objects/functions /// A rust to js interface. Allows interaction with rust objects/functions
/// from javascript. /// from javascript.
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Export { pub struct Export {
/// The javascript class name. /// The javascript class name.
pub class: Option<Ident>, pub class: Option<Ident>,
@ -44,6 +45,7 @@ pub struct Export {
/// The 3 types variations of `self`. /// The 3 types variations of `self`.
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum MethodSelf { pub enum MethodSelf {
/// `self` /// `self`
ByValue, ByValue,
@ -54,6 +56,7 @@ pub enum MethodSelf {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Import { pub struct Import {
pub module: Option<String>, pub module: Option<String>,
pub js_namespace: Option<Ident>, pub js_namespace: Option<Ident>,
@ -61,6 +64,7 @@ pub struct Import {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum ImportKind { pub enum ImportKind {
Function(ImportFunction), Function(ImportFunction),
Static(ImportStatic), Static(ImportStatic),
@ -69,6 +73,7 @@ pub enum ImportKind {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportFunction { pub struct ImportFunction {
pub function: Function, pub function: Function,
pub rust_name: Ident, pub rust_name: Ident,
@ -81,6 +86,7 @@ pub struct ImportFunction {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum ImportFunctionKind { pub enum ImportFunctionKind {
Method { Method {
class: String, class: String,
@ -91,18 +97,21 @@ pub enum ImportFunctionKind {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum MethodKind { pub enum MethodKind {
Constructor, Constructor,
Operation(Operation), Operation(Operation),
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Operation { pub struct Operation {
pub is_static: bool, pub is_static: bool,
pub kind: OperationKind, pub kind: OperationKind,
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub enum OperationKind { pub enum OperationKind {
Regular, Regular,
Getter(Option<Ident>), Getter(Option<Ident>),
@ -113,6 +122,7 @@ pub enum OperationKind {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportStatic { pub struct ImportStatic {
pub vis: syn::Visibility, pub vis: syn::Visibility,
pub ty: syn::Type, pub ty: syn::Type,
@ -122,6 +132,7 @@ pub struct ImportStatic {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportType { pub struct ImportType {
pub vis: syn::Visibility, pub vis: syn::Visibility,
pub rust_name: Ident, pub rust_name: Ident,
@ -133,6 +144,7 @@ pub struct ImportType {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct ImportEnum { pub struct ImportEnum {
/// The Rust enum's visibility /// The Rust enum's visibility
pub vis: syn::Visibility, pub vis: syn::Visibility,
@ -147,6 +159,7 @@ pub struct ImportEnum {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Function { pub struct Function {
pub name: String, pub name: String,
pub arguments: Vec<syn::ArgCaptured>, pub arguments: Vec<syn::ArgCaptured>,
@ -156,6 +169,7 @@ pub struct Function {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Struct { pub struct Struct {
pub name: Ident, pub name: Ident,
pub fields: Vec<StructField>, pub fields: Vec<StructField>,
@ -163,6 +177,7 @@ pub struct Struct {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct StructField { pub struct StructField {
pub name: Ident, pub name: Ident,
pub struct_name: Ident, pub struct_name: Ident,
@ -174,6 +189,7 @@ pub struct StructField {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Enum { pub struct Enum {
pub name: Ident, pub name: Ident,
pub variants: Vec<Variant>, pub variants: Vec<Variant>,
@ -181,6 +197,7 @@ pub struct Enum {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
#[derive(Clone)]
pub struct Variant { pub struct Variant {
pub name: Ident, pub name: Ident,
pub value: u32, pub value: u32,
@ -202,6 +219,7 @@ pub enum TypeLocation {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
#[derive(Clone)]
pub struct Const { pub struct Const {
pub vis: syn::Visibility, pub vis: syn::Visibility,
pub name: Ident, pub name: Ident,
@ -211,6 +229,7 @@ pub struct Const {
} }
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))] #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))]
#[derive(Clone)]
/// same as webidl::ast::ConstValue /// same as webidl::ast::ConstValue
pub enum ConstValue { pub enum ConstValue {
BooleanLiteral(bool), BooleanLiteral(bool),

View File

@ -31,8 +31,7 @@ interface WebGL2RenderingContext
{ {
}; };
[NoInterfaceObject] interface mixin WebGL2RenderingContextBase
interface WebGL2RenderingContextBase
{ {
const GLenum READ_BUFFER = 0x0C02; const GLenum READ_BUFFER = 0x0C02;
const GLenum UNPACK_ROW_LENGTH = 0x0CF2; const GLenum UNPACK_ROW_LENGTH = 0x0CF2;
@ -694,8 +693,8 @@ interface WebGL2RenderingContextBase
void bindVertexArray(WebGLVertexArrayObject? array); void bindVertexArray(WebGLVertexArrayObject? array);
}; };
WebGL2RenderingContextBase implements WebGLRenderingContextBase; WebGL2RenderingContextBase includes WebGLRenderingContextBase;
WebGL2RenderingContext implements WebGL2RenderingContextBase; WebGL2RenderingContext includes WebGL2RenderingContextBase;
[NoInterfaceObject] [NoInterfaceObject]
interface EXT_color_buffer_float { interface EXT_color_buffer_float {

View File

@ -111,8 +111,7 @@ typedef (Int32Array or sequence<GLint>) Int32List;
// WebGL2RenderingContext have in common. This doesn't have all the things they // WebGL2RenderingContext have in common. This doesn't have all the things they
// have in common, because we don't support splitting multiple overloads of the // have in common, because we don't support splitting multiple overloads of the
// same method across separate interfaces and pulling them in with "implements". // same method across separate interfaces and pulling them in with "implements".
[Exposed=(Window, Worker), NoInterfaceObject] interface mixin WebGLRenderingContextBase {
interface WebGLRenderingContextBase {
/* ClearBufferMask */ /* ClearBufferMask */
const GLenum DEPTH_BUFFER_BIT = 0x00000100; const GLenum DEPTH_BUFFER_BIT = 0x00000100;
const GLenum STENCIL_BUFFER_BIT = 0x00000400; const GLenum STENCIL_BUFFER_BIT = 0x00000400;
@ -802,7 +801,7 @@ interface WebGLRenderingContext {
void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data); void uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List data);
}; };
WebGLRenderingContext implements WebGLRenderingContextBase; WebGLRenderingContext includes WebGLRenderingContextBase;
// For OffscreenCanvas // For OffscreenCanvas
// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas // Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas

View File

@ -26,8 +26,9 @@ pub(crate) struct FirstPassRecord<'src> {
pub(crate) dictionaries: BTreeSet<&'src str>, pub(crate) dictionaries: BTreeSet<&'src str>,
pub(crate) enums: BTreeSet<&'src str>, pub(crate) enums: BTreeSet<&'src str>,
/// The mixins, mapping their name to the webidl ast node for the mixin. /// The mixins, mapping their name to the webidl ast node for the mixin.
pub(crate) mixins: BTreeMap<&'src str, Vec<&'src MixinMembers<'src>>>, pub(crate) mixins: BTreeMap<&'src str, MixinData<'src>>,
pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>, pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>,
pub(crate) includes: BTreeMap<&'src str, BTreeSet<&'src str>>,
} }
/// We need to collect interface data during the first pass, to be used later. /// We need to collect interface data during the first pass, to be used later.
@ -40,7 +41,16 @@ pub(crate) struct InterfaceData<'src> {
pub(crate) superclass: Option<&'src str>, pub(crate) superclass: Option<&'src str>,
} }
#[derive(PartialEq, Eq, PartialOrd, Ord)] /// We need to collect mixin data during the first pass, to be used later.
#[derive(Default)]
pub(crate) struct MixinData<'src> {
/// Whether only partial mixins were encountered
pub(crate) partial: bool,
pub(crate) members: Vec<&'src MixinMembers<'src>>,
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub(crate) enum OperationId<'src> { pub(crate) enum OperationId<'src> {
Constructor, Constructor,
Operation(Option<&'src str>), Operation(Option<&'src str>),
@ -79,6 +89,7 @@ impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
match self { match self {
Dictionary(dictionary) => dictionary.first_pass(record, ()), Dictionary(dictionary) => dictionary.first_pass(record, ()),
Enum(enum_) => enum_.first_pass(record, ()), Enum(enum_) => enum_.first_pass(record, ()),
IncludesStatement(includes) => includes.first_pass(record, ()),
Interface(interface) => interface.first_pass(record, ()), Interface(interface) => interface.first_pass(record, ()),
PartialInterface(interface) => interface.first_pass(record, ()), PartialInterface(interface) => interface.first_pass(record, ()),
InterfaceMixin(mixin) => mixin.first_pass(record, ()), InterfaceMixin(mixin) => mixin.first_pass(record, ()),
@ -111,24 +122,44 @@ impl<'src> FirstPass<'src, ()> for weedle::EnumDefinition<'src> {
} }
} }
impl<'src> FirstPass<'src, ()> for weedle::IncludesStatementDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record
.includes
.entry(self.lhs_identifier.0)
.or_insert_with(Default::default)
.insert(self.rhs_identifier.0);
Ok(())
}
}
fn first_pass_operation<'src>( fn first_pass_operation<'src>(
record: &mut FirstPassRecord<'src>, record: &mut FirstPassRecord<'src>,
mixin: bool,
self_name: &'src str, self_name: &'src str,
id: OperationId<'src>, id: OperationId<'src>,
arguments: &[Argument<'src>], arguments: &[Argument<'src>],
) -> Result<()> { ) -> Result<()> {
let mut names = Vec::with_capacity(arguments.len()); let mut names = Vec::with_capacity(arguments.len());
for argument in arguments { for argument in arguments {
match argument { match argument {
Argument::Single(arg) => names.push(arg.identifier.0), Argument::Single(single) => names.push(single.identifier.0),
Argument::Variadic(_) => return Ok(()), Argument::Variadic(variadic) => names.push(variadic.identifier.0),
} }
} }
record if mixin {
.interfaces &mut record
.get_mut(self_name) .mixins
.unwrap() .get_mut(self_name)
.operations .unwrap()
.operations
} else {
&mut record
.interfaces
.get_mut(self_name)
.unwrap()
.operations
}
.entry(id) .entry(id)
.and_modify(|operation_data| operation_data.overloaded = true) .and_modify(|operation_data| operation_data.overloaded = true)
.or_insert_with(Default::default) .or_insert_with(Default::default)
@ -143,12 +174,12 @@ fn first_pass_operation<'src>(
impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> { impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
{ {
let interface = record let interface_data = record
.interfaces .interfaces
.entry(self.identifier.0) .entry(self.identifier.0)
.or_insert_with(Default::default); .or_insert_with(Default::default);
interface.partial = false; interface_data.partial = false;
interface.superclass = self.inheritance.map(|s| s.identifier.0); interface_data.superclass = self.inheritance.map(|s| s.identifier.0);
} }
if util::is_chrome_only(&self.attributes) { if util::is_chrome_only(&self.attributes) {
@ -177,8 +208,8 @@ impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
.or_insert_with(|| .or_insert_with(||
InterfaceData { InterfaceData {
partial: true, partial: true,
operations: Default::default(),
global: false, global: false,
operations: Default::default(),
superclass: None, superclass: None,
}, },
); );
@ -201,6 +232,7 @@ impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> {
ExtendedAttribute::ArgList(list) if list.identifier.0 == "Constructor" => { ExtendedAttribute::ArgList(list) if list.identifier.0 == "Constructor" => {
first_pass_operation( first_pass_operation(
record, record,
false,
self_name, self_name,
OperationId::Constructor, OperationId::Constructor,
&list.args.body.list, &list.args.body.list,
@ -209,6 +241,7 @@ impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> {
ExtendedAttribute::NoArgs(name) if (name.0).0 == "Constructor" => { ExtendedAttribute::NoArgs(name) if (name.0).0 == "Constructor" => {
first_pass_operation( first_pass_operation(
record, record,
false,
self_name, self_name,
OperationId::Constructor, OperationId::Constructor,
&[], &[],
@ -219,6 +252,7 @@ impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> {
{ {
first_pass_operation( first_pass_operation(
record, record,
false,
self_name, self_name,
OperationId::Constructor, OperationId::Constructor,
&list.args.body.list, &list.args.body.list,
@ -260,6 +294,7 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceM
} }
first_pass_operation( first_pass_operation(
record, record,
false,
self_name, self_name,
match self.identifier.map(|s| s.0) { match self.identifier.map(|s| s.0) {
None => match self.specials.get(0) { None => match self.specials.get(0) {
@ -278,11 +313,23 @@ impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceM
impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src>{ impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src>{
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record {
.mixins let mixin_data = record
.entry(self.identifier.0) .mixins
.or_insert_with(Default::default) .entry(self.identifier.0)
.push(&self.members.body); .or_insert_with(Default::default);
mixin_data.partial = false;
mixin_data.members.push(&self.members.body);
}
if util::is_chrome_only(&self.attributes) {
return Ok(())
}
for member in &self.members.body {
member.first_pass(record, self.identifier.0)?;
}
Ok(()) Ok(())
} }
} }
@ -292,12 +339,55 @@ impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src>
record record
.mixins .mixins
.entry(self.identifier.0) .entry(self.identifier.0)
.or_insert_with(Default::default) .or_insert_with(||
MixinData {
partial: true,
members: Default::default(),
operations: Default::default(),
},
)
.members
.push(&self.members.body); .push(&self.members.body);
if util::is_chrome_only(&self.attributes) {
return Ok(())
}
for member in &self.members.body {
member.first_pass(record, self.identifier.0)?;
}
Ok(()) Ok(())
} }
} }
impl<'src> FirstPass<'src, &'src str> for weedle::mixin::MixinMember<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self {
weedle::mixin::MixinMember::Operation(op) => {
op.first_pass(record, self_name)
}
_ => Ok(()),
}
}
}
impl<'src> FirstPass<'src, &'src str> for weedle::mixin::OperationMixinMember<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
if self.stringifier.is_some() {
warn!("Unsupported webidl operation {:?}", self);
return Ok(())
}
first_pass_operation(
record,
true,
self_name,
OperationId::Operation(self.identifier.map(|s| s.0.clone())),
&self.args.body.list,
)
}
}
impl<'src> FirstPass<'src, ()> for weedle::TypedefDefinition<'src> { impl<'src> FirstPass<'src, ()> for weedle::TypedefDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> { fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if util::is_chrome_only(&self.attributes) { if util::is_chrome_only(&self.attributes) {

View File

@ -168,9 +168,6 @@ impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> {
weedle::Definition::Enum(enumeration) => { weedle::Definition::Enum(enumeration) => {
enumeration.webidl_parse(program, first_pass, ())? enumeration.webidl_parse(program, first_pass, ())?
} }
weedle::Definition::IncludesStatement(includes) => {
includes.webidl_parse(program, first_pass, ())?
}
weedle::Definition::Interface(interface) => { weedle::Definition::Interface(interface) => {
interface.webidl_parse(program, first_pass, ())? interface.webidl_parse(program, first_pass, ())?
} }
@ -182,6 +179,9 @@ impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> {
weedle::Definition::PartialInterfaceMixin(_) => { weedle::Definition::PartialInterfaceMixin(_) => {
// handled in the first pass // handled in the first pass
} }
weedle::Definition::IncludesStatement(..) => {
// handled in the first pass
}
weedle::Definition::Implements(..) => { weedle::Definition::Implements(..) => {
// nothing to do for this, ignore it // nothing to do for this, ignore it
} }
@ -199,25 +199,6 @@ impl<'src> WebidlParse<'src, ()> for weedle::Definition<'src> {
} }
} }
impl<'src> WebidlParse<'src, ()> for weedle::IncludesStatementDefinition<'src> {
fn webidl_parse(
&'src self,
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
(): (),
) -> Result<()> {
match first_pass.mixins.get(self.rhs_identifier.0) {
Some(member_lists) => {
for member in member_lists.iter().flat_map(|list| list.iter()) {
member.webidl_parse(program, first_pass, self.lhs_identifier.0)?;
}
}
None => warn!("Tried to include missing mixin {}", self.rhs_identifier.0),
}
Ok(())
}
}
impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> { impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> {
fn webidl_parse( fn webidl_parse(
&'src self, &'src self,
@ -261,10 +242,33 @@ impl<'src> WebidlParse<'src, ()> for weedle::InterfaceDefinition<'src> {
} }
} }
fn parse<'src>(
program: &mut backend::ast::Program,
first_pass: &FirstPassRecord<'src>,
self_name: &str,
mixin_name: &str,
) -> Result<()> {
if let Some(mixin_data) = first_pass.mixins.get(mixin_name) {
for members in &mixin_data.members {
for member in *members {
member.webidl_parse(program, first_pass, self_name)?;
}
}
}
if let Some(mixin_names) = first_pass.includes.get(mixin_name) {
for mixin_name in mixin_names {
parse(program, first_pass, self_name, mixin_name)?;
}
}
Ok(())
}
for member in &self.members.body { for member in &self.members.body {
member.webidl_parse(program, first_pass, self.identifier.0)?; member.webidl_parse(program, first_pass, self.identifier.0)?;
} }
parse(program, first_pass, self.identifier.0, self.identifier.0)?;
Ok(()) Ok(())
} }
} }
@ -280,7 +284,11 @@ impl<'src> WebidlParse<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
return Ok(()); return Ok(());
} }
if !first_pass.interfaces.contains_key(self.identifier.0) { if first_pass
.interfaces
.get(self.identifier.0)
.map(|interface_data| !interface_data.partial)
.unwrap_or(true) {
warn!( warn!(
"Partial interface {} missing non-partial interface", "Partial interface {} missing non-partial interface",
self.identifier.0 self.identifier.0
@ -345,8 +353,11 @@ impl<'src> WebidlParse<'src, &'src weedle::InterfaceDefinition<'src>> for Extend
throws, throws,
None, None,
) )
.map(wrap_import_function) .map(|import_functions|
.map(|import| program.imports.push(import)); for import_function in import_functions {
program.imports.push(wrap_import_function(import_function));
}
);
}; };
match self { match self {
@ -436,8 +447,8 @@ impl<'src> WebidlParse<'src, &'src str> for weedle::interface::InterfaceMember<'
Operation(op) => { Operation(op) => {
op.webidl_parse(program, first_pass, self_name) op.webidl_parse(program, first_pass, self_name)
} }
Const(cnst) => { Const(const_) => {
cnst.webidl_parse(program, first_pass, self_name) const_.webidl_parse(program, first_pass, self_name)
} }
Iterable(iterable) => { Iterable(iterable) => {
iterable.webidl_parse(program, first_pass, self_name) iterable.webidl_parse(program, first_pass, self_name)
@ -537,7 +548,7 @@ fn member_attribute<'src>(
return Ok(()); return Ok(());
} }
let statik = match modifier { let is_static = match modifier {
Some(Stringifier(_)) => { Some(Stringifier(_)) => {
warn!("Unsupported stringifier on type {:?}", (self_name, identifier)); warn!("Unsupported stringifier on type {:?}", (self_name, identifier));
return Ok(()) return Ok(())
@ -560,12 +571,15 @@ fn member_attribute<'src>(
identifier, identifier,
&type_.type_, &type_.type_,
self_name, self_name,
statik, is_static,
is_structural, is_structural,
throws, throws,
) )
.map(wrap_import_function) .map(|import_functions|
.map(|import| program.imports.push(import)); for import_function in import_functions {
program.imports.push(wrap_import_function(import_function));
}
);
if !readonly { if !readonly {
first_pass first_pass
@ -573,12 +587,15 @@ fn member_attribute<'src>(
identifier, identifier,
type_.type_.clone(), type_.type_.clone(),
self_name, self_name,
statik, is_static,
is_structural, is_structural,
throws, throws,
) )
.map(wrap_import_function) .map(|import_functions|
.map(|import| program.imports.push(import)); for import_function in import_functions {
program.imports.push(wrap_import_function(import_function));
}
);
} }
Ok(()) Ok(())
@ -642,7 +659,7 @@ fn member_operation<'src>(
if util::is_chrome_only(attrs) { if util::is_chrome_only(attrs) {
return Ok(()); return Ok(());
} }
let statik = match modifier { let is_static = match modifier {
Some(Stringifier(_)) => { Some(Stringifier(_)) => {
warn!("Unsupported stringifier on type {:?}", (self_name, identifier)); warn!("Unsupported stringifier on type {:?}", (self_name, identifier));
return Ok(()) return Ok(())
@ -670,7 +687,7 @@ fn member_operation<'src>(
}, },
return_type, return_type,
self_name, self_name,
statik, is_static,
specials.len() == 1 || first_pass specials.len() == 1 || first_pass
.interfaces .interfaces
.get(self_name) .get(self_name)
@ -678,8 +695,11 @@ fn member_operation<'src>(
.unwrap_or(false), .unwrap_or(false),
util::throws(attrs), util::throws(attrs),
) )
.map(wrap_import_function) .map(|import_functions|
.map(|import| program.imports.push(import)); for import_function in import_functions {
program.imports.push(wrap_import_function(import_function));
}
);
Ok(()) Ok(())
} }

View File

@ -1,4 +1,5 @@
use std::iter::FromIterator; use std::iter::FromIterator;
use std::iter;
use backend; use backend;
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident}; use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
@ -315,64 +316,75 @@ impl<'src> ToSynType<'src> for weedle::term::Object {
} }
} }
impl<'src> ToSynType<'src> for weedle::types::Type<'src> { impl<'src> ToSynType<'src> for NonAnyType<'src> {
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition) fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
-> Option<syn::Type> -> Option<syn::Type>
{ {
use weedle::types::NonAnyType::*; match self {
let single = match self { NonAnyType::Boolean(s) => s.to_syn_type(record, pos),
Type::Single(s) => s, NonAnyType::Octet(s) => s.to_syn_type(record, pos),
Type::Union(_) => return None, NonAnyType::Byte(s) => s.to_syn_type(record, pos),
}; NonAnyType::Identifier(s) => s.to_syn_type(record, pos),
NonAnyType::Integer(s) => s.to_syn_type(record, pos),
NonAnyType::FloatingPoint(s) => s.to_syn_type(record, pos),
let ty = match single { NonAnyType::Float32Array(s) => s.to_syn_type(record, pos),
// `any` becomes `::wasm_bindgen::JsValue`. NonAnyType::Float64Array(s) => s.to_syn_type(record, pos),
SingleType::Any(_) => { NonAnyType::Int8Array(s) => s.to_syn_type(record, pos),
let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")]; NonAnyType::Int16Array(s) => s.to_syn_type(record, pos),
return Some(leading_colon_path_ty(path)) NonAnyType::Int32Array(s) => s.to_syn_type(record, pos),
} NonAnyType::Uint8Array(s) => s.to_syn_type(record, pos),
SingleType::NonAny(other) => other, NonAnyType::Uint8ClampedArray(s) => s.to_syn_type(record, pos),
}; NonAnyType::Uint16Array(s) => s.to_syn_type(record, pos),
NonAnyType::Uint32Array(s) => s.to_syn_type(record, pos),
match ty { NonAnyType::DOMString(s) => s.to_syn_type(record, pos),
Boolean(s) => s.to_syn_type(record, pos), NonAnyType::ByteString(s) => s.to_syn_type(record, pos),
Octet(s) => s.to_syn_type(record, pos), NonAnyType::USVString(s) => s.to_syn_type(record, pos),
Byte(s) => s.to_syn_type(record, pos), NonAnyType::ArrayBuffer(b) => b.to_syn_type(record, pos),
Identifier(s) => s.to_syn_type(record, pos), NonAnyType::Object(o) => o.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 // Support for these types is not yet implemented, so skip
// generating any bindings for this function. // generating any bindings for this function.
| DataView(_) | NonAnyType::DataView(_)
| Error(_) | NonAnyType::Error(_)
| FrozenArrayType(_) | NonAnyType::FrozenArrayType(_)
| Promise(_) | NonAnyType::Promise(_)
| RecordType(..) | NonAnyType::RecordType(..)
| Sequence(_) | NonAnyType::Sequence(_)
| Symbol(_) => { | NonAnyType::Symbol(_) => {
None None
} }
} }
} }
} }
impl<'src> ToSynType<'src> for SingleType<'src> {
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
-> Option<syn::Type>
{
match self {
// `any` becomes `::wasm_bindgen::JsValue`.
SingleType::Any(_) => {
let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")];
Some(leading_colon_path_ty(path))
}
SingleType::NonAny(non_any) => non_any.to_syn_type(record, pos),
}
}
}
impl<'src> ToSynType<'src> for Type<'src> {
fn to_syn_type(&self, record: &FirstPassRecord<'src>, pos: TypePosition)
-> Option<syn::Type>
{
match self {
Type::Single(single) => single.to_syn_type(record, pos),
Type::Union(_) => None,
}
}
}
/// Map a webidl const value to the correct wasm-bindgen const value /// Map a webidl const value to the correct wasm-bindgen const value
pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> backend::ast::ConstValue { pub fn webidl_const_v_to_backend_const_v(v: &ConstValue) -> backend::ast::ConstValue {
@ -519,31 +531,153 @@ pub enum TypePosition {
Return, Return,
} }
/// Implemented on an AST type node to generate a snake case name. trait GetArgumentPossibilities<'src> {
trait TypeToString { fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>>;
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String);
} }
impl<T: TypeToString> TypeToString for MayBeNull<T> { impl<'src, T: GetArgumentPossibilities<'src>> GetArgumentPossibilities<'src> for MayBeNull<T> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
if self.q_mark.is_some() { Some(
dst.push_str("opt_"); self
} .type_
self.type_.type_to_string(record, dst); .get_argument_possibilities(record)?
.into_iter()
.map(|(ty, type_name)|
if self.q_mark.is_some() {
(option_ty(ty), "opt_".to_string() + &type_name)
} else {
(ty, type_name)
}
)
.collect()
)
} }
} }
impl<'src> TypeToString for weedle::types::ReturnType<'src> { impl<'src> GetArgumentPossibilities<'src> for weedle::common::Identifier<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
if let Some(other) = record.typedefs.get(&self.0) {
other.get_argument_possibilities(record)
} else {
Some(
vec![
(
self.to_syn_type(record, TypePosition::Argument)?,
self.get_type_name(record),
)
]
)
}
}
}
impl<'src> GetArgumentPossibilities<'src> for NonAnyType<'src> {
fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
if let NonAnyType::Identifier(identifier) = self {
identifier.get_argument_possibilities(record)
} else {
Some(
vec![
(
self.to_syn_type(record, TypePosition::Argument)?,
self.get_type_name(record),
)
]
)
}
}
}
impl<'src> GetArgumentPossibilities<'src> for SingleType<'src> {
fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
if let SingleType::NonAny(non_any) = self {
non_any.get_argument_possibilities(record)
} else {
Some(
vec![
(
self.to_syn_type(record, TypePosition::Argument)?,
self.get_type_name(record),
)
]
)
}
}
}
impl<'src> GetArgumentPossibilities<'src> for UnionMemberType<'src> {
fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
match self { match self {
weedle::types::ReturnType::Type(ty) => (*ty).type_to_string(record, dst), UnionMemberType::Single(single) => single.get_argument_possibilities(record),
UnionMemberType::Union(union) => union.get_argument_possibilities(record),
}
}
}
impl<'src> GetArgumentPossibilities<'src> for UnionType<'src> {
fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
let mut result = Vec::new();
for ty in &self.body.list {
result.extend(ty.get_argument_possibilities(record)?.into_iter());
}
Some(result)
}
}
impl<'src> GetArgumentPossibilities<'src> for Type<'src> {
fn get_argument_possibilities(&self, record: &FirstPassRecord<'src>) -> Option<Vec<(syn::Type, String)>> {
match self {
Type::Single(single) => single.get_argument_possibilities(record),
Type::Union(union) => union.get_argument_possibilities(record),
}
}
}
/// Implemented on an AST type node to generate a snake case name.
trait GetTypeName {
fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String);
fn get_type_name(&self, record: &FirstPassRecord) -> String {
let mut string = String::new();
self.push_type_name(record, &mut string);
return string;
}
}
impl<T: GetTypeName> GetTypeName for [T] {
fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
let mut first = true;
for union_member_type in self {
if first {
first = false;
} else {
dst.push_str("_and_");
}
union_member_type.push_type_name(record, dst);
}
}
}
impl<T: GetTypeName> GetTypeName for MayBeNull<T> {
fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
if self.q_mark.is_some() {
dst.push_str("opt_");
}
self.type_.push_type_name(record, dst);
}
}
impl<'src> GetTypeName for weedle::types::ReturnType<'src> {
fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
match self {
weedle::types::ReturnType::Type(ty) => (*ty).push_type_name(record, dst),
weedle::types::ReturnType::Void(_) => dst.push_str("void"), weedle::types::ReturnType::Void(_) => dst.push_str("void"),
} }
} }
} }
impl TypeToString for weedle::types::StringType { impl GetTypeName for weedle::types::StringType {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
match self { match self {
weedle::types::StringType::Byte(_) => dst.push_str("byte_str"), weedle::types::StringType::Byte(_) => dst.push_str("byte_str"),
weedle::types::StringType::DOM(_) => dst.push_str("dom_str"), weedle::types::StringType::DOM(_) => dst.push_str("dom_str"),
@ -552,107 +686,107 @@ impl TypeToString for weedle::types::StringType {
} }
} }
impl TypeToString for weedle::term::Byte { impl GetTypeName for weedle::term::Byte {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("i8"); dst.push_str("i8");
} }
} }
impl TypeToString for weedle::term::Octet { impl GetTypeName for weedle::term::Octet {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("u8"); dst.push_str("u8");
} }
} }
impl TypeToString for weedle::term::Boolean { impl GetTypeName for weedle::term::Boolean {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("bool"); dst.push_str("bool");
} }
} }
impl TypeToString for weedle::term::USVString { impl GetTypeName for weedle::term::USVString {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("usv_str"); dst.push_str("usv_str");
} }
} }
impl TypeToString for weedle::term::ByteString { impl GetTypeName for weedle::term::ByteString {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("byte_str"); dst.push_str("byte_str");
} }
} }
impl TypeToString for weedle::term::DOMString { impl GetTypeName for weedle::term::DOMString {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("dom_str"); dst.push_str("dom_str");
} }
} }
impl TypeToString for weedle::term::Float32Array { impl GetTypeName for weedle::term::Float32Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("f32_array"); dst.push_str("f32_array");
} }
} }
impl TypeToString for weedle::term::Float64Array { impl GetTypeName for weedle::term::Float64Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("f64_array"); dst.push_str("f64_array");
} }
} }
impl TypeToString for weedle::term::Int8Array { impl GetTypeName for weedle::term::Int8Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("i8_array"); dst.push_str("i8_array");
} }
} }
impl TypeToString for weedle::term::Int16Array { impl GetTypeName for weedle::term::Int16Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("i16_array"); dst.push_str("i16_array");
} }
} }
impl TypeToString for weedle::term::Int32Array { impl GetTypeName for weedle::term::Int32Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("i32_array"); dst.push_str("i32_array");
} }
} }
impl TypeToString for weedle::term::Uint8Array { impl GetTypeName for weedle::term::Uint8Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("u8_array"); dst.push_str("u8_array");
} }
} }
impl TypeToString for weedle::term::Uint8ClampedArray { impl GetTypeName for weedle::term::Uint8ClampedArray {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("u8_clamped_array"); dst.push_str("u8_clamped_array");
} }
} }
impl TypeToString for weedle::term::Uint16Array { impl GetTypeName for weedle::term::Uint16Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("u16_array"); dst.push_str("u16_array");
} }
} }
impl TypeToString for weedle::term::Uint32Array { impl GetTypeName for weedle::term::Uint32Array {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("u32_array"); dst.push_str("u32_array");
} }
} }
impl<'src> TypeToString for weedle::common::Identifier<'src> { impl<'src> GetTypeName for weedle::common::Identifier<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
match record.typedefs.get(self.0) { match record.typedefs.get(self.0) {
Some(other) => other.type_to_string(record, dst), Some(other) => other.push_type_name(record, dst),
None => dst.push_str(&self.0.to_snake_case()), None => dst.push_str(&self.0.to_snake_case()),
} }
} }
} }
impl TypeToString for IntegerType { impl GetTypeName for IntegerType {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
match self { match self {
IntegerType::LongLong(l) if l.unsigned.is_some() => dst.push_str("u64"), IntegerType::LongLong(l) if l.unsigned.is_some() => dst.push_str("u64"),
IntegerType::LongLong(_) => dst.push_str("i64"), IntegerType::LongLong(_) => dst.push_str("i64"),
@ -664,8 +798,8 @@ impl TypeToString for IntegerType {
} }
} }
impl TypeToString for FloatingPointType { impl GetTypeName for FloatingPointType {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
match self { match self {
FloatingPointType::Float(_) => dst.push_str("f32"), FloatingPointType::Float(_) => dst.push_str("f32"),
FloatingPointType::Double(_) => dst.push_str("f64"), FloatingPointType::Double(_) => dst.push_str("f64"),
@ -673,111 +807,133 @@ impl TypeToString for FloatingPointType {
} }
} }
impl TypeToString for weedle::term::ArrayBuffer { impl GetTypeName for weedle::term::ArrayBuffer {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("array_buffer"); dst.push_str("array_buffer");
} }
} }
impl TypeToString for weedle::term::Symbol { impl GetTypeName for weedle::term::Symbol {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("symbol"); dst.push_str("symbol");
} }
} }
impl TypeToString for weedle::term::Object { impl GetTypeName for weedle::term::Object {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("object"); dst.push_str("object");
} }
} }
impl TypeToString for weedle::term::DataView { impl GetTypeName for weedle::term::DataView {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("data_view"); dst.push_str("data_view");
} }
} }
impl TypeToString for weedle::term::Error { impl GetTypeName for weedle::term::Error {
fn type_to_string(&self, _record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, _record: &FirstPassRecord, dst: &mut String) {
dst.push_str("error"); dst.push_str("error");
} }
} }
impl<'src> TypeToString for weedle::types::SequenceType<'src> { impl<'src> GetTypeName for SequenceType<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
dst.push_str("seq_"); self.generics.body.push_type_name(record, dst);
self.generics.body.type_to_string(record, dst); dst.push_str("_seq");
} }
} }
impl<'src> TypeToString for weedle::types::PromiseType<'src> { impl<'src> GetTypeName for PromiseType<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
dst.push_str("promise_"); self.generics.body.push_type_name(record, dst);
self.generics.body.type_to_string(record, dst); dst.push_str("_promise");
} }
} }
impl<'src> TypeToString for weedle::types::FrozenArrayType<'src> { impl<'src> GetTypeName for FrozenArrayType<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
dst.push_str("frozen_array_"); self.generics.body.push_type_name(record, dst);
self.generics.body.type_to_string(record, dst); dst.push_str("_frozen_array");
} }
} }
impl<'src> TypeToString for weedle::types::RecordType<'src> { impl<'src> GetTypeName for RecordType<'src> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
dst.push_str("record_from_"); dst.push_str("record_from_");
self.generics.body.0.type_to_string(record, dst); self.generics.body.0.push_type_name(record, dst);
dst.push_str("_to_"); dst.push_str("_to_");
self.generics.body.2.type_to_string(record, dst); self.generics.body.2.push_type_name(record, dst);
} }
} }
impl<'a> TypeToString for weedle::types::Type<'a> { impl<'a> GetTypeName for NonAnyType<'a> {
fn type_to_string(&self, record: &FirstPassRecord, dst: &mut String) { fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
use weedle::types::NonAnyType::*; match self {
NonAnyType::Boolean(s) => s.push_type_name(record, dst),
NonAnyType::Octet(s) => s.push_type_name(record, dst),
NonAnyType::Byte(s) => s.push_type_name(record, dst),
NonAnyType::Identifier(s) => s.push_type_name(record, dst),
NonAnyType::Integer(s) => s.push_type_name(record, dst),
NonAnyType::FloatingPoint(s) => s.push_type_name(record, dst),
let single = match self { NonAnyType::Float32Array(s) => s.push_type_name(record, dst),
Type::Single(s) => s, NonAnyType::Float64Array(s) => s.push_type_name(record, dst),
Type::Union(_) => panic!("unions not supported"), NonAnyType::Int8Array(s) => s.push_type_name(record, dst),
}; NonAnyType::Int16Array(s) => s.push_type_name(record, dst),
NonAnyType::Int32Array(s) => s.push_type_name(record, dst),
NonAnyType::Uint8Array(s) => s.push_type_name(record, dst),
NonAnyType::Uint8ClampedArray(s) => s.push_type_name(record, dst),
NonAnyType::Uint16Array(s) => s.push_type_name(record, dst),
NonAnyType::Uint32Array(s) => s.push_type_name(record, dst),
let ty = match single { NonAnyType::DOMString(s) => s.push_type_name(record, dst),
SingleType::Any(_) => return dst.push_str("any"), NonAnyType::ByteString(s) => s.push_type_name(record, dst),
SingleType::NonAny(other) => other, NonAnyType::USVString(s) => s.push_type_name(record, dst),
}; NonAnyType::ArrayBuffer(s) => s.push_type_name(record, dst),
match ty { NonAnyType::DataView(s) => s.push_type_name(record, dst),
Boolean(s) => s.type_to_string(record, dst), NonAnyType::Error(s) => s.push_type_name(record, dst),
Octet(s) => s.type_to_string(record, dst), NonAnyType::FrozenArrayType(s) => s.push_type_name(record, dst),
Byte(s) => s.type_to_string(record, dst), NonAnyType::Object(s) => s.push_type_name(record, dst),
Identifier(s) => s.type_to_string(record, dst), NonAnyType::Promise(s) => s.push_type_name(record, dst),
Integer(s) => s.type_to_string(record, dst), NonAnyType::RecordType(s) => s.push_type_name(record, dst),
FloatingPoint(s) => s.type_to_string(record, dst), NonAnyType::Sequence(s) => s.push_type_name(record, dst),
NonAnyType::Symbol(s) => s.push_type_name(record, dst),
}
}
}
Float32Array(s) => s.type_to_string(record, dst), impl<'a> GetTypeName for SingleType<'a> {
Float64Array(s) => s.type_to_string(record, dst), fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
Int8Array(s) => s.type_to_string(record, dst), match self {
Int16Array(s) => s.type_to_string(record, dst), SingleType::Any(_) => dst.push_str("any"),
Int32Array(s) => s.type_to_string(record, dst), SingleType::NonAny(non_any) => non_any.push_type_name(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), impl<'a> GetTypeName for UnionMemberType<'a> {
ByteString(s) => s.type_to_string(record, dst), fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
USVString(s) => s.type_to_string(record, dst), match self {
ArrayBuffer(s) => s.type_to_string(record, dst), UnionMemberType::Single(single) => single.push_type_name(record, dst),
UnionMemberType::Union(union) => union.push_type_name(record, dst),
}
}
}
DataView(s) => s.type_to_string(record, dst), impl<'a> GetTypeName for UnionType<'a> {
Error(s) => s.type_to_string(record, dst), fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
FrozenArrayType(s) => s.type_to_string(record, dst), dst.push_str("union_of_");
Object(s) => s.type_to_string(record, dst), self.body.list.push_type_name(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), impl<'a> GetTypeName for Type<'a> {
fn push_type_name(&self, record: &FirstPassRecord, dst: &mut String) {
match self {
Type::Single(single) => single.push_type_name(record, dst),
Type::Union(union) => union.push_type_name(record, dst),
} }
} }
} }
@ -787,46 +943,110 @@ impl<'src> FirstPassRecord<'src> {
/// ///
/// `kind` is whether the function is a method, in which case we would need a `self` /// `kind` is whether the function is a method, in which case we would need a `self`
/// parameter. /// parameter.
fn webidl_arguments_to_syn_arg_captured( ///
/// Return option that contains a value if the conversion succeeds.
/// The value is a vector of argument variants.
/// Each variant is a vector of converted argument types and type names.
fn get_variants(
&self, &self,
arguments: &[Argument], arguments: &[Argument],
kind: &backend::ast::ImportFunctionKind, kind: &backend::ast::ImportFunctionKind,
) -> Option<Vec<syn::ArgCaptured>> ) -> Option<Vec<Vec<(syn::ArgCaptured, Option<String>)>>>
{ {
let mut res = if let backend::ast::ImportFunctionKind::Method { let arguments_possibilities = {
ty, fn get_argument_possibilities(record: &FirstPassRecord, argument: &Argument) -> Option<Vec<(syn::Type, String)>> {
kind: let single = match argument {
backend::ast::MethodKind::Operation(backend::ast::Operation { Argument::Single(single) => single,
is_static: false, .. Argument::Variadic(_) => return None,
}), };
.. match single.type_.type_.get_argument_possibilities(record) {
} = kind None => {
{ warn!("Argument's type is not yet supported: {:?}", argument);
let mut res = Vec::with_capacity(arguments.len() + 1); None
res.push(simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone()))); },
res Some(value) => Some(value),
} else {
Vec::with_capacity(arguments.len())
};
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) {
None => {
warn!("Argument's type is not yet supported: {:?}", argument);
return None;
}
Some(ty) => {
let name = argument.identifier.0.to_snake_case();
res.push(simple_fn_arg(rust_ident(&name), ty))
} }
} }
if !arguments.is_empty() {
let mut optional_arguments_possibilities = Vec::new();
if let Argument::Single(ref single) = arguments[0] {
if single.optional.is_some() {
optional_arguments_possibilities.push(Vec::new());
}
}
let mut arguments_possibilities: Vec<_> = get_argument_possibilities(
self,
&arguments[0]
)?
.into_iter()
.map(|argument_possibility| vec![argument_possibility])
.collect();
for argument in arguments[1..].iter() {
let mut new_arguments_possibilities = Vec::new();
for arguments_possibility in arguments_possibilities {
if let Argument::Single(single) = argument {
if single.optional.is_some() {
optional_arguments_possibilities.push(arguments_possibility.clone());
}
}
let mut element_argument_possibilities = get_argument_possibilities(
self,
&argument
)?;
for element_argument_possibility in element_argument_possibilities {
new_arguments_possibilities.push(
arguments_possibility
.iter()
.cloned()
.chain(iter::once(element_argument_possibility))
.collect()
)
}
}
arguments_possibilities = new_arguments_possibilities
}
optional_arguments_possibilities.extend(arguments_possibilities.into_iter());
optional_arguments_possibilities
} else {
vec![Vec::new()]
}
};
let mut result = Vec::new();
for arguments_possibility in arguments_possibilities {
let mut res = if let backend::ast::ImportFunctionKind::Method {
ty,
kind: backend::ast::MethodKind::Operation(
backend::ast::Operation {
is_static: false, ..
}
),
..
} = kind {
let mut res = Vec::with_capacity(arguments.len() + 1);
res.push((simple_fn_arg(raw_ident("self_"), shared_ref(ty.clone())), None));
res
} else {
Vec::with_capacity(arguments.len())
};
for (argument, argument_possibility) in arguments.iter().zip(arguments_possibility) {
let single = match argument {
Argument::Single(single) => single,
Argument::Variadic(_) => return None,
};
res.push(
(
simple_fn_arg(
rust_ident(&single.identifier.0.to_snake_case()),
argument_possibility.0.clone()
),
Some(argument_possibility.1.clone()),
)
);
}
result.push(res);
} }
Some(res) Some(result)
} }
/// Create a wasm-bindgen function, if possible. /// Create a wasm-bindgen function, if possible.
@ -841,37 +1061,32 @@ impl<'src> FirstPassRecord<'src> {
structural: bool, structural: bool,
catch: bool, catch: bool,
doc_comment: Option<String>, doc_comment: Option<String>,
) -> Option<backend::ast::ImportFunction> ) -> Option<Vec<backend::ast::ImportFunction>>
{ {
let ast_arguments = self.webidl_arguments_to_syn_arg_captured(arguments, &kind)?; let rust_name = if overloaded && !arguments.is_empty() {
let mut argument_type_names = String::new();
let rust_name = rust_ident( for arg in arguments {
&if overloaded && !arguments.is_empty() { let arg = match arg {
let mut argument_type_names = String::new(); Argument::Single(single) => single,
for arg in arguments { Argument::Variadic(_) => return None,
let arg = match arg { };
Argument::Single(single) => single, if argument_type_names.len() > 0 {
Argument::Variadic(_) => return None, argument_type_names.push_str("_and_");
};
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());
}
} }
if name == "new" { if same_argument_names {
"with_".to_owned() + &argument_type_names arg.type_.type_.push_type_name(self, &mut argument_type_names);
} else { } else {
name.to_snake_case() + "_with_" + &argument_type_names argument_type_names.push_str(&arg.identifier.0.to_snake_case());
} }
} else {
name.to_snake_case()
} }
); if name == "new" {
let name = name.to_string(); "with_".to_owned() + &argument_type_names
} else {
name.to_snake_case() + "_with_" + &argument_type_names
}
} else {
name.to_snake_case()
};
let js_ret = ret.clone(); let js_ret = ret.clone();
@ -879,31 +1094,57 @@ impl<'src> FirstPassRecord<'src> {
ret = Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty)) ret = Some(ret.map_or_else(|| result_ty(unit_ty()), result_ty))
} }
let shim = { let variants = self.get_variants(arguments, &kind)?;
let ns = match kind { let multiple_variants = variants.len() > 1;
backend::ast::ImportFunctionKind::Normal => "", let mut result = Vec::new();
backend::ast::ImportFunctionKind::Method { ref class, .. } => class, for variant in variants {
let (variant_types, variant_names): (Vec<_>, Vec<_>) = variant.into_iter().unzip();
let rust_name = if multiple_variants {
let mut rust_name = rust_name.clone();
let mut first = true;
for variant_name in variant_names {
if let Some(type_name) = variant_name {
if first {
rust_name.push_str("_using_");
first = false;
} else {
rust_name.push_str("_and_");
}
rust_name.push_str(&type_name);
}
}
rust_name
} else {
rust_name.clone()
};
let rust_name = rust_ident(&rust_name);
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))
}; };
raw_ident(&format!("__widl_f_{}_{}", rust_name, ns)) result.push(backend::ast::ImportFunction {
}; function: backend::ast::Function {
name: name.to_string(),
Some(backend::ast::ImportFunction { arguments: variant_types,
function: backend::ast::Function { ret: ret.clone(),
name, rust_attrs: vec![],
arguments: ast_arguments, rust_vis: public(),
ret, },
rust_attrs: vec![], rust_name,
rust_vis: public(), js_ret: js_ret.clone(),
}, catch,
rust_name, structural,
js_ret, kind: kind.clone(),
catch, shim,
structural, doc_comment: doc_comment.clone(),
kind, })
shim, }
doc_comment, Some(result)
})
} }
/// Create a wasm-bindgen method, if possible. /// Create a wasm-bindgen method, if possible.
@ -916,7 +1157,7 @@ impl<'src> FirstPassRecord<'src> {
is_static: bool, is_static: bool,
structural: bool, structural: bool,
catch: bool, catch: bool,
) -> Option<backend::ast::ImportFunction> { ) -> Option<Vec<backend::ast::ImportFunction>> {
let (overloaded, same_argument_names) = self.get_operation_overloading( let (overloaded, same_argument_names) = self.get_operation_overloading(
arguments, arguments,
&operation_id, &operation_id,
@ -999,14 +1240,36 @@ impl<'src> FirstPassRecord<'src> {
id: &::first_pass::OperationId, id: &::first_pass::OperationId,
self_name: &str, self_name: &str,
) -> (bool, bool) { ) -> (bool, bool) {
let data = match self.interfaces.get(self_name) { fn get_operation_data<'src>(
Some(data) => data, record: &'src FirstPassRecord,
None => return (false, false), id: &'src ::first_pass::OperationId,
}; self_name: &str,
let data = match data.operations.get(id) { mixin_name: &str,
Some(data) => data, ) -> Option<&'src ::first_pass::OperationData<'src>> {
None => return (false, false), if let Some(mixin_data) = record.mixins.get(mixin_name) {
}; if let Some(operation_data) = mixin_data.operations.get(id) {
return Some(operation_data);
}
}
if let Some(mixin_names) = record.includes.get(mixin_name) {
for mixin_name in mixin_names {
if let Some(operation_data) = get_operation_data(record, id, self_name, mixin_name) {
return Some(operation_data);
}
}
}
None
}
let operation_data = self
.interfaces
.get(self_name)
.and_then(|interface_data| interface_data.operations.get(id))
.unwrap_or_else(||
get_operation_data(self, id, self_name, self_name)
.expect(&format!("not found operation {:?} in interface {}", id, self_name))
);
let mut names = Vec::with_capacity(arguments.len()); let mut names = Vec::with_capacity(arguments.len());
for arg in arguments { for arg in arguments {
match arg { match arg {
@ -1015,8 +1278,8 @@ impl<'src> FirstPassRecord<'src> {
} }
} }
( (
data.overloaded, operation_data.overloaded,
*data *operation_data
.argument_names_same .argument_names_same
.get(&names) .get(&names)
.unwrap_or(&false) .unwrap_or(&false)
@ -1032,7 +1295,7 @@ impl<'src> FirstPassRecord<'src> {
is_static: bool, is_static: bool,
is_structural: bool, is_structural: bool,
catch: bool, catch: bool,
) -> Option<backend::ast::ImportFunction> { ) -> Option<Vec<backend::ast::ImportFunction>> {
let ret = match ty.to_syn_type(self, TypePosition::Return) { let ret = match ty.to_syn_type(self, TypePosition::Return) {
None => { None => {
warn!("Attribute's type does not yet support reading: {:?}", ty); warn!("Attribute's type does not yet support reading: {:?}", ty);
@ -1063,7 +1326,7 @@ impl<'src> FirstPassRecord<'src> {
is_static: bool, is_static: bool,
is_structural: bool, is_structural: bool,
catch: bool, catch: bool,
) -> Option<backend::ast::ImportFunction> { ) -> Option<Vec<backend::ast::ImportFunction>> {
let kind = backend::ast::ImportFunctionKind::Method { let kind = backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(), class: self_name.to_string(),
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())), ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),