Skip to content

Support WebIDL constants #470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from Jul 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub enum ImportKind {
Static(ImportStatic),
Type(ImportType),
Enum(ImportEnum),
Const(Const),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really an import, constants are not really importing anything. This constants should really be a field in the program.

}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
Expand Down Expand Up @@ -174,6 +175,24 @@ pub struct TypeAlias {
pub src: syn::Type,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct Const {
pub vis: syn::Visibility,
pub name: Ident,
pub interface_name: Ident,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use class here, rather than interface_name, and made the value an Option<String>. It is more consist with the function import.

pub ty: syn::Type,
pub value: ConstValue,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
/// same as webidl::ast::ConstValue
pub enum ConstValue {
BooleanLiteral(bool),
FloatLiteral(f64),
IntegerLiteral(i64),
Null,
}

impl Program {
pub(crate) fn shared(&self) -> shared::Program {
shared::Program {
Expand Down Expand Up @@ -293,6 +312,7 @@ impl ImportKind {
ImportKind::Static(_) => false,
ImportKind::Type(_) => false,
ImportKind::Enum(_) => false,
ImportKind::Const(_) => false,
}
}

Expand All @@ -302,6 +322,7 @@ impl ImportKind {
ImportKind::Static(ref f) => shared::ImportKind::Static(f.shared()),
ImportKind::Type(ref f) => shared::ImportKind::Type(f.shared()),
ImportKind::Enum(ref f) => shared::ImportKind::Enum(f.shared()),
ImportKind::Const(ref f) => shared::ImportKind::Const(f.shared()),
}
}
}
Expand Down Expand Up @@ -404,3 +425,9 @@ impl StructField {
}
}
}

impl Const {
fn shared(&self) -> shared::Const {
shared::Const {}
}
}
40 changes: 40 additions & 0 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ impl ToTokens for ast::ImportKind {
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
ast::ImportKind::Const(ref c) => c.to_tokens(tokens),
}
}
}
Expand Down Expand Up @@ -842,6 +843,7 @@ impl<'a> ToTokens for DescribeImport<'a> {
ast::ImportKind::Static(_) => return,
ast::ImportKind::Type(_) => return,
ast::ImportKind::Enum(_) => return,
ast::ImportKind::Const(_) => return,
};
let describe_name = format!("__wbindgen_describe_{}", f.shim);
let describe_name = Ident::new(&describe_name, Span::call_site());
Expand Down Expand Up @@ -958,3 +960,41 @@ impl ToTokens for ast::TypeAlias {
}).to_tokens(into);
}
}

impl ToTokens for ast::Const {
fn to_tokens(&self, tokens: &mut TokenStream) {
use ast::ConstValue::*;

let vis = &self.vis;
let name = &self.name;
let interface_name = &self.interface_name;
let ty = &self.ty;

let value: TokenStream = match self.value {
BooleanLiteral(false) => quote!(false),
BooleanLiteral(true) => quote!(true),
// the actual type is unknown because of typedefs
// so we cannot use std::fxx::INFINITY
// but we can use type inference
FloatLiteral(f) if f.is_infinite() && f.is_sign_positive() => quote!(1.0 / 0.0),
FloatLiteral(f) if f.is_infinite() && f.is_sign_negative() => quote!(-1.0 / 0.0),
FloatLiteral(f) if f.is_nan() => quote!(0.0 / 0.0),
// again no suffix
// panics on +-inf, nan
FloatLiteral(f) => {
let f = Literal::f64_unsuffixed(f);
quote!(#f)
},
IntegerLiteral(i) => {
let i = Literal::i64_unsuffixed(i);
quote!(#i)
},
Null => unimplemented!(),
};
(quote! {
impl #interface_name {
#vis const #name: #ty = #value;
}
}).to_tokens(tokens);
}
}
10 changes: 10 additions & 0 deletions crates/backend/src/defined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl ImportedTypes for ast::ImportKind {
ast::ImportKind::Function(fun) => fun.imported_types(f),
ast::ImportKind::Type(ty) => ty.imported_types(f),
ast::ImportKind::Enum(enm) => enm.imported_types(f),
ast::ImportKind::Const(c) => c.imported_types(f),
}
}
}
Expand Down Expand Up @@ -229,6 +230,15 @@ impl ImportedTypes for ast::TypeAlias {
}
}

impl ImportedTypes for ast::Const {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}

/// Remove any methods, statics, &c, that reference types that are *not*
/// defined.
pub trait RemoveUndefinedImports {
Expand Down
1 change: 1 addition & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
}
shared::ImportKind::Type(_) => {}
shared::ImportKind::Enum(_) => {}
shared::ImportKind::Const(_) => {}
}
Ok(())
}
Expand Down
4 changes: 4 additions & 0 deletions crates/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub enum ImportKind {
Static(ImportStatic),
Type(ImportType),
Enum(ImportEnum),
Const(Const)
}

#[derive(Deserialize, Serialize)]
Expand Down Expand Up @@ -124,6 +125,9 @@ pub struct StructField {
pub comments: Vec<String>,
}

#[derive(Deserialize, Serialize)]
pub struct Const {}

pub fn new_function(struct_name: &str) -> String {
let mut name = format!("__wbg_");
name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));
Expand Down
35 changes: 30 additions & 5 deletions crates/webidl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ use std::path::Path;
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::util::{ident_ty, rust_ident, wrap_import_function};
use failure::ResultExt;
use heck::CamelCase;
use heck::{CamelCase, ShoutySnakeCase};
use quote::ToTokens;

use util::{
create_basic_method, create_function, create_getter, create_setter, webidl_ty_to_syn_ty,
TypePosition,
create_basic_method, create_function, create_getter, create_setter, webidl_const_ty_to_syn_ty,
webidl_const_v_to_backend_const_v, webidl_ty_to_syn_ty, TypePosition,
};

/// Either `Ok(t)` or `Err(failure::Error)`.
Expand Down Expand Up @@ -297,9 +297,9 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
attr.webidl_parse(program, self_name)
}
webidl::ast::InterfaceMember::Operation(ref op) => op.webidl_parse(program, self_name),
webidl::ast::InterfaceMember::Const(ref c) => c.webidl_parse(program, self_name),
// TODO
webidl::ast::InterfaceMember::Const(_)
| webidl::ast::InterfaceMember::Iterable(_)
webidl::ast::InterfaceMember::Iterable(_)
| webidl::ast::InterfaceMember::Maplike(_)
| webidl::ast::InterfaceMember::Setlike(_) => {
warn!("Unsupported WebIDL interface member: {:?}", self);
Expand Down Expand Up @@ -474,3 +474,28 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
Ok(())
}
}

impl<'a> WebidlParse<&'a str> for webidl::ast::Const {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
interface_name: &'a str,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe self_name here to be more consistent with the other impls.

) -> Result<()> {
let syn_ty = webidl_const_ty_to_syn_ty(&self.type_);
program.imports.push(backend::ast::Import {
module: None,
version: None,
js_namespace: None,
kind: backend::ast::ImportKind::Const(backend::ast::Const {
vis: syn::Visibility::Public(syn::VisPublic {
pub_token: Default::default(),
}),
name: rust_ident(self.name.to_shouty_snake_case().as_str()),
interface_name: rust_ident(interface_name),
ty: syn_ty,
value: webidl_const_v_to_backend_const_v(&self.value),
}),
});
Ok(())
}
}
29 changes: 29 additions & 0 deletions crates/webidl/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,35 @@ pub fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option<
})
}

pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type {
use webidl::ast::ConstType::*;

// similar to webidl_ty_to_syn_ty
match ty {
Boolean => ident_ty(raw_ident("bool")),
Byte => ident_ty(raw_ident("i8")),
Octet => ident_ty(raw_ident("u8")),
RestrictedDouble | UnrestrictedDouble => ident_ty(raw_ident("f64")),
RestrictedFloat | UnrestrictedFloat => ident_ty(raw_ident("f32")),
SignedLong => ident_ty(raw_ident("i32")),
SignedLongLong => ident_ty(raw_ident("i64")),
SignedShort => ident_ty(raw_ident("i16")),
UnsignedLong => ident_ty(raw_ident("u32")),
UnsignedLongLong => ident_ty(raw_ident("u64")),
UnsignedShort => ident_ty(raw_ident("u16")),
Identifier(ref id) => ident_ty(rust_ident(id)),
}
}

pub fn webidl_const_v_to_backend_const_v(v: &webidl::ast::ConstValue) -> backend::ast::ConstValue {
match *v {
webidl::ast::ConstValue::BooleanLiteral(b) => backend::ast::ConstValue::BooleanLiteral(b),
webidl::ast::ConstValue::FloatLiteral(f) => backend::ast::ConstValue::FloatLiteral(f),
webidl::ast::ConstValue::IntegerLiteral(i) => backend::ast::ConstValue::IntegerLiteral(i),
webidl::ast::ConstValue::Null => backend::ast::ConstValue::Null,
}
}

fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
syn::ArgCaptured {
pat: syn::Pat::Ident(syn::PatIdent {
Expand Down
Loading