Log inGet started
Package

zerojs.package

readme.md

ZeroJS is a JavaScript interpreter for the Zero engine, written in Luau. It parses and executes ES2017-practical JavaScript entirely inside the Luau VM — no native code, no WebAssembly, no external dependency — and marshals values back to Luau transparently.

Importing

local zerojs = require("zerojs.init")

Inside the package, modules reference each other with the ~. self-reference; from anywhere else in a world, the bare root-relative id above (or @root::zerojs.init) imports the API.

API surface

Module-level

SymbolTypeDescription
zerojs.eval(src)(string) -> anyParse and execute src in a fresh one-shot VM. Returns the marshaled JS completion value. Raises a Luau error on a JS exception.
zerojs.new(opts?)(table?) -> VMCreate a persistent VM. opts.env seeds additional JS globals from a Luau table.
zerojs.nullsentinelThe JS null value (distinct from Luau nil).
zerojs.undefinedsentinelThe JS undefined value, which marshals to Luau nil when returned.
zerojs.versionstringVersion string of this package.
zerojs.lastError(vm)(VM) -> table?Returns the structured payload { name, message, stack } from the most recent JS exception on vm. nil if no exception has occurred on that VM.

VM instance

MethodDescription
vm:run(src, opts?)Execute src in this VM's persistent realm. opts.sourceName names the source for error messages and stack frames. Returns the marshaled completion value.
vm:get(name)Read a global from the VM's realm.
vm:set(name, value)Write a marshaled Luau value as a JS global in the VM's realm.

Marshaling

Luau values passed to opts.env or vm:set are converted to JS values. JS values returned from run/eval are converted back to Luau: numbers, strings, and booleans are transparent; arrays become 1-based Luau tables; objects become string-keyed Luau tables; JS functions become callable Luau closures; undefined becomes nil; null becomes zerojs.null.

Step-budget sandbox

Each VM runs with a default execution budget of 1,000,000 interpreter steps. A script that exceeds the budget raises a JS RangeError: step budget exceeded, which surfaces as a Luau error. The budget resets on each run/eval call.

Language scope

Supported

  • Variable declarations: var (function-scoped hoisting), let and const with full TDZ enforcement
  • Functions: declarations, expressions, arrow functions, closures, rest parameters, default parameters
  • Classes: declarations and expressions, inheritance via extends, super() in constructors and methods, getter and setter accessors, instance fields, static fields and methods, computed method keys, named class expressions, TDZ before declaration
  • Destructuring: object and array patterns in declarations, assignment, and function parameters; nested patterns; rename, default, rest; computed keys in object patterns; elision in array patterns
  • Spread: array literals, call arguments, new arguments, object literals
  • Template literals (untagged)
  • Full coercion and equality semantics: ==/!= abstract equality, ===/!== strict equality, typeof, instanceof
  • try/catch/finally, throw
  • All loop forms: for, while, do-while, for-in, for-of
  • async/await — executes synchronously (no event loop; settled immediately)
  • Object.keys, Array.isArray, globalThis, NaN, Infinity, console.log
  • Error, TypeError, RangeError, ReferenceError, SyntaxError constructors and inheritance
  • Property enumerability: for-in yields only own enumerable keys; object rest excludes prototype methods

Not yet supported

  • Regular expression evaluation (regex literals parse but do not match)
  • Promise and the event loop
  • Most standard library beyond console, Object.keys, Array.isArray, and the Error family

Not supported (by design)

  • Generators and iterators (function*, yield)
  • Proxy and Reflect
  • Labeled statements and with
  • Tagged template literals
  • Optional chaining (?.) and nullish coalescing (??)

Test suites

Three suites ship with the package, run via tools.tests.run:

tools.tests.run({ suite = "zerojs_lexer" })    -- 60 tests: tokenization
tools.tests.run({ suite = "zerojs_parser" })   -- 144 tests: AST construction and error recovery
tools.tests.run({ suite = "zerojs_semantics" }) -- 336 tests: runtime semantics end-to-end