Skip to content

Add support webidl namespaces. #678

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 13 commits into from
Aug 13, 2018
15 changes: 15 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use proc_macro2::{Ident, Span};
use shared;
use syn;
Expand All @@ -19,6 +20,8 @@ pub struct Program {
pub structs: Vec<Struct>,
/// rust consts
pub consts: Vec<Const>,
/// rust submodules
pub modules: BTreeMap<Ident, Module>,
}

/// A rust to js interface. Allows interaction with rust objects/functions
Expand Down Expand Up @@ -220,13 +223,25 @@ pub enum ConstValue {
Null,
}

/// A rust module
///
/// This exists to give the ability to namespace js imports.
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct Module {
pub vis: syn::Visibility,
/// js -> rust interfaces
pub imports: Vec<Import>,
}

impl Program {
pub(crate) fn shared(&self) -> Result<shared::Program, Diagnostic> {
Ok(shared::Program {
exports: self.exports.iter().map(|a| a.shared()).collect(),
structs: self.structs.iter().map(|a| a.shared()).collect(),
enums: self.enums.iter().map(|a| a.shared()).collect(),
imports: self.imports.iter()
// add in imports from inside modules
.chain(self.modules.values().flat_map(|m| m.imports.iter()))
.map(|a| a.shared())
.collect::<Result<_, Diagnostic>>()?,
version: shared::version(),
Expand Down
45 changes: 45 additions & 0 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ impl TryToTokens for ast::Program {
for i in self.imports.iter() {
DescribeImport(&i.kind).to_tokens(tokens);

// If there is a js namespace, check that name isn't a type. If it is,
// this import might be a method on that type.
if let Some(ns) = &i.js_namespace {
if types.contains(ns) && i.kind.fits_on_impl() {
let kind = match i.kind.try_to_token_stream() {
Expand All @@ -61,6 +63,11 @@ impl TryToTokens for ast::Program {
errors.push(e);
}
}
for m in self.modules.iter() {
if let Err(e) = ModuleInIter::from(m).try_to_tokens(tokens) {
errors.push(e);
}
}
for e in self.enums.iter() {
e.to_tokens(tokens);
}
Expand All @@ -87,6 +94,7 @@ impl TryToTokens for ast::Program {
// Each JSON blob is prepended with the length of the JSON blob so when
// all these sections are concatenated in the final wasm file we know
// how to extract all the JSON pieces, so insert the byte length here.
// The value is little-endian.
let generated_static_length = description.len() + 4;
let mut bytes = vec![
(description.len() >> 0) as u8,
Expand Down Expand Up @@ -1103,6 +1111,43 @@ impl ToTokens for ast::Const {
}
}

/// Struct to help implementing TryToTokens over the key/value pairs from the hashmap.
struct ModuleInIter<'a> {
name: &'a Ident,
module: &'a ast::Module
}

impl<'a> From<(&'a Ident, &'a ast::Module)> for ModuleInIter<'a> {
fn from((name, module): (&'a Ident, &'a ast::Module)) -> ModuleInIter<'a> {
ModuleInIter { name, module }
}
}

impl<'a> TryToTokens for ModuleInIter<'a> {
fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
let name = &self.name;
let imports = &self.module.imports;
let mut errors = Vec::new();
for i in imports.iter() {
DescribeImport(&i.kind).to_tokens(tokens);
}
let vis = &self.module.vis;
let mut body = TokenStream::new();
for i in imports.iter() {
if let Err(e) = i.kind.try_to_tokens(&mut body) {
errors.push(e);
}
}
Diagnostic::from_vec(errors)?;
(quote!{
#vis mod #name {
#body
}
}).to_tokens(tokens);
Ok(())
}
}

/// Emits the necessary glue tokens for "descriptor", generating an appropriate
/// symbol name as well as attributes around the descriptor function itself.
struct Descriptor<'a, T>(&'a Ident, T);
Expand Down
13 changes: 6 additions & 7 deletions crates/web-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use std::path;
use std::process::{self, Command};

fn main() {
env_logger::init();

if let Err(e) = try_main() {
eprintln!("Error: {}", e);
for c in e.iter_causes() {
Expand All @@ -24,11 +26,9 @@ fn main() {

fn try_main() -> Result<(), failure::Error> {
println!("cargo:rerun-if-changed=build.rs");
env_logger::init();

println!("cargo:rerun-if-changed=webidls/enabled");
let entries = fs::read_dir("webidls/enabled").context("reading webidls/enabled directory")?;

let entries = fs::read_dir("webidls/enabled").context("reading webidls/enabled directory")?;
let mut source = SourceFile::default();
for entry in entries {
let entry = entry.context("getting webidls/enabled/*.webidl entry")?;
Expand All @@ -38,8 +38,7 @@ fn try_main() -> Result<(), failure::Error> {
}
println!("cargo:rerun-if-changed={}", path.display());
source = source.add_file(&path)
.with_context(|_| format!("reading contents of file \"{}\"",
path.display()))?;
.with_context(|_| format!("reading contents of file \"{}\"", path.display()))?;
}

let bindings = match wasm_bindgen_webidl::compile(&source.contents) {
Expand Down Expand Up @@ -70,9 +69,9 @@ fn try_main() -> Result<(), failure::Error> {
let status = Command::new("rustfmt")
.arg(&out_file_path)
.status()
.context("running rustfmt")?;
.context("running rustfmt")?;
if !status.success() {
bail!("rustfmt failed: {}", status)
bail!("rustfmt failed: {}", status)
}
}

Expand Down
9 changes: 9 additions & 0 deletions crates/web-sys/tests/wasm/console.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
use web_sys::console;

#[wasm_bindgen_test]
fn test_console() {
console::time("test label");
console::time_end("test label");
}
1 change: 1 addition & 0 deletions crates/web-sys/tests/wasm/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod anchor_element;
pub mod body_element;
pub mod br_element;
pub mod button_element;
pub mod console;
pub mod div_element;
pub mod element;
pub mod event;
Expand Down
1 change: 1 addition & 0 deletions crates/webidl-tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pub mod consts;
pub mod enums;
pub mod simple;
pub mod throws;
pub mod namespace;
11 changes: 11 additions & 0 deletions crates/webidl-tests/namespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const strictEqual = require('assert').strictEqual;

global.mathtest = {};

global.mathtest.powf = function powf(base, exp) {
return Math.pow(base, exp);
}

global.mathtest.add_one = function add_one(val) {
return val + 1;
}
10 changes: 10 additions & 0 deletions crates/webidl-tests/namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use wasm_bindgen_test::*;

include!(concat!(env!("OUT_DIR"), "/namespace.rs"));

#[wasm_bindgen_test]
fn simple_namespace_test() {
assert_eq!(mathtest::add_one(1), 2);
assert_eq!(mathtest::powf(1.0, 100.0), 1.0);
assert_eq!(mathtest::powf(10.0, 2.0), 100.0);
}
4 changes: 4 additions & 0 deletions crates/webidl-tests/namespace.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace mathtest {
long add_one(long val);
double powf(double base, double exponent);
};
Loading