Migrate constructors to new naming scheme

This commit is contained in:
Alex Crichton 2018-08-29 18:27:49 -07:00
parent 5a4a34d4a1
commit 923abc7d85
3 changed files with 129 additions and 94 deletions

View File

@ -7,6 +7,7 @@
//! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can //! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can
//! be partial. //! be partial.
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use weedle::{DictionaryDefinition, PartialDictionaryDefinition}; use weedle::{DictionaryDefinition, PartialDictionaryDefinition};
@ -80,7 +81,7 @@ pub(crate) struct DictionaryData<'src> {
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub(crate) enum OperationId<'src> { pub(crate) enum OperationId<'src> {
Constructor, Constructor(IgnoreTraits<&'src str>),
Operation(Option<&'src str>), Operation(Option<&'src str>),
IndexingGetter, IndexingGetter,
IndexingSetter, IndexingSetter,
@ -363,7 +364,7 @@ fn process_interface_attribute<'src>(
record, record,
FirstPassOperationType::Interface, FirstPassOperationType::Interface,
self_name, self_name,
&[OperationId::Constructor], &[OperationId::Constructor(IgnoreTraits(self_name))],
&list.args.body.list, &list.args.body.list,
&return_ty, &return_ty,
&None, &None,
@ -381,7 +382,7 @@ fn process_interface_attribute<'src>(
record, record,
FirstPassOperationType::Interface, FirstPassOperationType::Interface,
self_name, self_name,
&[OperationId::Constructor], &[OperationId::Constructor(IgnoreTraits(self_name))],
&[], &[],
&return_ty, &return_ty,
&None, &None,
@ -401,7 +402,7 @@ fn process_interface_attribute<'src>(
record, record,
FirstPassOperationType::Interface, FirstPassOperationType::Interface,
self_name, self_name,
&[OperationId::Constructor], &[OperationId::Constructor(IgnoreTraits(list.rhs_identifier.0))],
&list.args.body.list, &list.args.body.list,
&return_ty, &return_ty,
&None, &None,
@ -784,3 +785,24 @@ impl<'a> FirstPassRecord<'a> {
} }
} }
} }
#[derive(Copy, Clone, Debug)]
pub struct IgnoreTraits<T>(pub T);
impl<T> PartialEq for IgnoreTraits<T> {
fn eq(&self, _other: &IgnoreTraits<T>) -> bool { true }
}
impl<T> Eq for IgnoreTraits<T> {}
impl<T> PartialOrd for IgnoreTraits<T> {
fn partial_cmp(&self, _other: &IgnoreTraits<T>) -> Option<Ordering> {
Some(Ordering::Equal)
}
}
impl<T> Ord for IgnoreTraits<T> {
fn cmp(&self, _other: &IgnoreTraits<T>) -> Ordering {
Ordering::Equal
}
}

View File

@ -314,7 +314,7 @@ impl<'src> FirstPassRecord<'src> {
) { ) {
let name = match id { let name = match id {
OperationId::Operation(Some(name)) => name, OperationId::Operation(Some(name)) => name,
OperationId::Constructor | OperationId::Constructor(_) |
OperationId::Operation(None) | OperationId::Operation(None) |
OperationId::IndexingGetter | OperationId::IndexingGetter |
OperationId::IndexingSetter | OperationId::IndexingSetter |
@ -404,13 +404,13 @@ impl<'src> FirstPassRecord<'src> {
}), }),
}); });
for (ctor_name, args) in data.constructors.iter() { // for (ctor_name, args) in data.constructors.iter() {
self.append_constructor(program, name, ctor_name, args); // self.append_constructor(program, name, ctor_name, args);
} // }
for (id, op_data) in data.operations2.iter() { for (id, op_data) in data.operations2.iter() {
if let OperationId::Constructor = id { // if let OperationId::Constructor = id {
continue // TODO // continue // TODO
} // }
self.member_operation2(program, name, data, id, op_data); self.member_operation2(program, name, data, id, op_data);
} }
for member in data.consts.iter() { for member in data.consts.iter() {
@ -453,61 +453,61 @@ impl<'src> FirstPassRecord<'src> {
} }
} }
fn append_constructor( // fn append_constructor(
&self, // &self,
program: &mut backend::ast::Program, // program: &mut backend::ast::Program,
iface_name: &'src str, // iface_name: &'src str,
ctor_name: &'src str, // ctor_name: &'src str,
args: &[Argument<'src>], // args: &[Argument<'src>],
) { // ) {
let (overloaded, same_argument_names) = self.get_operation_overloading( // let (overloaded, same_argument_names) = self.get_operation_overloading(
args, // args,
&::first_pass::OperationId::Constructor, // &::first_pass::OperationId::Constructor,
iface_name, // iface_name,
false, // false,
); // );
//
let self_ty = ident_ty(rust_ident(camel_case_ident(iface_name).as_str())); // let self_ty = ident_ty(rust_ident(camel_case_ident(iface_name).as_str()));
//
let kind = backend::ast::ImportFunctionKind::Method { // let kind = backend::ast::ImportFunctionKind::Method {
class: ctor_name.to_string(), // class: ctor_name.to_string(),
ty: self_ty.clone(), // ty: self_ty.clone(),
kind: backend::ast::MethodKind::Constructor, // kind: backend::ast::MethodKind::Constructor,
}; // };
//
let structural = false; // let structural = false;
//
// Constructors aren't annotated with `[Throws]` extended attributes // // Constructors aren't annotated with `[Throws]` extended attributes
// (how could they be, since they themselves are extended // // (how could they be, since they themselves are extended
// attributes?) so we must conservatively assume that they can // // attributes?) so we must conservatively assume that they can
// always throw. // // always throw.
// // //
// From https://heycam.github.io/webidl/#Constructor (emphasis // // From https://heycam.github.io/webidl/#Constructor (emphasis
// mine): // // mine):
// // //
// > The prose definition of a constructor must either return an IDL // // > The prose definition of a constructor must either return an IDL
// > value of a type corresponding to the interface the // // > value of a type corresponding to the interface the
// > `[Constructor]` extended attribute appears on, **or throw an // // > `[Constructor]` extended attribute appears on, **or throw an
// > exception**. // // > exception**.
let throws = true; // let throws = true;
//
for import_function in self.create_function( // for import_function in self.create_function(
"new", // "new",
overloaded, // overloaded,
same_argument_names, // same_argument_names,
&match self.convert_arguments(args) { // &match self.convert_arguments(args) {
Some(arguments) => arguments, // Some(arguments) => arguments,
None => return, // None => return,
}, // },
IdlType::Interface(iface_name), // IdlType::Interface(iface_name),
kind, // kind,
structural, // structural,
throws, // throws,
None, // None,
) { // ) {
program.imports.push(wrap_import_function(import_function)); // program.imports.push(wrap_import_function(import_function));
} // }
} // }
fn member_attribute( fn member_attribute(
&self, &self,
@ -571,28 +571,29 @@ impl<'src> FirstPassRecord<'src> {
id: &OperationId<'src>, id: &OperationId<'src>,
op_data: &OperationData2<'src>, op_data: &OperationData2<'src>,
) { ) {
let operation_kind = match id { let import_function_kind = |opkind| {
OperationId::Constructor => panic!("constructors are unsupported"), self.import_function_kind(self_name, data.global, op_data.is_static, opkind)
OperationId::Operation(_) => backend::ast::OperationKind::Regular,
OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
}; };
let operation = backend::ast::Operation { let kind = match id {
is_static: op_data.is_static, OperationId::Constructor(ctor_name) => {
kind: operation_kind, let self_ty = ident_ty(rust_ident(&camel_case_ident(self_name)));
}; backend::ast::ImportFunctionKind::Method {
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str())); class: ctor_name.0.to_string(),
let kind = if data.global { ty: self_ty.clone(),
backend::ast::ImportFunctionKind::ScopedMethod { kind: backend::ast::MethodKind::Constructor,
ty, }
operation,
} }
} else { OperationId::Operation(_) => {
backend::ast::ImportFunctionKind::Method { import_function_kind(backend::ast::OperationKind::Regular)
class: self_name.to_string(), }
ty, OperationId::IndexingGetter => {
kind: backend::ast::MethodKind::Operation(operation), import_function_kind(backend::ast::OperationKind::IndexingGetter)
}
OperationId::IndexingSetter => {
import_function_kind(backend::ast::OperationKind::IndexingSetter)
}
OperationId::IndexingDeleter => {
import_function_kind(backend::ast::OperationKind::IndexingDeleter)
} }
}; };
for method in self.create_imports(kind, id, op_data) { for method in self.create_imports(kind, id, op_data) {

View File

@ -522,7 +522,7 @@ impl<'src> FirstPassRecord<'src> {
) )
} }
fn import_function_kind( pub fn import_function_kind(
&self, &self,
self_name: &str, self_name: &str,
global: bool, global: bool,
@ -630,16 +630,28 @@ impl<'src> FirstPassRecord<'src> {
} }
} }
let (name, force_structural) = match id { let (name, force_structural, force_throws) = match id {
OperationId::Constructor => ("new", false), // Constructors aren't annotated with `[Throws]` extended attributes
OperationId::Operation(Some(s)) => (*s, false), // (how could they be, since they themselves are extended
// attributes?) so we must conservatively assume that they can
// always throw.
//
// From https://heycam.github.io/webidl/#Constructor (emphasis
// mine):
//
// > The prose definition of a constructor must either return an IDL
// > value of a type corresponding to the interface the
// > `[Constructor]` extended attribute appears on, **or throw an
// > exception**.
OperationId::Constructor(_) => ("new", false, true),
OperationId::Operation(Some(s)) => (*s, false, false),
OperationId::Operation(None) => { OperationId::Operation(None) => {
warn!("unsupported unnamed operation"); warn!("unsupported unnamed operation");
return Vec::new() return Vec::new()
} }
OperationId::IndexingGetter => ("get", true), OperationId::IndexingGetter => ("get", true, false),
OperationId::IndexingSetter => ("set", true), OperationId::IndexingSetter => ("set", true, false),
OperationId::IndexingDeleter => ("delete", true), OperationId::IndexingDeleter => ("delete", true, false),
}; };
let mut ret = Vec::new(); let mut ret = Vec::new();
@ -707,7 +719,7 @@ impl<'src> FirstPassRecord<'src> {
&ret_ty, &ret_ty,
kind.clone(), kind.clone(),
force_structural || is_structural(&signature.orig.attrs), force_structural || is_structural(&signature.orig.attrs),
throws(&signature.orig.attrs), force_throws || throws(&signature.orig.attrs),
None, None,
)); ));
} }