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
| Symbol | Type | Description |
|---|---|---|
zerojs.eval(src) | (string) -> any | Parse 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?) -> VM | Create a persistent VM. opts.env seeds additional JS globals from a Luau table. |
zerojs.null | sentinel | The JS null value (distinct from Luau nil). |
zerojs.undefined | sentinel | The JS undefined value, which marshals to Luau nil when returned. |
zerojs.version | string | Version 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
| Method | Description |
|---|---|
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),letandconstwith 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,
newarguments, 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.logError,TypeError,RangeError,ReferenceError,SyntaxErrorconstructors and inheritance- Property enumerability:
for-inyields only own enumerable keys; object rest excludes prototype methods
Not yet supported
- Regular expression evaluation (regex literals parse but do not match)
Promiseand the event loop- Most standard library beyond
console,Object.keys,Array.isArray, and theErrorfamily
Not supported (by design)
- Generators and iterators (
function*,yield) ProxyandReflect- 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