Merge pull request #785 from afdw/master

Add initial support for unions in return types, add more fixes for case of identifiers
This commit is contained in:
Alex Crichton 2018-09-05 09:26:42 -07:00 committed by GitHub
commit c6d3011cff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 45 deletions

View File

@ -1,12 +1,11 @@
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};
use util::{TypePosition, camel_case_ident, snake_case_ident, shared_ref, option_ty, array};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
pub(crate) enum IdlType<'a> {
@ -337,7 +336,7 @@ terms_to_idl_type! {
impl<'a> IdlType<'a> {
/// Generates a snake case type name.
pub(crate) fn push_type_name(&self, dst: &mut String) {
pub(crate) fn push_snake_case_name(&self, dst: &mut String) {
match self {
IdlType::Boolean => dst.push_str("bool"),
IdlType::Byte => dst.push_str("i8"),
@ -348,13 +347,13 @@ impl<'a> IdlType<'a> {
IdlType::UnsignedLong => dst.push_str("u32"),
IdlType::LongLong => dst.push_str("i64"),
IdlType::UnsignedLongLong => dst.push_str("u64"),
IdlType::Float |
IdlType::UnrestrictedFloat => dst.push_str("f32"),
IdlType::Double |
IdlType::UnrestrictedDouble => dst.push_str("f64"),
IdlType::DomString |
IdlType::ByteString |
IdlType::UsvString => dst.push_str("str"),
| IdlType::Float
| IdlType::UnrestrictedFloat => dst.push_str("f32"),
| IdlType::Double
| IdlType::UnrestrictedDouble => dst.push_str("f64"),
| IdlType::DomString
| IdlType::ByteString
| IdlType::UsvString => dst.push_str("str"),
IdlType::Object => dst.push_str("object"),
IdlType::Symbol => dst.push_str("symbol"),
IdlType::Error => dst.push_str("error"),
@ -371,31 +370,31 @@ impl<'a> IdlType<'a> {
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::Interface(name) => dst.push_str(&snake_case_ident(name)),
IdlType::Dictionary(name) => dst.push_str(&snake_case_ident(name)),
IdlType::Enum(name) => dst.push_str(&snake_case_ident(name)),
IdlType::Nullable(idl_type) => {
dst.push_str("opt_");
idl_type.push_type_name(dst);
idl_type.push_snake_case_name(dst);
},
IdlType::FrozenArray(idl_type) => {
idl_type.push_type_name(dst);
idl_type.push_snake_case_name(dst);
dst.push_str("_frozen_array");
},
IdlType::Sequence(idl_type) => {
idl_type.push_type_name(dst);
idl_type.push_snake_case_name(dst);
dst.push_str("_sequence");
},
IdlType::Promise(idl_type) => {
idl_type.push_type_name(dst);
idl_type.push_snake_case_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);
idl_type_from.push_snake_case_name(dst);
dst.push_str("_to_");
idl_type_to.push_type_name(dst);
idl_type_to.push_snake_case_name(dst);
},
IdlType::Union(idl_types) => {
dst.push_str("union_of_");
@ -406,7 +405,7 @@ impl<'a> IdlType<'a> {
} else {
dst.push_str("_and_");
}
idl_type.push_type_name(dst);
idl_type.push_snake_case_name(dst);
}
},
@ -415,14 +414,6 @@ impl<'a> IdlType<'a> {
}
}
/// 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 {
@ -467,8 +458,8 @@ impl<'a> IdlType<'a> {
IdlType::Float32Array => Some(array("f32", pos)),
IdlType::Float64Array => Some(array("f64", pos)),
IdlType::Interface(name) |
IdlType::Dictionary(name) => {
| IdlType::Interface(name)
| IdlType::Dictionary(name) => {
let ty = ident_ty(rust_ident(camel_case_ident(name).as_str()));
if pos == TypePosition::Argument {
Some(shared_ref(ty))
@ -491,7 +482,27 @@ impl<'a> IdlType<'a> {
}
}
IdlType::Record(_idl_type_from, _idl_type_to) => None,
IdlType::Union(_idl_types) => None,
IdlType::Union(idl_types) => {
// Handles union types in all places except operation argument types.
// Currently treats them as object type, if possible.
// TODO: add better support for union types here?
// Approaches for it:
// 1. Use strategy of finding the nearest common subclass (finding the best type
// that is suitable for all values of this union)
// 2. Generate enum with payload in Rust for each union type
if idl_types
.iter()
.all(|idl_type|
match idl_type {
IdlType::Interface(..) => true,
_ => false,
}
) {
IdlType::Object.to_syn_type(pos)
} else {
None
}
},
IdlType::Any => {
let path = vec![rust_ident("wasm_bindgen"), rust_ident("JsValue")];
@ -552,7 +563,7 @@ impl<'a> IdlType<'a> {
.flat_map(|idl_type| idl_type.flatten())
.collect(),
idl_type @ _ => vec![idl_type.clone()]
idl_type @ _ => vec![idl_type.clone()],
}
}
}

View File

@ -41,14 +41,13 @@ use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::defined::ImportedTypeReferences;
use backend::util::{ident_ty, rust_ident, raw_ident, wrap_import_function};
use failure::ResultExt;
use heck::{ShoutySnakeCase, SnakeCase};
use proc_macro2::{Ident, Span};
use weedle::attribute::{ExtendedAttributeList};
use weedle::dictionary::DictionaryMember;
use first_pass::{FirstPass, FirstPassRecord, OperationId, InterfaceData};
use first_pass::OperationData;
use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc};
use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, shouty_snake_case_ident, snake_case_ident, mdn_doc};
use idl_type::ToIdlType;
pub use error::{Error, ErrorKind, Result};
@ -280,7 +279,7 @@ impl<'src> FirstPassRecord<'src> {
Some(ast::DictionaryField {
required: field.required.is_some(),
name: rust_ident(&field.identifier.0.to_snake_case()),
name: rust_ident(&snake_case_ident(field.identifier.0)),
ty,
})
}
@ -293,7 +292,7 @@ impl<'src> FirstPassRecord<'src> {
) {
let mut module = backend::ast::Module {
vis: public(),
name: rust_ident(name.to_snake_case().as_str()),
name: rust_ident(snake_case_ident(name).as_str()),
imports: Default::default(),
};
@ -368,7 +367,7 @@ impl<'src> FirstPassRecord<'src> {
program.consts.push(backend::ast::Const {
vis: public(),
name: rust_ident(member.identifier.0.to_shouty_snake_case().as_str()),
name: rust_ident(shouty_snake_case_ident(member.identifier.0).as_str()),
class: Some(rust_ident(camel_case_ident(&self_name).as_str())),
ty,
value: webidl_const_v_to_backend_const_v(&member.const_value),

View File

@ -3,7 +3,7 @@ use std::ptr;
use backend;
use backend::util::{ident_ty, leading_colon_path_ty, raw_ident, rust_ident};
use heck::{CamelCase, SnakeCase};
use heck::{CamelCase, ShoutySnakeCase, SnakeCase};
use proc_macro2::Ident;
use syn;
use weedle;
@ -23,9 +23,28 @@ pub(crate) fn shared_ref(ty: syn::Type) -> syn::Type {
}.into()
}
/// Fix camelcase of identifiers like HTMLBRElement
/// Fix case of identifiers like `HTMLBRElement` or `texImage2D`
fn fix_ident(identifier: &str) -> String {
identifier
.replace("HTML", "HTML_")
.replace("1D", "_1d")
.replace("2D", "_2d")
.replace("3D", "_3d")
}
/// Convert an identifier to camel case
pub fn camel_case_ident(identifier: &str) -> String {
identifier.replace("HTML", "HTML_").to_camel_case()
fix_ident(identifier).to_camel_case()
}
/// Convert an identifier to shouty snake case
pub fn shouty_snake_case_ident(identifier: &str) -> String {
fix_ident(identifier).to_shouty_snake_case()
}
/// Convert an identifier to snake case
pub fn snake_case_ident(identifier: &str) -> String {
fix_ident(identifier).to_snake_case()
}
// Returns a link to MDN
@ -309,7 +328,7 @@ impl<'src> FirstPassRecord<'src> {
let ret = ty.to_idl_type(self)?;
self.create_one_function(
&name,
&name.to_snake_case(),
&snake_case_ident(name),
None.into_iter(),
&ret,
kind,
@ -494,7 +513,7 @@ impl<'src> FirstPassRecord<'src> {
None => continue,
};
let mut rust_name = name.to_snake_case();
let mut rust_name = snake_case_ident(name);
let mut first = true;
for (i, arg) in signature.args.iter().enumerate() {
// Find out if any other known signature either has the same
@ -541,9 +560,9 @@ impl<'src> FirstPassRecord<'src> {
// then we can't use that if the types are also the same because
// otherwise it could be ambiguous.
if any_same_name && any_different_type {
arg.push_type_name(&mut rust_name);
arg.push_snake_case_name(&mut rust_name);
} else {
rust_name.push_str(&arg_name.to_snake_case());
rust_name.push_str(&snake_case_ident(arg_name));
}
}
ret.extend(self.create_one_function(

View File

@ -19,7 +19,7 @@ pub fn draw() {
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<web_sys::CanvasRenderingContext2D>()
.dyn_into::<web_sys::CanvasRenderingContext2d>()
.unwrap();
context.begin_path();