- ES2023 compliant — implements the ECMAScript 2023 specification
- Async/await built-in — first-class async/await support without transpilation
- Bytecode support — compile JavaScript to
.jscbytecode files for fast loading and execution, with configurable optimization levels (-O0through-O3) - Fast — outperforms QuickJS in benchmarks
- Small — ~5.2 MB binary (with
replfeature) - Zero-dependency built-in implementations for:
- Regex/JSON/Base64/BigInt
- Unicode
fetch(HTTP client),rusttlsrequired- WebSocket
- Server-Sent Events (SSE)
No external C libraries or system dependencies for the above — everything is implemented from scratch in Rust.
V8 benchmark suite comparison (higher is better):
| Benchmark | qjs | node | boa | pipa | vs qjs |
|---|---|---|---|---|---|
| Richards | 963 | 45162 | 142 | 950 | -1.3% |
| DeltaBlue | 941 | 98351 | 142 | 976 | +3.7% |
| Crypto | 1070 | 59358 | 126 | 1100 | +2.8% |
| RayTrace | 1462 | 80659 | 312 | 956 | -34.6% |
| EarleyBoyer | 2083 | 92667 | 372 | 1848 | -11.3% |
| RegExp | 329 | 13157 | 62.6 | 1018 | +209.4% |
| Splay | 2410 | 50606 | 527 | 2038 | -15.4% |
| NavierStokes | 1809 | 56244 | 295 | 2115 | +16.9% |
| SCORE (total) | 1198 | 54138 | 203 | 1295 | +8.1% |
Ranking: #1 node (54138) · #2 pipa (1295) · #3 qjs (1198) · #4 boa (203)
Tested against tc39/test262 (excluding intl402).
| Category | Tests | Pass Rate | Notes |
|---|---|---|---|
| Core Builtins | |||
| Math | 324 | 99.7% (323/324) | |
| Boolean | 50 | 100% (50/50) | |
| parseFloat | 54 | 98.1% (53/54) | |
| parseInt | 55 | 96.4% (53/55) | |
| Number | 339 | 98.8% (335/339) | |
| Object.is | 21 | 100% (21/21) | |
| Object.defineProperty | 1131 | 98.9% (1118/1131) | |
| Object.create | 320 | 99.4% (318/320) | |
| Object.getPrototypeOf | 39 | 100% (39/39) | |
| Date | 594 | 89.2% (530/594) | |
| global | 29 | 100% (29/29) | |
| Infinity | 6 | 100% (6/6) | |
| eval | 10 | 90.0% (9/10) | |
| URI encode/decode | 173 | 45.1% (78/173) | |
| Function | 507 | 85.2% (432/507) | |
| Other Builtins | |||
| Symbol | 98 | 87.8% (86/98) | |
| JSON | 165 | 49.1% (81/165) | |
| Error | 180 | 52.8% (95/180) | |
| RegExp | 1878 | 42.3% (794/1878) | |
| String | 1222 | 77.2% (943/1222) | |
| Reflect | 153 | 21.6% (33/153) | |
| Map | 203 | 22.2% (45/203) | |
| Set | 382 | 18.8% (72/382) | |
| BigInt | 77 | 27.3% (21/77) | |
| Promise | 676 | 5.6% (38/676) | Limited async support |
| Proxy | 311 | 0% (0/311) | Not yet implemented |
cargo install pipa-js
# Run a script
pipa script.js
# Run precompiled bytecode
pipa script.jsc
# Compile JavaScript to bytecode
pipa -compile input.js output.jsc
# Disassemble bytecode (debugging)
pipa -diss script.jsc
# Specify optimization level (default: -O2)
pipa -O3 script.js
# Start REPL (requires the repl feature)
pipaUse pipa-js as a library to embed JavaScript in your Rust project:
[dependencies]
pipa-js = "0.1.2"use pipa::{JSRuntime, eval};
let mut rt = JSRuntime::new();
let mut ctx = rt.new_context();
let val = eval(&mut ctx, "1 + 2").unwrap();
assert_eq!(val.get_int(), 3);use pipa::{JSRuntime, eval};
let mut rt = JSRuntime::new();
let mut ctx = rt.new_context();
eval(&mut ctx, r#"
function greet(name) {
return "Hello, " + name + "!";
}
"#).unwrap();
let val = eval(&mut ctx, r#"greet("world")"#).unwrap();
assert!(val.is_string());
let s = ctx.get_atom_str(val.get_atom());
assert_eq!(s, "Hello, world!");use pipa::{JSRuntime, eval, JSValue};
fn js_print(ctx: &mut pipa::JSContext, args: &[JSValue]) -> JSValue {
for arg in args {
if arg.is_string() {
print!("{}", ctx.get_atom_str(arg.get_atom()));
} else if arg.is_int() {
print!("{}", arg.get_int());
}
}
println!();
JSValue::undefined()
}
let mut rt = JSRuntime::new();
let mut ctx = rt.new_context();
ctx.register_global_builtin("print", 1, js_print);
eval(&mut ctx, r#"print("hello from Rust!")"#).unwrap();use pipa::{JSRuntime, eval, eval_async};
let mut rt = JSRuntime::new();
let mut ctx = rt.new_context();
eval_async(&mut ctx, r#"
var result = null;
(async () => {
result = await fetch("https://httpbin.org/json");
})();
"#).unwrap();
let val = eval(&mut ctx, "JSON.stringify(result)").unwrap();
println!("{}", ctx.get_atom_str(val.get_atom()));Requires the
fetchfeature (enabled by default).eval_asynciseval+run_event_loopin one call.
use pipa::{JSRuntime, eval, compile_to_register_bytecode};
let mut rt = JSRuntime::new();
let mut ctx = rt.new_context();
// Compile JavaScript to register-based bytecode
let (code, constants) = compile_to_register_bytecode(
&mut ctx,
"function fib(n) { return n < 2 ? n : fib(n-1) + fib(n-2); } fib(20)",
).unwrap();
// code: Vec<u8>, constants: Vec<JSValue>
assert!(!code.is_empty());# Default build (includes REPL, fetch, and process support)
cargo build --release
# Minimal build (no REPL, no fetch, no process)
cargo build --release --no-default-featuresIf using pipa as a library dependency and you don't need REPL/fetch/process features, add it with
default-features = false:[dependencies] pipa-js = { version = "0.1.1", default-features = false }
MIT