### Install Rust using rustup Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Use this command to install Rust and manage toolchains. It is the recommended method for setting up your Rust environment. ```shell curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -------------------------------- ### Install @boa-dev/boa_wasm Source: https://github.com/boa-dev/boa/blob/main/ffi/wasm/README.md Install the package using npm or yarn. ```bash npm install @boa-dev/boa_wasm ``` ```bash yarn add @boa-dev/boa_wasm ``` -------------------------------- ### Boa CLI Usage Examples Source: https://context7.com/boa-dev/boa/llms.txt Provides examples of how to use the `boa_cli` for running JavaScript files, entering the REPL, and using various command-line flags for debugging and configuration. ```bash # Install cargo install boa_cli # Run a JS file boa script.js # REPL boa # Strict mode boa --strict script.js # Treat as ES module boa --module -r ./src app.mjs # Dump AST (debug, json, json-pretty) boa --dump-ast json-pretty script.js # Execution trace boa --trace script.js # Generate instruction flowgraph (graphviz or mermaid) boa --flowgraph graphviz script.js | dot -Tpng -o flow.png # Inject $boa debug object boa --debug-object script.js # Benchmark cargo run --release -p boa_cli -- bench-v8/combined.js ``` -------------------------------- ### Text VM Tracing Output Example Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md Example of the tracing output generated when the VM's trace feature is enabled. Useful for debugging and understanding execution flow. ```text Time Opcode Operands Top Of Stack 6μs PushOne dst:0 1 7μs PutLexicalValue src:0, binding_index:0 ``` -------------------------------- ### Start Boa REPL Source: https://github.com/boa-dev/boa/blob/main/cli/README.md Launch the Boa interactive Read-Eval-Print Loop (REPL) by running the 'boa' command without any arguments. ```shell boa ``` -------------------------------- ### Review Boa Bytecode Snapshots Source: https://github.com/boa-dev/boa/blob/main/tests/insta-bytecode/README.md Use this command to review generated bytecode snapshots. Ensure `cargo-insta` is installed as a dependency. ```bash cargo insta test --review ``` ```bash insta review ``` -------------------------------- ### SpiderMonkey Bytecode Output Example Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md An example of bytecode output from SpiderMonkey, used for comparison. This format shows location, opcode, and operands. ```text loc op ----- -- 00000: GlobalOrEvalDeclInstantiation 0 # main: 00005: One # 1 00006: InitGLexical "a" # 1 00011: Pop # 00012: Int8 2 # 2 00014: InitGLexical "b" # 2 00019: Pop # 00020: GetGName "dis" # dis ``` -------------------------------- ### Install Boa CLI with Cargo Source: https://github.com/boa-dev/boa/blob/main/cli/README.md Install the boa_cli package using Cargo, Rust's package manager. ```shell cargo install boa_cli ``` -------------------------------- ### Creating an Empty Object Source: https://github.com/boa-dev/boa/blob/main/docs/shapes.md This snippet initializes an empty object, which serves as the starting point for shape transitions. ```js let o = {}; ``` -------------------------------- ### Get String Summary with $boa.string.summary Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Obtain a concise summary of a string's properties, including its storage type and encoding. ```javascript $boa.string.summary("Greeting") // { storage: "heap", encoding: "latin1" } ``` -------------------------------- ### Build All Workspace Documentation Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Generates documentation for all features and private items across the entire workspace, including dependencies. This can result in a larger documentation set. ```shell cargo doc --all-features --document-private-items --workspace ``` -------------------------------- ### Context::default and Context::builder Source: https://context7.com/boa-dev/boa/llms.txt Demonstrates how to create an ECMAScript execution context. `Context::default()` provides a basic context, while `Context::builder()` allows for custom configuration of job executors, module loaders, and other host hooks. ```APIDOC ## `Context::default` / `Context::builder` — Create an execution context `Context` is the primary way to interact with the JavaScript runtime. `Context::default()` creates a context with a default job executor and module loader. `Context::builder()` exposes a `ContextBuilder` to configure custom `JobExecutor`, `ModuleLoader`, clock, and other host hooks before building. ```rust use boa_engine::{Context, Source, JsResult}; fn main() -> JsResult<()> { // Default context (synchronous, no module loader) let mut context = Context::default(); let result = context.eval(Source::from_bytes("1 + 2"))?; println!("{}", result.display()); // 3 Ok(()) } ``` ``` -------------------------------- ### Create and Consume JavaScript Promises from Rust Source: https://context7.com/boa-dev/boa/llms.txt Demonstrates creating resolved, rejected, and pending promises, as well as chaining `.then()` and using `Promise.all`. Ensure `ctx.run_jobs()?` is called after promise operations that might schedule microtasks. ```rust use boa_engine::{ Context, JsError, JsNativeError, JsValue, NativeFunction, builtins::promise::PromiseState, js_string, object::builtins::JsPromise, }; fn main() -> Result<(), Box> { let ctx = &mut Context::default(); // 1. Resolved promise let p1 = JsPromise::resolve(js_string!("done"), ctx)?; ctx.run_jobs()?; assert!(matches!(p1.state(), PromiseState::Fulfilled(_))); // 2. Rejected promise let p2 = JsPromise::reject(JsNativeError::error().with_message("oops"), ctx)?; ctx.run_jobs()?; assert!(matches!(p2.state(), PromiseState::Rejected(_))); // 3. Manual resolve/reject via resolvers let (promise, resolvers) = JsPromise::new_pending(ctx); resolvers.resolve.call(&JsValue::undefined(), &[JsValue::from(42)], ctx)?; ctx.run_jobs()?; if let PromiseState::Fulfilled(v) = promise.state() { println!("Resolved: {}", v.display()); // 42 } // 4. Promise.all let all = JsPromise::all( [JsPromise::resolve(1, ctx)?, JsPromise::resolve(2, ctx)?, JsPromise::resolve(3, ctx)?], ctx, )?; ctx.run_jobs()?; if let PromiseState::Fulfilled(v) = all.state() { println!("All: {}", v.display()); // [ 1, 2, 3 ] } // 5. Chaining let chained = JsPromise::resolve(10, ctx)? .then( Some(NativeFunction::from_fn_ptr(|_, args, ctx| { let n = args.get_or_undefined(0).to_number(ctx)?; Ok(JsValue::from(n * 2.0)) }).to_js_function(ctx.realm())), None, ctx, )?; ctx.run_jobs()?; if let PromiseState::Fulfilled(v) = chained.state() { println!("Chained: {}", v.display()); // 20 } Ok(()) } ``` -------------------------------- ### Get String Encoding with $boa.string.encoding Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Identify the internal encoding of a string. This is important for handling international characters correctly. ```javascript $boa.string.encoding("Greeting") // "latin1" $boa.string.encoding("挨拶") // "utf16" ``` -------------------------------- ### Simple JavaScript for VM Tracing Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md This is a basic JavaScript snippet used to generate trace output. It initializes two variables, 'a' and 'b'. ```javascript let a = 1; let b = 2; ``` -------------------------------- ### Build Workspace Member Documentation Only Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Generates documentation only for the workspace members, excluding dependencies. Use the `--no-deps` flag to achieve this. ```shell cargo doc --all-features --document-private-items --workspace --no-deps ``` -------------------------------- ### Build and Pack WebAssembly Module Source: https://context7.com/boa-dev/boa/llms.txt Command to build a Rust project into a WebAssembly module and prepare it for web usage. ```bash # Build and pack wasm-pack build --target web ``` -------------------------------- ### Get String Storage Type with $boa.string.storage Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Determine if a string is stored statically or on the heap. Useful for understanding string memory management. ```javascript $boa.string.storage("push") // "static" $boa.string.storage("specialFunction") // "heap" ``` -------------------------------- ### ES Module System with Module and SimpleModuleLoader Source: https://context7.com/boa-dev/boa/llms.txt Illustrates how to implement and use the ES module system in Boa. It covers parsing module source, loading modules from the filesystem using `SimpleModuleLoader`, and executing the full module lifecycle (load, link, evaluate). ```APIDOC ## `Module` and `SimpleModuleLoader` — ES module system Boa implements the full ES module lifecycle: parse → load → link → evaluate. `SimpleModuleLoader` resolves modules from the filesystem. `Module::load_link_evaluate` is a convenience method that runs the full lifecycle. Synthetic modules let Rust expose JS-importable modules. ```rust use std::{path::Path, rc::Rc, error::Error}; use boa_engine::{ Context, JsError, JsValue, Module, builtins::promise::PromiseState, js_string, module::SimpleModuleLoader, }; use boa_parser::Source; fn main() -> Result<(), Box> { const SRC: &str = r#" export function add(a, b) { return a + b; } export const PI = 3.14159; "#; let loader = Rc::new(SimpleModuleLoader::new("./scripts/modules")?); let ctx = &mut Context::builder().module_loader(loader.clone()).build()?; // Parse the module source let module = Module::parse( Source::from_reader(SRC.as_bytes(), Some(Path::new("./main.mjs"))), None, ctx, )?; // Insert into loader so it can be imported by other modules loader.insert( Path::new("./scripts/modules").canonicalize()?.join("main.mjs"), module.clone(), ); // Full lifecycle in one call let promise = module.load_link_evaluate(ctx); ctx.run_jobs()?; match promise.state() { PromiseState::Fulfilled(_) => {} PromiseState::Rejected(err) => { return Err(JsError::from_opaque(err).try_native(ctx)?.into()); } PromiseState::Pending => return Err("module pending".into()), } // Access exported bindings let ns = module.namespace(ctx); let pi = ns.get(js_string!("PI"), ctx)?; println!("PI = {}", pi.display()); // PI = 3.14159 let add = ns.get(js_string!("add"), ctx)?; let result = add.as_callable().unwrap() .call(&JsValue::undefined(), &[JsValue::from(2), JsValue::from(3)], ctx)?; println!("add(2, 3) = {}", result.display()); // add(2, 3) = 5 Ok(()) } ``` ``` -------------------------------- ### Get Object Memory Address Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Retrieve the memory address of a given object as a hexadecimal string. This is useful for debugging and understanding object identity. ```JavaScript let o = { x: 10, y: 20 } $boa.object.id(o) // '0x7F5B3251B718' ``` ```JavaScript // Getting the address of the $boa object in memory $boa.object.id($boa) // '0x7F5B3251B5D8' ``` -------------------------------- ### Run ECMAScript Test Suite (Output Results) Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Execute the ECMAScript test suite and save the results to a specified directory for later comparison. ```shell cargo run --release --bin boa_tester -- run -o ./test-results ``` -------------------------------- ### Get Function Bytecode with $boa.function.bytecode Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Retrieves the compiled bytecode of a given function as a formatted string. Useful for understanding function compilation and execution. ```JavaScript >> function add(x, y) { return x + y } >> $boa.function.bytecode(add) "\n------------------------Compiled Output: 'add'------------------------\nLocation Count Handler Opcode Operands\n\n000000 0000 none CreateMappedArgumentsObject\n000001 0001 none PutLexicalValue 2: 0\n000004 0002 none GetArgument 0\n000006 0003 none PutLexicalValue 2: 1\n000009 0004 none GetArgument 1\n000011 0005 none PutLexicalValue 2: 2\n000014 0006 none PushDeclarativeEnvironment 2\n000016 0007 none GetName 0000: 'x'\n000018 0008 none GetName 0001: 'y'\n000020 0009 none Add\n000021 0010 none SetAccumulatorFromStack\n000022 0011 none CheckReturn\n000023 0012 none Return\n000024 0013 none CheckReturn\n000025 0014 none Return\n\nConstants:\n 0000: [ENVIRONMENT] index: 1, bindings: 1\n 0001: [ENVIRONMENT] index: 2, bindings: 3\n 0002: [ENVIRONMENT] index: 3, bindings: 0\n\nBindings:\n 0000: x\n 0001: y\n\nHandlers: \n" ``` -------------------------------- ### Boa CLI Options Source: https://github.com/boa-dev/boa/blob/main/cli/README.md Displays the available command-line options for the Boa CLI, including arguments for file input, execution modes, and output formatting. ```txt Usage: boa [OPTIONS] [FILE]... Arguments: [FILE]... The JavaScript file(s) to be evaluated Options: --strict Run in strict mode -a, --dump-ast [] Dump the AST to stdout with the given format [possible values: debug, json, json-pretty] -t, --trace Dump the AST to stdout with the given format --vi Use vi mode in the REPL -O, --optimize Enable bytecode compiler optimizations --optimizer-statistics Print optimizer statistics (requires -O) --flowgraph [] Generate instruction flowgraph. Default is Graphviz [possible values: graphviz, mermaid] --flowgraph-direction Specifies the direction of the flowgraph. Default is top-top-bottom [possible values: top-to-bottom, bottom-to-top, left-to-right, right-to-left] --debug-object Inject debugging object `$boa` --test262-object Inject the test262 host object `$262` -m, --module Treats the input files as modules -r, --root Root path from where the module resolver will try to load the modules [default: .] -e, --expression Execute a JavaScript expression then exit -q, --quiet Suppress the welcome banner when starting the REPL -h, --help Print help (see more with '--help') -V, --version Print version ``` -------------------------------- ### $boa.limits.backtrace Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Accessor property to get and set the backtrace limit for thrown errors. When set, it limits the number of frames displayed in the error's backtrace. ```APIDOC ## Getter & Setter $boa.limits.backtrace ### Description This is an accessor property on the module, its getter returns the backtrace limit for a thrown error. Its setter can be used to set the backtrace limit. ### Method Getter/Setter ### Endpoint $boa.limits.backtrace ### Parameters None ### Request Example ```javascript $boa.limits.backtrace = 100; ``` ### Response #### Success Response (Getter) - **backtraceLimit** (number) - The current backtrace limit. #### Success Response (Setter) None (operation is performed) ### Response Example (Getter) ```javascript console.log($boa.limits.backtrace); ``` ### Error Handling None explicitly documented. ``` -------------------------------- ### Get Object Shape Type Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Determine the type of an object's shape, which can be 'shared' or 'unique'. This provides insight into how the object's structure is managed. ```JavaScript $boa.shape.type({x: 3}) // 'shared' ``` ```JavaScript $boa.shape.type(Number) // 'unique' ``` -------------------------------- ### $boa.function.trace(func, this, ...args) Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Traces the execution of a specified function, including its immediate instructions. ```APIDOC ## $boa.function.trace(func, this, ...args) ### Description This function traces the execution of the specified function. It only traces the immediate instructions of the target function and does not trace any functions called by it. The `this` value and arguments can be customized. ### Method $boa.function.trace(func, this, ...args) ### Parameters * **func** (Function) - The function to trace. * **this** (any) - The `this` value to use when calling the function. * **...args** (any) - The arguments to pass to the function. ### Request Example ```javascript const add = (a, b) => a + b; $boa.function.trace(add, undefined, 1, 2); ``` ### Response * **string** - A trace log of the function's execution, showing timing and operations. ``` -------------------------------- ### Get Object Shape ID Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Obtain the memory address of an object's shape as a hexadecimal string. This helps in identifying and comparing object shapes. ```JavaScript $boa.shape.id(Number) // '0x7FC35A073868' ``` ```JavaScript $boa.shape.id({}) // '0x7FC35A046258' ``` -------------------------------- ### Generate Function Flowgraph Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Get the instruction flowgraph of a function without quitting the Boa shell. Specify the desired format (e.g., 'graphviz', 'mermaid') or provide options for format and direction. ```JavaScript $boa.function.flowgraph(func, 'graphviz') ``` ```JavaScript $boa.function.flowgraph(func, { format: 'mermaid', direction: 'TopBottom' }) ``` -------------------------------- ### Run Boa Compiler Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Execute the Boa compiler from the command line. Pass JavaScript files as arguments to compile them. ```shell cargo run -- file1.js file2.js ``` -------------------------------- ### Implement Custom JobExecutor for Async Operations Source: https://context7.com/boa-dev/boa/llms.txt Implement the `JobExecutor` trait to manage promises and async jobs. This example shows a `SimpleQueue` that processes jobs from a FIFO queue, suitable for custom async runtimes. ```rust use std::{cell::RefCell, collections::VecDeque, rc::Rc}; use boa_engine::{ Context, JsResult, context::ContextBuilder, job::{Job, JobExecutor, NativeAsyncJob, PromiseJob}, js_string, native_function::NativeFunction, property::Attribute, }; use futures_lite::future; struct SimpleQueue { promises: RefCell>, async_jobs: RefCell>, } impl SimpleQueue { fn new() -> Rc { Rc::new(Self { promises: RefCell::default(), async_jobs: RefCell::default(), }) } } impl JobExecutor for SimpleQueue { fn enqueue_job(self: Rc, job: Job, _ctx: &mut Context) { match job { Job::PromiseJob(p) => self.promises.borrow_mut().push_back(p), Job::AsyncJob(a) => self.async_jobs.borrow_mut().push_back(a), _ => {} } } fn run_jobs(self: Rc, ctx: &mut Context) -> JsResult<()> { loop { let async_job = self.async_jobs.borrow_mut().pop_front(); if let Some(job) = async_job { future::block_on(job.call(&RefCell::new(ctx)))?; } let promise_job = self.promises.borrow_mut().pop_front(); match promise_job { Some(job) => { job.call(ctx)?; } None if self.async_jobs.borrow().is_empty() => break, None => {} } } Ok(()) } } fn main() -> JsResult<()> { let queue = SimpleQueue::new(); let ctx = &mut ContextBuilder::new() .job_executor(queue) .build() .unwrap(); // setTimeout-style async function ctx.register_global_callable( js_string!("delay"), 1, NativeFunction::from_async_fn(|_, args, ctx| { let ms = args.get_or_undefined(0).to_u32(&mut ctx.borrow_mut()).unwrap_or(0); async move { // In a real runtime, sleep here Ok(boa_engine::JsValue::from(ms)) } }), ).unwrap(); ctx.eval(boa_parser::Source::from_bytes( "delay(100).then(ms => { /* handle result */ })" ))?; ctx.run_jobs()?; Ok(()) } ``` -------------------------------- ### Run Boa Benchmarks Source: https://github.com/boa-dev/boa/blob/main/README.md Command to execute the Boa JavaScript engine's benchmarks locally. Ensure Boa is built in release mode before running. ```bash cargo run --release -p boa_cli -- bench-v8/combined.js ``` -------------------------------- ### Run ECMAScript Test Suite (Verbose) Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Execute the official ECMAScript test suite with verbose output. Panics are logged to error.log. ```shell cargo run --release --bin boa_tester -- run -v 2> error.log ``` -------------------------------- ### Boa CLI Usage Source: https://github.com/boa-dev/boa/blob/main/README.md Displays the available command-line options for the Boa JavaScript engine. Use this to understand how to execute JavaScript files and configure engine behavior. ```txt Usage: boa [OPTIONS] [FILE]... Arguments: [FILE]... The JavaScript file(s) to be evaluated Options: --strict Run in strict mode -a, --dump-ast [] Dump the AST to stdout with the given format [possible values: debug, json, json-pretty] -t, --trace Dump the AST to stdout with the given format --vi Use vi mode in the REPL -O, --optimize --optimizer-statistics --flowgraph [] Generate instruction flowgraph. Default is Graphviz [possible values: graphviz, mermaid] --flowgraph-direction Specifies the direction of the flowgraph. Default is top-top-bottom [possible values: top-to-bottom, bottom-to-top, left-to-right, right-to-left] --debug-object Inject debugging object `$boa` --test262-object Inject the test262 host object `$262` -m, --module Treats the input files as modules -r, --root Root path from where the module resolver will try to load the modules [default: .] -h, --help Print help (see more with '--help') -V, --version Print version ``` -------------------------------- ### Run Boa with a JavaScript file Source: https://github.com/boa-dev/boa/blob/main/README.md Clone the Boa repository and execute a JavaScript file using `cargo run -- test.js` in the project root. ```bash cargo run -- test.js ``` -------------------------------- ### LLDB Manual debugging Source: https://github.com/boa-dev/boa/blob/main/docs/debugging.md Use `rust-lldb` for manual debugging. You can run your Boa executable with arguments within this environment to set breakpoints and inspect state. ```bash rust-lldb ./target/debug/boa [arguments] ``` -------------------------------- ### Register Boa Runtime Extensions (Console, Fetch) Source: https://context7.com/boa-dev/boa/llms.txt Use `boa_runtime::register` to conveniently enable multiple extensions like `Console` and `FetchExtension`. The `FetchExtension` requires the `reqwest-blocking` feature flag. ```rust use boa_engine::{Context, Source}; fn main() { let mut ctx = Context::default(); // Register all available extensions boa_runtime::register( ( boa_runtime::extensions::ConsoleExtension::default(), // Enable with feature flag "reqwest-blocking": // boa_runtime::extensions::FetchExtension( // boa_runtime::fetch::BlockingReqwestFetcher::default() // ), ), None, // use default realm &mut ctx, ); ctx.eval(Source::from_bytes(r#" console.log("Extensions registered!"); // With fetch extension enabled: // fetch("https://api.example.com/data") // .then(r => r.json()) // .then(data => console.log(data)); "#)).unwrap(); ctx.run_jobs().unwrap(); } ``` -------------------------------- ### Generate VM instruction flowgraph Source: https://github.com/boa-dev/boa/blob/main/docs/debugging.md Pipe the output of `--flowgraph` to the `dot` command to generate a visual representation of the VM instruction flowgraph. This helps in understanding execution paths. ```bash cargo run -- test.js --flowgraph | dot -Tpng > test.png ``` -------------------------------- ### Create a default execution context Source: https://context7.com/boa-dev/boa/llms.txt Use `Context::default()` for a basic context with a default job executor and module loader. This is suitable for simple synchronous evaluations. ```rust use boa_engine::{Context, Source, JsResult}; fn main() -> JsResult<()> { // Default context (synchronous, no module loader) let mut context = Context::default(); let result = context.eval(Source::from_bytes("1 + 2"))?; println!("{}", result.display()); // 3 Ok(()) } ``` -------------------------------- ### Boa REPL Commands Source: https://github.com/boa-dev/boa/blob/main/cli/README.md Lists the available dot-commands for the Boa interactive REPL, such as help, exit, clear, and load. ```markdown | Command | Description | | -------------- | ----------------------------------- | | .help | Show available REPL commands | | .exit | Exit the REPL | | .clear | Clear the terminal screen | | .load | Load and evaluate a JavaScript file | ``` -------------------------------- ### Boa Parser Source Input Abstraction Source: https://context7.com/boa-dev/boa/llms.txt Demonstrates creating `Source` objects from byte slices, file paths, and readers. The `Source` type abstracts over different input methods for parsing. ```rust use boa_parser::Source; use std::path::Path; fn main() { // From a &str / &[u8] let s1 = Source::from_bytes("1 + 1"); // From a file path (reads lazily) // let s2 = Source::from_filepath(Path::new("./app.js")).unwrap(); // From any Read with a name hint let code = b"console.log('hello')"; let s3 = Source::from_reader(code.as_slice(), Some(Path::new("./inline.js"))); } ``` -------------------------------- ### VM Stack Organization Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md Illustrates the layout of the VM's value stack during a function call, showing the 'this' value, function object, arguments, and registers relative to the frame pointer (fp) and register pointer (rp). ```text Setup by the caller ┌─────────────────────────────────────────────────────────┐ ┌───── register pointer (rp) ▼ ▼ ▼ | -(2+N): this | -(1+N): func | -N: arg1 | ... | -1: argN | 0: reg1 | ... | K: regK | ▲ ▲ ▲ ▲ ▲ ▲ └──────────────────────────────┘ └──────────────────────┘ └────────────────────┘ function prologue arguments Setup by the callee ▲ └─ Frame pointer (fp) ``` -------------------------------- ### Create Object with Property 'x' Source: https://github.com/boa-dev/boa/blob/main/docs/shapes.md Initializes an object with a single property 'x'. This action can lead to the creation or transition to a specific shape (e.g., S2). ```javascript let o2 = { x: 200 }; ``` -------------------------------- ### Registering Native Functions Source: https://context7.com/boa-dev/boa/llms.txt Demonstrates how to register various types of Rust functions and closures as global JavaScript functions within a Boa Engine context. This includes plain function pointers, Copy closures, Clone closures with GcRefCell for mutable state, and asynchronous functions. ```APIDOC ## Registering Native Functions This section details how to expose Rust functions and closures to JavaScript using `boa_engine::native_function::NativeFunction`. ### 1. From a function pointer Register a plain Rust function pointer as a global JavaScript function. ```rust use boa_engine::{Context, JsValue, Source, js_string}; use boa_engine::native_function::NativeFunction; let mut context = Context::default(); context.register_global_callable( js_string("double"), 1, NativeFunction::from_fn_ptr(|_, args, ctx| { let n = args.get_or_undefined(0).to_number(ctx)?; Ok(JsValue::from(n * 2.0)) }), ).unwrap(); // Usage in JavaScript: // double(21) would return 42.0 ``` ### 2. Copy closure Register a closure that captures `Copy` types by value. ```rust use boa_engine::{Context, JsValue, Source, js_string}; use boa_engine::native_function::NativeFunction; let multiplier = 10_i32; context.register_global_callable( js_string("multiply"), 1, NativeFunction::from_copy_closure(move |_, args, ctx| { let n = args.get_or_undefined(0).to_i32(ctx)?; Ok(JsValue::from(n * multiplier)) }), ).unwrap(); // Usage in JavaScript: // multiply(5) would return 50 ``` ### 3. Clone closure with `GcRefCell` Register a closure that captures mutable state using `GcRefCell`. ```rust use boa_engine::{Context, JsValue, Source, js_string}; use boa_engine::native_function::NativeFunction; use boa_gc::{Finalize, GcRefCell, Trace}; #[derive(Trace, Finalize)] struct Counter { value: i32 } let state = GcRefCell::new(Counter { value: 0 }); context.register_global_callable( js_string("increment"), 0, NativeFunction::from_copy_closure_with_captures( |_, _, cap, _| { cap.borrow_mut().value += 1; Ok(JsValue::from(cap.borrow().value)) }, state, ), ).unwrap(); // Usage in JavaScript: // increment() would return 1, then 2 on subsequent calls ``` ### 4. Async function Register an asynchronous Rust function. ```rust use boa_engine::{Context, JsValue, Source, js_string}; use boa_engine::native_function::NativeFunction; context.register_global_callable( js_string("asyncAdd"), 2, NativeFunction::from_async_fn(|_, args, ctx| { let a = args.get_or_undefined(0).to_number(&mut ctx.borrow_mut()).unwrap_or(0.0); let b = args.get_or_undefined(1).to_number(&mut ctx.borrow_mut()).unwrap_or(0.0); async move { Ok(JsValue::from(a + b)) } }), ).unwrap(); // Usage in JavaScript: // await asyncAdd(5, 10) would return 15 ``` ``` -------------------------------- ### Boa WebAssembly Compilation Configuration Source: https://context7.com/boa-dev/boa/llms.txt Shows the `Cargo.toml` configuration required to compile Boa to WebAssembly, including enabling the `js` feature and setting the `getrandom` backend. ```toml # Cargo.toml [dependencies] boa_engine = { version = "0.21.0", features = ["js"] } [target.wasm32-unknown-unknown] rustflags = '--cfg getrandom_backend="wasm_js"' ``` -------------------------------- ### Manage ES Modules with SimpleModuleLoader in Rust Source: https://context7.com/boa-dev/boa/llms.txt Shows how to parse, load, link, and evaluate ES modules using Boa's `Module` and `SimpleModuleLoader`. It covers setting up a custom module loader and accessing exported bindings. ```rust use std::{path::Path, rc::Rc, error::Error}; use boa_engine::{ Context, JsError, JsValue, Module, builtins::promise::PromiseState, js_string, module::SimpleModuleLoader, }; use boa_parser::Source; fn main() -> Result<(), Box> { const SRC: &str = r#" export function add(a, b) { return a + b; } export const PI = 3.14159; "#; let loader = Rc::new(SimpleModuleLoader::new("./scripts/modules")?); let ctx = &mut Context::builder().module_loader(loader.clone()).build()?; // Parse the module source let module = Module::parse( Source::from_reader(SRC.as_bytes(), Some(Path::new("./main.mjs"))), None, ctx, )?; // Insert into loader so it can be imported by other modules loader.insert( Path::new("./scripts/modules").canonicalize()?.join("main.mjs"), module.clone(), ); // Full lifecycle in one call let promise = module.load_link_evaluate(ctx); ctx.run_jobs()?; match promise.state() { PromiseState::Fulfilled(_) => {} PromiseState::Rejected(err) => { return Err(JsError::from_opaque(err).try_native(ctx)?.into()); } PromiseState::Pending => return Err("module pending".into()), } // Access exported bindings let ns = module.namespace(ctx); let pi = ns.get(js_string!("PI"), ctx)?; println!("PI = {}", pi.display()); // PI = 3.14159 let add = ns.get(js_string!("add"), ctx)?; let result = add.as_callable().unwrap() .call(&JsValue::undefined(), &[JsValue::from(2), JsValue::from(3)], ctx)?; println!("add(2, 3) = {}", result.display()); // add(2, 3) = 5 Ok(()) } ``` -------------------------------- ### Implementing JavaScript Classes Source: https://context7.com/boa-dev/boa/llms.txt Explains how to expose Rust structs as JavaScript classes using the `Class` trait. This allows creating instances in JavaScript using `new ClassName()`, defining constructor logic, and adding prototype methods, static methods, and properties. ```APIDOC ## Exposing Rust Structs as JavaScript Classes This section covers how to implement the `Class` trait to register Rust structs as JavaScript constructors. ### `Class` Trait Implementation Implement the `Class` trait for a `#[derive(Trace, Finalize, JsData)]` struct. ```rust use boa_engine::{ Context, JsArgs, JsData, JsResult, JsString, JsValue, Source, class::{Class, ClassBuilder}, error::JsNativeError, js_string, native_function::NativeFunction, property::Attribute, }; use boa_gc::{Finalize, Trace}; #[derive(Debug, Trace, Finalize, JsData)] struct Vec2 { x: f64, y: f64 } impl Class for Vec2 { const NAME: &'static str = "Vec2"; const LENGTH: usize = 2; // Constructor logic when `new Vec2(...)` is called fn data_constructor(_this: &JsValue, args: &[JsValue], ctx: &mut Context) -> JsResult { Ok(Vec2 { x: args.get_or_undefined(0).to_number(ctx)?, y: args.get_or_undefined(1).to_number(ctx)?, }) } // Initialize prototype methods, static methods, and properties fn init(class: &mut ClassBuilder<'_>) -> JsResult<()> { // Instance method class.method( js_string("length"), 0, NativeFunction::from_fn_ptr(|this, _, _| { if let Some(obj) = this.as_object() && let Some(v) = obj.downcast_ref::() { return Ok(JsValue::from((v.x * v.x + v.y * v.y).sqrt())); } Err(JsNativeError::typ().with_message("invalid this").into()) }), ); // Static method class.static_method( js_string("zero"), 0, NativeFunction::from_fn_ptr(|_, _, ctx| { // Simplified: just return undefined as demonstration Ok(JsValue::undefined()) }), ); // Inherited property class.property(js_string("dimensions"), 2, Attribute::default()); Ok(()) } } fn main() { let mut ctx = Context::default(); ctx.register_global_class::().unwrap(); // Usage in JavaScript: // let v = new Vec2(3, 4); // console.log(v.length()); // Output: 5 // console.log(Vec2.prototype.dimensions); // Output: 2 } ``` ``` -------------------------------- ### $boa.string.summary Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Provides a summary object containing the storage type and encoding of a string. ```APIDOC ## Function $boa.string.summary(str) ### Description Returns an object with a short summary of the given string, including its storage type and encoding. ### Method Function Call ### Endpoint $boa.string.summary ### Parameters - **str** (string) - Required - The string to summarize. ### Request Example ```JavaScript $boa.string.summary("Greeting") ``` ### Response #### Success Response - **summary** (object) - An object containing `storage` and `encoding` properties. - **storage** (string) - The storage type (`"static"` or `"heap"`). - **encoding** (string) - The encoding type (e.g., `"latin1"`, `"utf16"`). ### Response Example ```JavaScript $boa.string.summary("Greeting") // { storage: "heap", encoding: "latin1" } ``` ### Error Handling None explicitly documented. ``` -------------------------------- ### Add boa_engine to Cargo.toml Source: https://github.com/boa-dev/boa/blob/main/README.md To use Boa, add the `boa_engine` crate to your project's `Cargo.toml` file. ```toml [dependencies] boa_engine = "0.21.0" ``` -------------------------------- ### Rust VM Execution Loop Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md The core fetch-decode-execute loop of the Boa VM. Use this to understand the fundamental execution flow of bytecode instructions. ```rust fn run(&mut self) -> CompletionRecord { while let Some(byte) = bytecode.get(frame.pc) { let opcode = Opcode::decode(*byte); match self.execute_one(Self::execute_bytecode_instruction, opcode) { ControlFlow::Continue(()) => {} // Continue execution ControlFlow::Break(value) => return value, // Stop execution and return value } } // If loop finishes without break, it means execution completed normally // This part might need adjustment based on actual CompletionRecord definition unimplemented!("CompletionRecord for normal completion"); } ``` -------------------------------- ### $boa.gc.collect() Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Force triggers the garbage collector to scan the heap and collect garbage. ```APIDOC ## $boa.gc.collect() ### Description This function forces the garbage collector to scan the heap and collect any unreferenced objects. ### Method $boa.gc.collect() ### Parameters None ### Request Example ```javascript $boa.gc.collect() ``` ### Response None (modifies heap state) ``` -------------------------------- ### Dump AST in interactive mode Source: https://github.com/boa-dev/boa/blob/main/docs/debugging.md When running Boa interactively (REPL), use the `--dump-ast` flag to print the AST. The default format is Debug. ```bash cargo run -- --dump-ast # AST dump format is Debug by default. ``` -------------------------------- ### Runtime Limits Source: https://context7.com/boa-dev/boa/llms.txt Configure runtime limits for loop iterations and call stack depth using `Context::runtime_limits_mut()` to prevent infinite loops and deep recursion. Exceeding these limits results in a non-catchable engine error. ```APIDOC ## Runtime limits — Protect against infinite loops and deep recursion `Context::runtime_limits_mut()` exposes configurable limits on loop iterations and call stack depth. Exceeding a limit throws a non-catchable engine error that propagates through `JsResult`. ```rust use boa_engine::{Context, Source}; fn main() { let mut ctx = Context::default(); // Cap loops at 100 iterations ctx.runtime_limits_mut().set_loop_iteration_limit(100); // This succeeds (50 < 100) assert!(ctx.eval(Source::from_bytes("for (let i=0;i<50;i++) {}")).is_ok()); // This fails – cannot be caught from JS assert!(ctx.eval(Source::from_bytes("while (true) {}")).is_err()); // Cap recursion depth ctx.runtime_limits_mut().set_recursion_limit(20); ctx.eval(Source::from_bytes( "function fact(n) { return n <= 1 ? 1 : n * fact(n-1); }" )).unwrap(); assert!(ctx.eval(Source::from_bytes("fact(10)")).is_ok()); // depth 10 < 20 assert!(ctx.eval(Source::from_bytes("fact(50)")).is_err()); // depth 50 > 20 } ``` ``` -------------------------------- ### Stack Layout During Function Call Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md Visualizes the VM stack during a call to function 'x' from function 'y', detailing the positions of 'this', function objects, arguments, and registers for both caller and callee. ```text caller prologue caller arguments callee prologue callee arguments ┌─────────────────┐ ┌─────────┐ ┌─────────────────┐ ┌──────┐ ▼ ▼ ▼ ▼ │ ▼ ▼ ▼ | 0: undefined | 1: y | 2: 1 | 3: 2 | 4: undefined | 5: x | 6: 3 | ▲ ▲ ▲ │ caller register pointer ────┤ │ │ │ callee register pointer │ callee frame pointer │ └───── caller frame pointer ``` -------------------------------- ### SequenceString Structure Source: https://github.com/boa-dev/boa/blob/main/docs/string.md Illustrates the memory layout for heap-allocated strings (Latin-1 and UTF-16), including the vtable, reference count, and data slice. ```rust pub(crate) struct SequenceString { vtable: JsStringVTable, refcount: Cell, _marker: PhantomData T>, pub(crate) data: [u8; 0], } ``` -------------------------------- ### $boa.function.bytecode(func) Source: https://github.com/boa-dev/boa/blob/main/docs/boa_object.md Returns the compiled bytecode of a given function as a formatted string. ```APIDOC ## $boa.function.bytecode(func) ### Description This function returns the compiled bytecode of a function as a string, detailing opcodes, operands, and constants. ### Method $boa.function.bytecode(func) ### Parameters * **func** (Function) - The function for which to retrieve the bytecode. ### Request Example ```javascript function add(x, y) { return x + y; } $boa.function.bytecode(add); ``` ### Response * **string** - A formatted string representing the function's compiled bytecode. ``` -------------------------------- ### Bytecode Instruction Format Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md Describes the format of bytecode instructions, consisting of a one-byte opcode followed by variable-length operands. ```text ┌────────┬──────────┬──────────┬───┐ │ opcode │ operand1 │ operand2 │...│ │ (1 B) │ (varies) │ (varies) │ │ └────────┴──────────┴──────────┴───┘ ``` -------------------------------- ### Configure Rustflags for Web Assembly Source: https://github.com/boa-dev/boa/blob/main/README.md For the `wasm32-unknown-unknown` target, enable the `js` feature flag and set `RUSTFLAGS` in `.cargo/config.toml` for `getrandom` WebAssembly support. ```toml [target.wasm32-unknown-unknown] rustflags = '--cfg getrandom_backend="wasm_js"' ``` -------------------------------- ### Run Boa Test Suite Source: https://github.com/boa-dev/boa/blob/main/CONTRIBUTING.md Execute the Boa test suite using Cargo. This command runs all internal tests. ```shell cargo test ``` -------------------------------- ### VM Compiled Output and Execution Trace Source: https://github.com/boa-dev/boa/blob/main/docs/vm.md Displays the compiled bytecode and the runtime execution trace of a simple JavaScript snippet. It includes details on opcodes, operands, and stack operations. ```text ----------------------Compiled Output: '
'----------------------- Location Count Handler Opcode Operands 000000 0000 none PushOne 000001 0001 none PutLexicalValue 0000: 'a' 000006 0002 none PushInt8 2 000008 0003 none PutLexicalValue 0001: 'b' 000013 0004 none Return Literals: Bindings: 0000: a 0001: b Functions: Handlers: ----------------------------------------- Call Frame ----------------------------------------- Time Opcode Operands Top Of Stack 6μs PushOne 1 7μs PutLexicalValue 0000: 'a' 0μs PushInt8 2 2 1μs PutLexicalValue 0001: 'b' 0μs Return Stack: undefined ```