diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index e7dc2980ac..144d2e3000 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -126,16 +126,16 @@ jobs: ~/.cargo/git ~/.cargo/registry key: ${{ runner.os }}-cargo-examples-${{ hashFiles('**/Cargo.lock') }} + - run: cd boa_examples - name: Build examples uses: actions-rs/cargo@v1 with: command: build - args: --examples -v - name: Run example classes uses: actions-rs/cargo@v1 with: command: run - args: --example classes + args: --bin classes doc: name: Documentation diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 65b2c6666d..aec41fae7e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -130,16 +130,16 @@ jobs: ~/.cargo/git ~/.cargo/registry key: ${{ runner.os }}-cargo-examples-${{ hashFiles('**/Cargo.lock') }} + - run: cd boa_examples - name: Build examples uses: actions-rs/cargo@v1 with: command: build - args: --examples -v - name: Run example classes uses: actions-rs/cargo@v1 with: command: run - args: --example classes + args: --bin classes doc: name: Documentation diff --git a/Cargo.lock b/Cargo.lock index 9fc066129d..3c97f5c790 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "boa_examples" +version = "0.11.0" +dependencies = [ + "boa_engine", + "boa_gc", + "gc", +] + [[package]] name = "boa_gc" version = "0.13.0" diff --git a/Cargo.toml b/Cargo.toml index 2a92388ffc..d351771690 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "boa_tester", "boa_unicode", "boa_wasm", + "boa_examples", ] # The release profile, used for `cargo build --release`. diff --git a/boa_examples/Cargo.toml b/boa_examples/Cargo.toml new file mode 100644 index 0000000000..97596905f3 --- /dev/null +++ b/boa_examples/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "boa_examples" +version = "0.11.0" +authors = ["boa-dev"] +repository = "https://github.com/boa-dev/boa" +license = "Unlicense/MIT" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +boa_engine = { path = "../boa_engine", features = ["console"] } +boa_gc = { path = "../boa_gc" } +gc = { version = "0.4.1" } diff --git a/boa_examples/scripts/calc.js b/boa_examples/scripts/calc.js new file mode 100644 index 0000000000..017534fab2 --- /dev/null +++ b/boa_examples/scripts/calc.js @@ -0,0 +1,14 @@ +module.exports = { + add: function (a, b) { + return a + b; + }, + subtract: function (a, b) { + return a - b; + }, + multiply: function (a, b) { + return a * b; + }, + divide: function (a, b) { + return a / b; + }, +}; diff --git a/boa_examples/scripts/calctest.js b/boa_examples/scripts/calctest.js new file mode 100644 index 0000000000..660453a1c1 --- /dev/null +++ b/boa_examples/scripts/calctest.js @@ -0,0 +1,8 @@ +//load module +let calc = require("./scripts/calc.js"); + +console.log("Using calc module"); +console.log("Add: " + calc.add(3, 3)); +console.log("Subtract: " + calc.subtract(3, 3)); +console.log("Multiply: " + calc.multiply(3, 3)); +console.log("Divide: " + calc.divide(3, 3)); diff --git a/boa_examples/scripts/enhancedglobal.js b/boa_examples/scripts/enhancedglobal.js new file mode 100644 index 0000000000..6870f79bf9 --- /dev/null +++ b/boa_examples/scripts/enhancedglobal.js @@ -0,0 +1,11 @@ +//access custom global variable +console.log("Custom global: " + customstring); + +//call a custom global function with arguments +console.log("Custom function: " + rusty_hello("Boa! Boa!")); + +//access a custom global object and call a member function of that object +let a = 5; +let b = 5; +let result = rusty_obj.add(a, b); +console.log("Custom object: Result from rusty_obj.add() : " + result); diff --git a/boa_examples/scripts/helloworld.js b/boa_examples/scripts/helloworld.js new file mode 100644 index 0000000000..74e66195d1 --- /dev/null +++ b/boa_examples/scripts/helloworld.js @@ -0,0 +1 @@ +console.log("Hello World from JS file!"); diff --git a/boa_engine/examples/classes.rs b/boa_examples/src/bin/classes.rs similarity index 100% rename from boa_engine/examples/classes.rs rename to boa_examples/src/bin/classes.rs index 55ea749f26..88c19e2d49 100644 --- a/boa_engine/examples/classes.rs +++ b/boa_examples/src/bin/classes.rs @@ -1,10 +1,10 @@ // NOTE: this example requires the `console` feature to run correctly. - use boa_engine::{ class::{Class, ClassBuilder}, property::Attribute, Context, JsResult, JsValue, }; + use boa_gc::{Finalize, Trace}; // We create a new struct that is going to represent a person. diff --git a/boa_engine/examples/closures.rs b/boa_examples/src/bin/closures.rs similarity index 100% rename from boa_engine/examples/closures.rs rename to boa_examples/src/bin/closures.rs diff --git a/boa_engine/examples/jsarray.rs b/boa_examples/src/bin/jsarray.rs similarity index 96% rename from boa_engine/examples/jsarray.rs rename to boa_examples/src/bin/jsarray.rs index 86c5bda183..2b369e109d 100644 --- a/boa_engine/examples/jsarray.rs +++ b/boa_examples/src/bin/jsarray.rs @@ -1,9 +1,11 @@ +// This example shows how to manipulate a Javascript array using Rust code. + use boa_engine::{ object::{FunctionBuilder, JsArray}, - Context, JsValue, + Context, JsResult, JsValue, }; -fn main() -> Result<(), JsValue> { +fn main() -> JsResult<()> { // We create a new `Context` to create a new Javascript executor. let context = &mut Context::default(); diff --git a/boa_examples/src/bin/loadfile.rs b/boa_examples/src/bin/loadfile.rs new file mode 100644 index 0000000000..1692aecf92 --- /dev/null +++ b/boa_examples/src/bin/loadfile.rs @@ -0,0 +1,28 @@ +// This example shows how to load, parse and execute JS code from a source file +// (./scripts/helloworld.js) + +use std::fs::read_to_string; + +use boa_engine::Context; + +fn main() { + let js_file_path = "./scripts/helloworld.js"; + + match read_to_string(js_file_path) { + Ok(src) => { + // Instantiate the execution context + let mut context = Context::default(); + // Parse the source code + match context.eval(src) { + Ok(res) => { + println!("{}", res.to_string(&mut context).unwrap()); + } + Err(e) => { + // Pretty print the error + eprintln!("Uncaught {}", e.display()); + } + }; + } + Err(msg) => eprintln!("Error: {}", msg), + } +} diff --git a/boa_examples/src/bin/loadstring.rs b/boa_examples/src/bin/loadstring.rs new file mode 100644 index 0000000000..f3c50098e6 --- /dev/null +++ b/boa_examples/src/bin/loadstring.rs @@ -0,0 +1,21 @@ +// This example loads, parses and executes a JS code string + +use boa_engine::Context; + +fn main() { + let js_code = "console.log('Hello World from a JS code string!')"; + + // Instantiate the execution context + let mut context = Context::default(); + + // Parse the source code + match context.eval(js_code) { + Ok(res) => { + println!("{}", res.to_string(&mut context).unwrap()); + } + Err(e) => { + // Pretty print the error + eprintln!("Uncaught {}", e.display()); + } + }; +} diff --git a/boa_examples/src/bin/modulehandler.rs b/boa_examples/src/bin/modulehandler.rs new file mode 100644 index 0000000000..e482447e33 --- /dev/null +++ b/boa_examples/src/bin/modulehandler.rs @@ -0,0 +1,59 @@ +// This example implements a custom module handler which mimics +// the require/module.exports pattern + +use boa_engine::{prelude::JsObject, property::Attribute, Context, JsResult, JsValue}; +use std::fs::read_to_string; + +fn main() { + let js_file_path = "./scripts/calctest.js"; + let buffer = read_to_string(js_file_path); + + if buffer.is_err() { + println!("Error: {}", buffer.unwrap_err()); + return; + } + + // Creating the execution context + let mut ctx = Context::default(); + + // Adding custom implementation that mimics 'require' + ctx.register_global_function("require", 0, require); + + // Adding custom object that mimics 'module.exports' + let moduleobj = JsObject::default(); + moduleobj + .set("exports", JsValue::from(" "), false, &mut ctx) + .unwrap(); + ctx.register_global_property("module", JsValue::from(moduleobj), Attribute::default()); + + // Instantiating the engine with the execution context + // Loading, parsing and executing the JS code from the source file + ctx.eval(&buffer.unwrap()).unwrap(); +} + +// Custom implementation that mimics the 'require' module loader +fn require(_: &JsValue, args: &[JsValue], ctx: &mut Context) -> JsResult { + let arg = args.get(0).unwrap(); + + // BUG: Dev branch seems to be passing string arguments along with quotes + let libfile = arg + .to_string(ctx) + .expect("Failed to convert to string") + .to_string(); + + // Read the module source file + println!("Loading: {}", libfile); + let buffer = read_to_string(libfile); + if let Err(..) = buffer { + println!("Error: {}", buffer.unwrap_err()); + Ok(JsValue::Rational(-1.0)) + } else { + // Load and parse the module source + ctx.eval(&buffer.unwrap()).unwrap(); + + // Access module.exports and return as ResultValue + let global_obj = ctx.global_object().to_owned(); + let module = global_obj.get("module", ctx).unwrap(); + module.as_object().unwrap().get("exports", ctx) + } +}