A JavaScript engine written in Rust, with a full pipeline from source text to bytecode execution:
Source -> Lexer -> Parser -> Compiler -> VM
The repository contains:
- A library crate: javascript
- A CLI binary crate: js
- Rust integration tests and JavaScript self-tests
- A Node-based Test262 runner under ci/runner.js
This project is actively developed and already passes a large portion of Test262 in practice.
Important: two well-known missing areas are still:
- decorators
- proper tail calls (tail call optimization)
If you need either today, use transpilation (for decorators) or avoid relying on spec-level PTC behavior.
This engine is intentionally not a legacy-web-quirk-compatible sloppy-mode runtime.
- This engine does not explicitly target full, historical sloppy-mode compatibility.
- Legacy web quirks and edge-case loose-mode behaviors are not a primary compatibility goal.
- In practice, strict and modern ECMAScript behavior is prioritized over preserving legacy oddities.
- Bytecode VM architecture (not AST tree-walking execution)
- ECMAScript parser and compiler implemented in Rust
- Supports script and module execution
- Includes async-related features (Promises, async/await, top-level await in module mode)
- REPL with persistent command history
- Cross-platform CLI (Linux, macOS, Windows)
Core source layout:
- src/core/tokenizer.rs: lexer/tokenizer
- src/core/parser.rs: parser (AST construction)
- src/core/statement.rs: AST node definitions
- src/core/compiler.rs: AST to bytecode compilation
- src/core/opcode.rs: opcode definitions
- src/core/vm.rs and src/core/vm/: VM runtime and builtins
- src/core/value.rs: runtime value model
- src/core/mod.rs: top-level compile/run pipeline and public core entry points
- src/lib.rs: crate public API re-exports
- js/src/main.rs: CLI entry point and REPL loop
cargo build --all-features --release
cargo build -p js --release# Run a file
cargo run -r -p js -- path/to/script.js
# Run a module
cargo run -r -p js -- --module path/to/module.js
cargo run -r -p js -- path/to/module.mjs
# Evaluate inline code
cargo run -r -p js -- -e "1 + 2"
# Start REPL
cargo run -r -p jsUsage: js [OPTIONS] [FILE]
Options:
-e, --eval <EVAL>
--timer-wait-ms <TIMER_WAIT_MS>
--module
-h, --help
-V, --version
- Exit with .exit or Ctrl-D
- Multiline input is supported for incomplete code
- History is stored at ~/.js_repl_history (resolved via dirs::home_dir())
Add dependency:
[dependencies]
javascript = "0.1.14"Basic script evaluation:
use javascript::evaluate_script;
fn main() {
let out = evaluate_script("1 + 2", false, Option::<&std::path::Path>::None).unwrap();
assert_eq!(out, "3");
}Module evaluation:
use javascript::evaluate_script;
fn main() {
let src = "export const x = 1;\n x";
let out = evaluate_script(src, true, Option::<&std::path::Path>::None).unwrap();
println!("{out}");
}Persistent REPL API:
use javascript::Repl;
fn main() {
let mut repl = Repl::new();
repl.eval("let a = 10;").unwrap();
let out = repl.eval("a + 5").unwrap();
assert_eq!(out, "15");
}Other exported APIs include tokenize, parse_statement, parse_statements, read_script_file, and value/string helpers.
cargo test -r --all-features --testscargo clippy -r --all-features --all-targets -- -D warnings
cargo fmt --all# Uses bash + timeout logic and categorizes PASS/FAIL/SKIP/TIMEOUT
bash ./test-vm.shWindows note: run through bash (for example Git Bash), not directly as a PowerShell script.
Node-based runner:
# Requires Node.js
node ci/runner.js --limit 10000 --focus "language/expressions/addition"
# Run one focused case
node ci/runner.js --limit 1 --focus "language/literals/string/S7.8.4_A4.1_T1.js"Key runner options:
- --focus (required, supports multiple and comma-separated values)
- --limit
- --jobs
- --timeout
- --fail-on-failure
- --keep-tmp
The runner builds the engine, composes harness files, runs tests, and writes logs to test262-results.log.
As of current implementation:
- decorators: not implemented
- tail-call-optimization: not implemented
- full historical sloppy-mode quirks: intentionally not a compatibility target
These are common gaps across many real-world engines/runtimes as well, but they remain spec-visible differences.
- Run format, clippy, and tests before opening PRs.
- Keep parser/compiler/vm changes accompanied by tests (Rust and/or JS scripts).
- For conformance work, include focused Test262 repro paths in commit or PR notes.
MIT. See LICENSE.