Skip to content

Commit 36fe4c2

Browse files
authored
Merge pull request #678 from derekdreery/webidl_namespace_support
Add support webidl namespaces.
2 parents 539e987 + ea05235 commit 36fe4c2

File tree

14 files changed

+509
-55
lines changed

14 files changed

+509
-55
lines changed

crates/backend/src/ast.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::BTreeMap;
12
use proc_macro2::{Ident, Span};
23
use shared;
34
use syn;
@@ -19,6 +20,8 @@ pub struct Program {
1920
pub structs: Vec<Struct>,
2021
/// rust consts
2122
pub consts: Vec<Const>,
23+
/// rust submodules
24+
pub modules: BTreeMap<Ident, Module>,
2225
}
2326

2427
/// A rust to js interface. Allows interaction with rust objects/functions
@@ -220,13 +223,25 @@ pub enum ConstValue {
220223
Null,
221224
}
222225

226+
/// A rust module
227+
///
228+
/// This exists to give the ability to namespace js imports.
229+
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
230+
pub struct Module {
231+
pub vis: syn::Visibility,
232+
/// js -> rust interfaces
233+
pub imports: Vec<Import>,
234+
}
235+
223236
impl Program {
224237
pub(crate) fn shared(&self) -> Result<shared::Program, Diagnostic> {
225238
Ok(shared::Program {
226239
exports: self.exports.iter().map(|a| a.shared()).collect(),
227240
structs: self.structs.iter().map(|a| a.shared()).collect(),
228241
enums: self.enums.iter().map(|a| a.shared()).collect(),
229242
imports: self.imports.iter()
243+
// add in imports from inside modules
244+
.chain(self.modules.values().flat_map(|m| m.imports.iter()))
230245
.map(|a| a.shared())
231246
.collect::<Result<_, Diagnostic>>()?,
232247
version: shared::version(),

crates/backend/src/codegen.rs

+45
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ impl TryToTokens for ast::Program {
4343
for i in self.imports.iter() {
4444
DescribeImport(&i.kind).to_tokens(tokens);
4545

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

1114+
/// Struct to help implementing TryToTokens over the key/value pairs from the hashmap.
1115+
struct ModuleInIter<'a> {
1116+
name: &'a Ident,
1117+
module: &'a ast::Module
1118+
}
1119+
1120+
impl<'a> From<(&'a Ident, &'a ast::Module)> for ModuleInIter<'a> {
1121+
fn from((name, module): (&'a Ident, &'a ast::Module)) -> ModuleInIter<'a> {
1122+
ModuleInIter { name, module }
1123+
}
1124+
}
1125+
1126+
impl<'a> TryToTokens for ModuleInIter<'a> {
1127+
fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
1128+
let name = &self.name;
1129+
let imports = &self.module.imports;
1130+
let mut errors = Vec::new();
1131+
for i in imports.iter() {
1132+
DescribeImport(&i.kind).to_tokens(tokens);
1133+
}
1134+
let vis = &self.module.vis;
1135+
let mut body = TokenStream::new();
1136+
for i in imports.iter() {
1137+
if let Err(e) = i.kind.try_to_tokens(&mut body) {
1138+
errors.push(e);
1139+
}
1140+
}
1141+
Diagnostic::from_vec(errors)?;
1142+
(quote!{
1143+
#vis mod #name {
1144+
#body
1145+
}
1146+
}).to_tokens(tokens);
1147+
Ok(())
1148+
}
1149+
}
1150+
11061151
/// Emits the necessary glue tokens for "descriptor", generating an appropriate
11071152
/// symbol name as well as attributes around the descriptor function itself.
11081153
struct Descriptor<'a, T>(&'a Ident, T);

crates/web-sys/build.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::path;
1313
use std::process::{self, Command};
1414

1515
fn main() {
16+
env_logger::init();
17+
1618
if let Err(e) = try_main() {
1719
eprintln!("Error: {}", e);
1820
for c in e.iter_causes() {
@@ -24,11 +26,9 @@ fn main() {
2426

2527
fn try_main() -> Result<(), failure::Error> {
2628
println!("cargo:rerun-if-changed=build.rs");
27-
env_logger::init();
28-
2929
println!("cargo:rerun-if-changed=webidls/enabled");
30-
let entries = fs::read_dir("webidls/enabled").context("reading webidls/enabled directory")?;
3130

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

4544
let bindings = match wasm_bindgen_webidl::compile(&source.contents) {
@@ -70,9 +69,9 @@ fn try_main() -> Result<(), failure::Error> {
7069
let status = Command::new("rustfmt")
7170
.arg(&out_file_path)
7271
.status()
73-
.context("running rustfmt")?;
72+
.context("running rustfmt")?;
7473
if !status.success() {
75-
bail!("rustfmt failed: {}", status)
74+
bail!("rustfmt failed: {}", status)
7675
}
7776
}
7877

crates/web-sys/tests/wasm/console.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use wasm_bindgen_test::*;
2+
use wasm_bindgen::prelude::*;
3+
use web_sys::console;
4+
5+
#[wasm_bindgen_test]
6+
fn test_console() {
7+
console::time("test label");
8+
console::time_end("test label");
9+
}

crates/web-sys/tests/wasm/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod anchor_element;
1414
pub mod body_element;
1515
pub mod br_element;
1616
pub mod button_element;
17+
pub mod console;
1718
pub mod div_element;
1819
pub mod element;
1920
pub mod event;

crates/webidl-tests/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ pub mod consts;
1010
pub mod enums;
1111
pub mod simple;
1212
pub mod throws;
13+
pub mod namespace;

crates/webidl-tests/namespace.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const strictEqual = require('assert').strictEqual;
2+
3+
global.mathtest = {};
4+
5+
global.mathtest.powf = function powf(base, exp) {
6+
return Math.pow(base, exp);
7+
}
8+
9+
global.mathtest.add_one = function add_one(val) {
10+
return val + 1;
11+
}

crates/webidl-tests/namespace.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use wasm_bindgen_test::*;
2+
3+
include!(concat!(env!("OUT_DIR"), "/namespace.rs"));
4+
5+
#[wasm_bindgen_test]
6+
fn simple_namespace_test() {
7+
assert_eq!(mathtest::add_one(1), 2);
8+
assert_eq!(mathtest::powf(1.0, 100.0), 1.0);
9+
assert_eq!(mathtest::powf(10.0, 2.0), 100.0);
10+
}

crates/webidl-tests/namespace.webidl

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace mathtest {
2+
long add_one(long val);
3+
double powf(double base, double exponent);
4+
};

0 commit comments

Comments
 (0)