mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 18:20:51 +00:00
Merge pull request #470 from jrakow/webidl-const
Support WebIDL constants
This commit is contained in:
commit
696678b8cc
@ -42,6 +42,7 @@ pub enum ImportKind {
|
||||
Static(ImportStatic),
|
||||
Type(ImportType),
|
||||
Enum(ImportEnum),
|
||||
Const(Const),
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||
@ -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,
|
||||
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 {
|
||||
@ -293,6 +312,7 @@ impl ImportKind {
|
||||
ImportKind::Static(_) => false,
|
||||
ImportKind::Type(_) => false,
|
||||
ImportKind::Enum(_) => false,
|
||||
ImportKind::Const(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -404,3 +425,9 @@ impl StructField {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Const {
|
||||
fn shared(&self) -> shared::Const {
|
||||
shared::Const {}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
@ -1758,6 +1758,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
}
|
||||
shared::ImportKind::Type(_) => {}
|
||||
shared::ImportKind::Enum(_) => {}
|
||||
shared::ImportKind::Const(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ pub enum ImportKind {
|
||||
Static(ImportStatic),
|
||||
Type(ImportType),
|
||||
Enum(ImportEnum),
|
||||
Const(Const)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
@ -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()));
|
||||
|
@ -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)`.
|
||||
@ -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);
|
||||
@ -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,
|
||||
) -> 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(())
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
190
crates/webidl/tests/all/consts.rs
Normal file
190
crates/webidl/tests/all/consts.rs
Normal file
@ -0,0 +1,190 @@
|
||||
use super::project;
|
||||
|
||||
#[test]
|
||||
fn bool() {
|
||||
project()
|
||||
.file(
|
||||
"foo.webidl",
|
||||
r#"
|
||||
interface Foo {
|
||||
const boolean not_true = false;
|
||||
const boolean not_false = true;
|
||||
};
|
||||
"#,
|
||||
)
|
||||
// a corresponding const in the js implementation is not required
|
||||
// value is taken directly from idl
|
||||
.file(
|
||||
"foo.js",
|
||||
r#"
|
||||
export class Foo {
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
extern crate wasm_bindgen;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod foo;
|
||||
use foo::Foo;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn test() {
|
||||
let falsish: bool = Foo::NOT_TRUE;
|
||||
assert!(!falsish);
|
||||
let trueish: bool = Foo::NOT_FALSE;
|
||||
assert!(trueish);
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ints() {
|
||||
project()
|
||||
.file(
|
||||
"foo.webidl",
|
||||
r#"
|
||||
interface Byte {
|
||||
const byte imin = -128;
|
||||
const byte imax = 127;
|
||||
const octet umin = 0;
|
||||
const octet umax = 255;
|
||||
};
|
||||
interface Short {
|
||||
const short imin = -32768;
|
||||
const short imax = 32767;
|
||||
const unsigned short umin = 0;
|
||||
const unsigned short umax = 65535;
|
||||
};
|
||||
interface Long {
|
||||
const long imin = -2147483648;
|
||||
const long imax = 2147483647;
|
||||
const unsigned long umin = 0;
|
||||
const unsigned long umax = 4294967295;
|
||||
};
|
||||
interface LongLong {
|
||||
const long long imin = -9223372036854775808;
|
||||
const long long imax = 9223372036854775807;
|
||||
const unsigned long long umin = 0;
|
||||
// bug in webidl
|
||||
// https://github.com/sgodwincs/webidl-rs/issues/15
|
||||
//const unsigned long long umax = 18446744073709551615;
|
||||
};
|
||||
"#,
|
||||
)
|
||||
// a corresponding const in the js implementation is not required
|
||||
// value is taken directly from idl
|
||||
.file(
|
||||
"foo.js",
|
||||
r#"
|
||||
export class Byte {
|
||||
}
|
||||
export class Short {
|
||||
}
|
||||
export class Long {
|
||||
}
|
||||
export class LongLong {
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
extern crate wasm_bindgen;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod foo;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn test() {
|
||||
assert_eq!(foo::Byte::IMIN, i8::min_value());
|
||||
assert_eq!(foo::Byte::IMAX, i8::max_value());
|
||||
assert_eq!(foo::Byte::UMIN, u8::min_value());
|
||||
assert_eq!(foo::Byte::UMAX, u8::max_value());
|
||||
|
||||
assert_eq!(foo::Short::IMIN, i16::min_value());
|
||||
assert_eq!(foo::Short::IMAX, i16::max_value());
|
||||
assert_eq!(foo::Short::UMIN, u16::min_value());
|
||||
assert_eq!(foo::Short::UMAX, u16::max_value());
|
||||
|
||||
assert_eq!(foo::Long::IMIN, i32::min_value());
|
||||
assert_eq!(foo::Long::IMAX, i32::max_value());
|
||||
assert_eq!(foo::Long::UMIN, u32::min_value());
|
||||
assert_eq!(foo::Long::UMAX, u32::max_value());
|
||||
|
||||
assert_eq!(foo::LongLong::IMIN, i64::min_value());
|
||||
assert_eq!(foo::LongLong::IMAX, i64::max_value());
|
||||
assert_eq!(foo::LongLong::UMIN, u64::min_value());
|
||||
//assert_eq!(foo::LongLong::UMAX, u64::max_value());
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floats() {
|
||||
project()
|
||||
.file(
|
||||
"foo.webidl",
|
||||
r#"
|
||||
interface floats {
|
||||
const float f = 0.0;
|
||||
const unrestricted float neg_inf = -Infinity;
|
||||
const unrestricted float inf = Infinity;
|
||||
const unrestricted float nan = NaN;
|
||||
};
|
||||
interface doubles {
|
||||
const double d = 0.0;
|
||||
const unrestricted double neg_inf = -Infinity;
|
||||
const unrestricted double inf = Infinity;
|
||||
const unrestricted double nan = NaN;
|
||||
};
|
||||
"#,
|
||||
)
|
||||
// a corresponding const in the js implementation is not required
|
||||
// value is taken directly from idl
|
||||
.file(
|
||||
"foo.js",
|
||||
r#"
|
||||
export class floats {
|
||||
}
|
||||
export class doubles {
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
extern crate wasm_bindgen;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod foo;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn test() {
|
||||
assert_eq!(foo::floats::F, 0.0);
|
||||
assert!(foo::floats::NEG_INF.is_infinite());
|
||||
assert!(foo::floats::NEG_INF.is_sign_negative());
|
||||
assert!(foo::floats::INF.is_infinite());
|
||||
assert!(foo::floats::INF.is_sign_positive());
|
||||
assert!(foo::floats::NAN.is_nan());
|
||||
|
||||
assert_eq!(foo::doubles::D, 0.0);
|
||||
assert!(foo::doubles::NEG_INF.is_infinite());
|
||||
assert!(foo::doubles::NEG_INF.is_sign_negative());
|
||||
assert!(foo::doubles::INF.is_infinite());
|
||||
assert!(foo::doubles::INF.is_sign_positive());
|
||||
assert!(foo::doubles::NAN.is_nan());
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.test();
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
extern crate wasm_bindgen_test_project_builder as project_builder;
|
||||
use project_builder::project;
|
||||
|
||||
mod simple;
|
||||
mod consts;
|
||||
mod enums;
|
||||
mod simple;
|
||||
mod throws;
|
||||
|
Loading…
x
Reference in New Issue
Block a user