Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·part ofpackage zerojs.package·originates fromworld f63c1fe3-4…▲1problem

compiler

Compiles JavaScript source (parsed by `zerojs.parser`) to Luau source that executes against the same realm value model as the interpreter (`zerojs.runtime`). Objects, prototypes, the stdlib, promises, typed arrays and the bridge are shared between tiers, so compiled and interpret…

byzero-proxy @ DESKTOP-DB3UJOJ·posted 2mo ago
What it does

compiler

Compiles JavaScript source (parsed by zerojs.parser) to Luau source that executes against the same realm value model as the interpreter (zerojs.runtime). Objects, prototypes, the stdlib, promises, typed arrays and the bridge are shared between tiers, so compiled and interpreted code interoperate freely on one VM: bindings persist across runs, either tier can call functions the other created, and host marshaling behaves identically.

The speed comes from eliminating the interpreter's per-node dispatch and environment lookups: JS statements become plain Luau control flow, locals become Luau locals, and array element access rides the runtime's dense integer-indexed storage (rt.iget/rt.iset).

Surface:

  • compile(source, sourceName?) -> (luauSource?, err?) — translate a program.
  • load(source, sourceName?) -> (chunk?, err?) — translate and load; the chunk takes the runtime companion as its argument.
  • makeRtc(rt, globalObj, globalEnv?) — build the runtime companion binding the JS-semantics operations (operators, member access, calls, classes, destructuring, async/generators, step budgets) to a realm.
  • runOn(rt, globalObj, source, sourceName?) — compile and run against a realm, returning the JS completion value.

Coverage spans the language the parser accepts: expressions and operators with JS coercion semantics, control flow (including switch fall-through and labeled-free break/continue), functions, closures, arrow functions with lexical this, arguments, destructuring with defaults and rest, template literals, regex literals, classes (inheritance, super, accessors, fields, static members), try/catch/finally across loop and return boundaries, async/await on the VM event loop, and generators. A construct outside the covered set raises compile bail: <node>; zerojs.api's auto engine then runs that program on the interpreter and records the bail.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

strict module zerojs.compiler Compiles a JavaScript AST (zerojs.parser) to Luau source that executes against the SAME realm value model as the interpreter (zerojs.runtime). Objects, prototypes, the stdlib, typed arrays and the bridge are shared, so compiled code interoperates with interpreted code and host marshaling with no second value model. Speed comes from eliminating per-node dispatch and environment lookups, plus integer-indexed array fast paths (rt.iget/iset). `compile` returns Luau source; `load` returns a chunk taking the runtime companion `rtc` (built by `makeRtc` from a realm + its global object). A construct outside the covered subset raises "compile bail: <node>" so the caller can fall back to the interpreter for that program.

makeRtc(rt: any, globalObj: any, globalEnv: any?) → any

Runtime companion. `makeRtc(rt, globalObj)` binds the JS-semantics operations compiled code calls into to a specific realm. JS values ARE realm values: undefined = values.undefined, null = values.null, numbers/strings/booleans native, objects = JSObject. Luau nil is never a JS value. `globalEnv` is the interpreter Env whose `vars` map holds the script-scope cells (top-level var/let/const/function bindings). Compiled code reads and writes the SAME cells the interpreter uses, so bindings persist across runs and across engine tiers on one VM. When absent, a private cell table is created (standalone use).

argtypedescription
rtany
globalObjany
globalEnvany?

toUint32(v: any) → number

argtypedescription
vany

toInt32(v: any) → number

argtypedescription
vany

truthy(v: any) → boolean

Every hot operation opens with a native-type fast path: the overwhelming majority of dynamic operands are already numbers/booleans/strings, and the full abstract-operation path only runs for objects and mixed types.

argtypedescription
vany

add(l: any, r: any) → any

argtypedescription
lany
rany

sub(l: any, r: any) → any

argtypedescription
lany
rany

mul(l: any, r: any) → any

argtypedescription
lany
rany

div(l: any, r: any) → any

argtypedescription
lany
rany

mod(l: any, r: any) → any return math

argtypedescription
lany
rany

pow(l: any, r: any) → any return toNumber

argtypedescription
lany
rany

band(l: any, r: any) → any return toInt32

argtypedescription
lany
rany

bor(l: any, r: any) → any return toInt32

argtypedescription
lany
rany

bxor(l: any, r: any) → any return toInt32

argtypedescription
lany
rany

shl(l: any, r: any) → any return toInt32

argtypedescription
lany
rany

shr(l: any, r: any) → any return toInt32

argtypedescription
lany
rany

ushr(l: any, r: any) → any return toUint32

argtypedescription
lany
rany

seq(l: any, r: any) → boolean

Primitive same-type equality is native (NaN ~= NaN holds in both languages); everything else takes the abstract operation.

argtypedescription
lany
rany

sneq(l: any, r: any) → boolean return not rtc

argtypedescription
lany
rany

eq(l: any, r: any) → boolean

argtypedescription
lany
rany

neq(l: any, r: any) → boolean return not rtc

argtypedescription
lany
rany

relational(op: string, l: any, r: any) → boolean

argtypedescription
opstring
lany
rany

lt(l: any, r: any) → boolean return relational

argtypedescription
lany
rany

gt(l: any, r: any) → boolean return relational

argtypedescription
lany
rany

le(l: any, r: any) → boolean return relational

argtypedescription
lany
rany

ge(l: any, r: any) → boolean return relational

argtypedescription
lany
rany

instanceOf(l: any, r: any) → boolean return rt

argtypedescription
lany
rany

inOp(key: any, obj: any) → boolean

argtypedescription
keyany
objany

imul(a: any, b: any) → number

Math.imul: exact low-32-bit product (double multiplication loses precision past 2^53, so the multiply splits at 16 bits).

argtypedescription
aany
bany

max2(a: any, b: any) → number

Two-argument Math.max/min with JS NaN propagation.

argtypedescription
aany
bany

min2(a: any, b: any) → number

argtypedescription
aany
bany

neg(v: any) → number return

argtypedescription
vany

pos(v: any) → number return toNumber

argtypedescription
vany

bnot(v: any) → number return toInt32

argtypedescription
vany

lnot(v: any) → boolean return not rt

argtypedescription
vany

typeof(v: any) → string return rt

argtypedescription
vany

get(obj: any, key: string) → any

Member read mirroring the interpreter's getMember: nullish guard, string indexing / length / StringProto, Number/Boolean protos, else realm get. An own data property on a plain object is the overwhelmingly common case, so it resolves in two table reads before the full dispatch.

argtypedescription
objany
keystring

iget(obj: any, idx: number) → any

Integer-indexed read: strings index characters, arrays hit the dense fast path, everything else routes through the string-key member read.

argtypedescription
objany
idxnumber

getc(obj: any, key: any) → any

Computed read: a numeric key takes the integer path, otherwise the key is coerced to a property key string.

argtypedescription
objany
keyany

set(obj: any, key: string, v: any) → any

argtypedescription
objany
keystring
vany

iset(obj: any, idx: number, v: any) → any

argtypedescription
objany
idxnumber
vany

setc(obj: any, key: any, v: any) → any

argtypedescription
objany
keyany
vany

gget(name: string) → any

Unresolved-name access, mirroring the interpreter's lookupVar/assignVar: script-scope cells shadow the global object; a read of a name that is in neither is a ReferenceError; an assignment to one creates a global-object property.

argtypedescription
namestring

gset(name: string, v: any) → any

argtypedescription
namestring
vany

gtypeof(name: string) → string

`typeof x` on an undeclared global is "undefined", not a ReferenceError.

argtypedescription
namestring

constErr( ) → void

Script-scope declaration: `var` keeps an existing cell (redeclaration is a no-op); lexical kinds bind a fresh cell.

gdeclare(name: string, kind: string) → void

argtypedescription
namestring
kindstring

ginit(name: string, v: any) → any

Declaration initializer: writes the cell directly, bypassing the const assignment guard (a const's own initialization is not an assignment).

argtypedescription
namestring
vany

budget(n: number?, limit: number?, yieldMode: boolean?) → any

argtypedescription
nnumber?
limitnumber?
yieldModeboolean?

budgetRestore(prev: any) → void

argtypedescription
prevany

budgetState( ) → any

The calling coroutine's budget state, seeding the plain guard when absent — loop back-edges fetch it once and decrement inline.

tickPark(st: any) → void

Slow path for an exhausted inline-decremented budget: raise, or park and refill under yield mode.

argtypedescription
stany

tick(n: number) → void

argtypedescription
nnumber

isCallable(fn: any) → boolean

argtypedescription
fnany

call(fn: any, thisVal: any, args: { any }) → any

argtypedescription
fnany
thisValany
args{ any }

mcall(obj: any, key: string, args: { any }) → any

argtypedescription
objany
keystring
args{ any }

mcallc(obj: any, key: any, args: { any }) → any

argtypedescription
objany
keyany
args{ any }

callv(fn: any, thisVal: any, ...: ?) → any

Vararg calling convention: arguments travel as Luau varargs instead of a per-call table. A compiled callee exposes its raw closure on `__direct` (signature (this, p1..pK)) and the varargs pass straight through — Luau drops extras and leaves missing params nil, which the callee head converts to undefined. Only a non-direct callee (host, interpreter, generator/async wrapper) materializes the args table.

argtypedescription
fnany
thisValany
...?

mcallv(obj: any, key: string, ...: ?) → any

argtypedescription
objany
keystring
...?

mcallcv(obj: any, key: any, ...: ?) → any

argtypedescription
objany
keyany
...?

newv(ctor: any, ...: ?) → any

Vararg `new`: a class constructor carrying `__directCtor` constructs in one call with no args table; everything else funnels into rtc.new (the table materializes only on that fallback).

argtypedescription
ctorany
...?

new(ctor: any, args: { any }) → any

argtypedescription
ctorany
args{ any }

func(impl: (any, { any }) → void

Wrap a compiled Luau closure (signature impl(thisVal, args)) as a JS function object living in the realm. A call arriving on a thread with no budget state (a timer or host callback outside any run) seeds a plain guard: a runaway callback raises RangeError like the interpreter's synchronous bodies. Parking belongs exclusively to loop-spawned async bodies — a synchronous callback runs inline on the thread that pumps the timers, and parking there would suspend the pump its own resume depends on.

argtypedescription
impl(any, { any }

call(_rt: any, thisVal: any, argList: { any }) → void

argtypedescription
_rtany
thisValany
argList{ any }

funcD(direct: any, name: string, length: number, nparams: number) → any

Wrap a direct-convention compiled closure (signature (this, p1..pK)). Compiled call sites dispatch `__direct` with varargs — no args table, no budget check: direct dispatch is only reachable from inside compiled code, whose thread was seeded at its entry boundary. The `call` slot is that boundary: host, interpreter, stdlib, and timer callers arrive here with an args table, get the budget seed, and the list unpacks into the direct closure. `nparams` is the declared parameter count: the unpack width. A direct closure can observe at most its declared parameters (no `arguments`, no rest), and a fixed width stays correct when a caller-built list carries nil holes for skipped arguments (`#` would truncate there).

argtypedescription
directany
namestring
lengthnumber
nparamsnumber

call(_rt: any, thisVal: any, argList: { any }) → void

argtypedescription
_rtany
thisValany
argList{ any }

arg(args: { any }, i: number) → any

argtypedescription
args{ any }
inumber

arr(elems: { any }) → any

argtypedescription
elems{ any }

arrFin(arr: any, n: number) → void

Array-literal length finalizer: trailing holes extend the length past the last written index without creating properties.

argtypedescription
arrany
nnumber

obj( ) → any

objLit(vals: any, keyList: { string }) → any

A plain object literal in one construction: `vals` becomes the props table directly and `keyList` the insertion-ordered keys (duplicates already collapsed at compile time). A value that is undefined simply has no vals entry while its key stays listed — present-with-undefined.

argtypedescription
valsany
keyList{ string }

throw(v: any) → void

argtypedescription
vany

isJsThrow(e: any) → void

argtypedescription
eany

spread(v: any) → void

Expand an iterable into a Luau array of JS values (array spread, call spread, and array destructuring share this).

argtypedescription
vany

dguard(v: any) → void

Destructuring support, mirroring the interpreter's bindPattern. A nullish destructuring source is a TypeError.

argtypedescription
vany

relem(source: any, index: number) → any

One element of a destructured source: array/object by index, string by character, anything else undefined.

argtypedescription
sourceany
indexnumber

dget(source: any, key: string) → any

One property of a destructured source (string keys resolve through the member read so string sources get their prototype methods).

argtypedescription
sourceany
keystring

restArr(v: any, start: number) → any

Array-rest: the elements of `v` from index `start` on, as a new array.

argtypedescription
vany
startnumber

restObj(v: any, consumed: { [string]: boolean }) → any

Object-rest: the enumerable own keys of `v` not in `consumed`.

argtypedescription
vany
consumed{ [string]: boolean }

restArgs(args: { any }, start: number) → any

Rest parameter: the tail of the call's argument list from `start` (1-based).

argtypedescription
args{ any }
startnumber

isCallableObj(v: any) → boolean

argtypedescription
vany

classCtx(name: string, superVal: any) → any

Validate the heritage clause and build the class context: prototype object, super constructor, derived flag.

argtypedescription
namestring
superValany

runFields(ctx: any, instance: any) → void

Run the instance field initializers against a revealed instance.

argtypedescription
ctxany
instanceany

classBuild(ctx: any, ctorImpl: any, ctorLen: number, fields: any, directN: number?) → any

Build the constructor function object and wire the prototype chain. `ctorImpl(this, args)` is the compiled constructor body (nil for the default constructor); in a derived class it receives rtc.TDZ as `this` and must reveal it via super(). `directN` marks a positional-convention constructor body: the impl's signature is (this, p1..pN) instead of (this, argList). Only base (non-derived) constructors take it; classBuild then exposes `__directCtor` so rtc.newv constructs with zero intermediate tables.

argtypedescription
ctxany
ctorImplany
ctorLennumber
fieldsany
directNnumber?

call(_rt2: any, _thisVal: any, _args: { any }) → void

argtypedescription
_rt2any
_thisValany
_args{ any }

construct(_rt2: any, args: { any }, _newTarget: any) → void

argtypedescription
_rt2any
args{ any }
_newTargetany

superNew(ctx: any, args: { any }) → any

super(...) inside a derived constructor: construct through the super constructor, adopt the instance under this class's prototype, run the field initializers, and reveal it as `this`.

argtypedescription
ctxany
args{ any }

superGet(ctx: any, static: boolean, key: string) → any

super.<key> read: through the home object's parent with the current `this` untouched. Instance members resolve through the prototype's parent; static members through the super constructor.

argtypedescription
ctxany
staticboolean
keystring

superCall(ctx: any, static: boolean, key: string, thisVal: any, args: { any }) → any

argtypedescription
ctxany
staticboolean
keystring
thisValany
args{ any }

thisChk(v: any) → any

Guard a `this` read in a derived constructor before super() has run.

argtypedescription
vany

ctorRet(v: any, thisVal: any) → any

An explicit `return v` from a derived constructor: an object result overrides; anything else yields the revealed `this`.

argtypedescription
vany
thisValany

installAccessor(target: any, key: string, half: string, fn: any) → void

Install one accessor half (a JS function) onto a target, merging with an existing accessor entry for the other half.

argtypedescription
targetany
keystring
halfstring
fnany

ctorFastW(instance: any) → boolean

Constructor write fast-path eligibility, sampled once at constructor entry: true when no object on the instance's prototype chain owns an accessor. Field writes emitted under this flag also compare rt.accGen against its entry sample, so any accessor install or prototype mutation mid-body reroutes the remaining writes through rt.set.

argtypedescription
instanceany

classMethod(ctx: any, static: boolean, key: string, fn: any) → void

argtypedescription
ctxany
staticboolean
keystring
fnany

classAcc(ctx: any, static: boolean, key: string, half: string, fn: any) → void

argtypedescription
ctxany
staticboolean
keystring
halfstring
fnany

classSField(ctx: any, key: string, init: any) → void

argtypedescription
ctxany
keystring
initany

objAcc(obj: any, key: string, half: string, fn: any) → void

Object-literal accessor property.

argtypedescription
objany
keystring
halfstring
fnany

await(v: any) → any

Async functions and generators. Compiled bodies are ordinary Luau, so they suspend with coroutine.yield exactly like the interpreter's async machinery, sharing the same VM loop and promise module. Await: resolve the operand to a promise (one microtask tick even for non-thenables, per spec) and suspend this coroutine until settlement.

argtypedescription
vany

asyncFunc(impl: (any, { any }) → void

An async call runs its body in a loop-spawned coroutine and returns a result promise: the synchronous prefix runs during the call, the body suspends at its first await, a JS throw becomes the rejection, and a returned value or thenable is adopted.

argtypedescription
impl(any, { any }

call(_rt2: any, thisVal: any, args: { any }) → void

argtypedescription
_rt2any
thisValany
args{ any }

yield(v: any) → any

yield / yield*: runs on the generator's coroutine; the value sent into the matching next() becomes the expression's result.

argtypedescription
vany

yieldStar(v: any) → any

argtypedescription
vany

genFunc(impl: (any, { any }) → void

A generator call builds a suspended body on its own coroutine; next() resumes it to the next yield. The generator object carries next/return and registers with the realm's iterator protocol.

argtypedescription
impl(any, { any }

call(_rt2: any, thisVal: any, args: { any }) → void

argtypedescription
_rt2any
thisValany
args{ any }

step(sendVal: any) → void

argtypedescription
sendValany

call(_rt3: any, _this3: any, nargs: { any }) → void

argtypedescription
_rt3any
_this3any
nargs{ any }

call(_rt3: any, _this3: any, nargs: { any }) → void

argtypedescription
_rt3any
_this3any
nargs{ any }

importCall(spec: any) → any

import() expression: resolve through the realm's dynamic-import hook and hand back a settled promise of the namespace (module bodies evaluate synchronously, so the promise is born resolved or rejected).

argtypedescription
specany

importMeta(url: string) → any

import.meta: an object carrying the module's url.

argtypedescription
urlstring

regex(pattern: string, flags: string) → any

A regex literal constructs a fresh RegExp through the realm's RegExp constructor, so each evaluation yields an independent object with its own lastIndex.

argtypedescription
patternstring
flagsstring

iter(v: any) → void

for-of driver: returns a step function yielding (hasValue, value). Arrays iterate by live index (length re-read each step), mirroring the interpreter's array-first iteration; strings yield characters; anything else consults the realm's iterator registry.

argtypedescription
vany

keys(v: any) → void

for-in driver: enumerable keys of the object and its prototype chain.

argtypedescription
vany

jsName(name: string) → string

argtypedescription
namestring

propIsPlain(name: string) → boolean

argtypedescription
namestring

bail(node: any, why: string?) → never

argtypedescription
nodeany
whystring?

isSimpleNode(node: any) → boolean

A node whose evaluation is order-independent and side-effect-free, safe to inline into an operand position without a temp.

argtypedescription
nodeany

newGen( ) → any

emit(self: any, line: string) → void

argtypedescription
selfany
linestring

newTemp(self: any) → string

Transient temp from the function's register pool. Pool slots are declared once at the function head and reassigned; the counter resets at each statement, so a statement's operand temps recycle the same few registers instead of exhausting Luau's 200-local limit on large bodies. A pool value never outlives its statement's own emission.

argtypedescription
selfany

persistTemp(self: any) → string

Construct-persistent temp: a dedicated local whose value survives across nested statement execution (loop step functions, switch state, try results). Never recycled.

argtypedescription
selfany

markPoolSlot(self: any) → void

Record where the pool declaration belongs (after the function preamble); `finishPool` inserts it once the body is generated and the high-water mark is known.

argtypedescription
selfany

finishPool(self: any) → void

argtypedescription
selfany

pushScope(self: any) → void

argtypedescription
selfany

popScope(self: any) → void

argtypedescription
selfany

declare(self: any, name: string, kind: string?) → void

`kind` distinguishes const bindings (assignment traps) from mutable ones.

argtypedescription
selfany
namestring
kindstring?

isConstLocal(self: any, name: string) → boolean

Is the nearest declaration of `name` a const binding?

argtypedescription
selfany
namestring

isLocal(self: any, name: string) → boolean

argtypedescription
selfany
namestring

currentScopeHas(self: any, name: string) → boolean

Declared in the innermost scope specifically — lexical declarations shadow an outer binding by emitting a fresh Luau local, so the check that guards redeclaration must not look past the current scope.

argtypedescription
selfany
namestring

scanPatternNames(pat: any, out: { string }) → void

Hoisting scan: collect var + function-declaration names reachable in a function/program body without descending into nested functions.

argtypedescription
patany
out{ string }

scanVarsList(body: { any }, out: { string }) → void

argtypedescription
body{ any }
out{ string }

scanVarsStmt(stmt: any, out: { string }) → void

argtypedescription
stmtany
out{ string }

numericExpr(node: any, numVars: { [string]: boolean }) → boolean

argtypedescription
nodeany
numVars{ [string]: boolean }

inferTypes(body: { any }) → void

Scan one function body (not descending into nested function bodies except to spot assignments that capture and mutate outer names) and return (numVars, arrVars): the names provably number- and array-typed throughout.

argtypedescription
body{ any }

demote(name: string) → void

argtypedescription
namestring

recordAssign(name: string, rhs: any) → void

argtypedescription
namestring
rhsany

scanNestedFn(node: any) → void

Inside a nested function only mutations of outer names matter.

argtypedescription
nodeany

scanExpr(node: any) → void

argtypedescription
nodeany

scanStmt(node: any) → void

argtypedescription
nodeany

referencesArguments(node: any) → boolean

Does a function body reference `arguments`? Arrows inherit the outer binding, so the scan descends into arrow functions but not into nested non-arrow functions (which bind their own).

argtypedescription
nodeany

directEligible(node: any) → boolean

Shared direct-convention parameter eligibility: no rest param, no duplicate plain names, a bounded count, and no `arguments` reference in a non-arrow body. Used by function emission and by class emission when deciding whether a constructor body can take the positional convention.

argtypedescription
nodeany

scanLexical(body: { any }, out: { string }) → void

Direct block-level lexical declarations (let/const/class/function names) that become locals scoped to this block.

argtypedescription
body{ any }
out{ string }

expr(self: any, node: any) → string

Expressions Compile a node to a Luau expression string, emitting any needed preceding statements. Guarantees left-to-right evaluation for callers that sequence operands through `operand`.

argtypedescription
selfany
nodeany

operand(self: any, node: any) → string

Evaluate a node into a simple operand (inline for trivial nodes, otherwise a hoisted temp) so an ordered operand list keeps left-to-right evaluation.

argtypedescription
selfany
nodeany

arrayLit(self: any, node: any) → string

argtypedescription
selfany
nodeany

objectLit(self: any, node: any) → string

argtypedescription
selfany
nodeany

rtNumKey(n: number) → string

argtypedescription
nnumber

isSuperNode(node: any) → boolean

argtypedescription
nodeany

emitSetNamed(self: any, obj: string, name: string, v: string) → void

Emit a named member write: an overwrite of an existing own data property lands directly in the props slot with zero calls (own presence shadows any proto setter); everything else — new keys, accessors, frozen/proxy/array/ typed-array receivers, primitives — takes the full runtime write.

argtypedescription
selfany
objstring
namestring
vstring

memberGet(self: any, node: any) → string

argtypedescription
selfany
nodeany

argList(self: any, args: { any }) → string

Build a Luau table-constructor of the argument values, expanding spreads.

argtypedescription
selfany
args{ any }

argParts(self: any, args: { any }) → string

Arguments as a bare operand list for the vararg calling convention. Returns nil when the call needs the table form (spread, or a list big enough to pressure the register file).

argtypedescription
selfany
args{ any }

call(self: any, node: any) → string

argtypedescription
selfany
nodeany

isNum(self: any, node: any) → boolean

Is this expression provably number-typed under the current function's inferred locals?

argtypedescription
selfany
nodeany

isArr(self: any, node: any) → boolean

argtypedescription
selfany
nodeany

boolTest(self: any, node: any) → string

Compile a test-position expression to a Luau boolean: comparisons and logical not are already boolean; everything else goes through rtc.truthy.

argtypedescription
selfany
nodeany

binary(self: any, node: any) → string

argtypedescription
selfany
nodeany

numGuard( ) → string

operand() results are re-read-safe (literals, locals, temps; globals hoist), so the guard can reference them twice. A side that is a number literal or a proven-number expression needs no runtime check.

emitArmInto(self: any, node: any, dest: string) → void

Emit an arm's value into an existing destination temp. A Cond or Logical in arm position threads the destination down instead of allocating its own temp, so right-nested ternary/guard chains cost one register per chain. The arm's scratch temps die once the result lands, so the counter rewinds.

argtypedescription
selfany
nodeany
deststring

logicalInto(self: any, node: any, dest: string) → void

argtypedescription
selfany
nodeany
deststring

condInto(self: any, node: any, dest: string) → void

argtypedescription
selfany
nodeany
deststring

logical(self: any, node: any) → string

Short-circuit operators compile to a temp filled by if-statements, so the right operand is only evaluated when needed and no closure is allocated.

argtypedescription
selfany
nodeany

cond(self: any, node: any) → string

argtypedescription
selfany
nodeany

unary(self: any, node: any) → string

argtypedescription
selfany
nodeany

assign(self: any, node: any) → string

Assignment as an expression: returns the assigned value.

argtypedescription
selfany
nodeany

patBind(self: any, pat: any, srcT: string, mode: string) → void

Recursive destructuring emission. `srcT` is a Luau temp holding the current source value; `mode` picks the leaf binding form: "local" — declare (or assign an already-declared) Luau local "gvar" — program-level var: assign the hoisted script-scope cell "ginit" — program-level let/const: initialize the script-scope cell "assign" — plain assignment (locals, globals, and member targets)

argtypedescription
selfany
patany
srcTstring
modestring

resolveLocal(self: any, name: string) → void

Resolve a name to its storage: the scope index it binds in (nearest-first) and its kind, or nil when unbound (a global reference).

argtypedescription
selfany
namestring

varRef(self: any, name: string) → string

The Luau expression for a bound name. A module compiled in spill mode keeps its module-scope bindings in the `_L` table (one upvalue for every nested function, no per-binding local/upvalue registers); everything else is a plain local.

argtypedescription
selfany
namestring

identRef(self: any, name: string) → string

argtypedescription
selfany
namestring

emitDenseWrite(self: any, obj: string, key: string, v: string) → void

Inline dense-array element write for a proven array binding and numeric index: overwrites hit the slot, appends push the dense boundary and bump the length property (always present on the key list from newArray on); gaps and non-integer indices take the runtime write.

argtypedescription
selfany
objstring
keystring
vstring

emitAssignIdent(self: any, name: string, valueExpr: string) → void

argtypedescription
selfany
namestring
valueExprstring

update(self: any, node: any, asExpr: boolean) → string

++/-- : returns old value (postfix) or new value (prefix).

argtypedescription
selfany
nodeany
asExprboolean

template(self: any, node: any) → string

argtypedescription
selfany
nodeany

funcExpr(self: any, node: any, opts: any?) → string

opts.classCtx = { ctxT, static } enables super resolution in the body; opts.ctor = { ctxT, derived } marks a constructor body (this-TDZ guards, return-through-ctorRet, super() revealing `this`); opts.raw emits a plain Luau closure instead of a realm function object (constructor impls).

argtypedescription
selfany
nodeany
optsany?

classExpr(self: any, node: any) → string

Compile a class (declaration or expression) to an IIFE producing the constructor. Member bodies compile as realm functions with the class context bound for super resolution; the constructor compiles as a raw closure invoked by the runtime's construct path.

argtypedescription
selfany
nodeany

memberKeyExpr(member: any) → string

argtypedescription
memberany

fieldInit(valueNode: any, static: boolean) → string

A field initializer compiles to a plain closure over `this`, with the class context available for super and the class-name binding captured.

argtypedescription
valueNodeany
staticboolean

stmt(self: any, node: any) → void

Statements

argtypedescription
selfany
nodeany

varDecl(self: any, node: any) → void

argtypedescription
selfany
nodeany

funcDecl(self: any, node: any) → void

argtypedescription
selfany
nodeany

exprStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

discardExpr(self: any, e: any) → void

Evaluate an expression for effect only. A call compiles to a bare Luau call statement; anything else assigns a recycled pool slot (a fresh `local _` per statement would exhaust the register file on large bodies).

argtypedescription
selfany
eany

assignEffect(self: any, node: any) → void

Assignment executed for side effect (statement position).

argtypedescription
selfany
nodeany

ifStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

countNodes(node: any) → number

Approximate interpreter step count of a subtree: one step per AST node, excluding nested function bodies (their steps are consumed when called). Loop back-edges tick this amount so the step budget trips at roughly the same script size on both tiers.

argtypedescription
nodeany

hasDirectContinue(node: any) → boolean

Does this statement subtree contain a Continue that would bind to the loop being compiled (not to a nested loop, and not inside a nested function)?

argtypedescription
nodeany

noComp(self: any, fn: () → void

Loop bodies do not feed the program completion value (the interpreter's While/DoWhile/For all complete with no value); clear the accumulator while compiling one.

argtypedescription
selfany
fn(

emitLoopBudget(self: any, cost: number) → string

The loop's budget back-edge: the coroutine's state is fetched once ahead of the loop, and each iteration decrements inline with a rare slow call.

argtypedescription
selfany
costnumber

whileStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

loopBodyWithTail(self: any, body: any, emitTail: () → void

A loop whose Luau body has trailing statements after the JS body (a for update, a do-while test) cannot use a bare Luau `continue` — it would skip them. When the JS body continues directly, wrap it in a one-shot repeat so continue compiles to breaking the wrapper, landing on the trailing code.

argtypedescription
selfany
bodyany
emitTail(

doWhileStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

forStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

stmtForUpdate(self: any, expr: any) → void

argtypedescription
selfany
exprany

forOfStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

forInStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

bindForHead(self: any, left: any, valueTmp: string) → void

Bind the loop variable of a for-of/for-in head to the Luau temp holding the current value/key.

argtypedescription
selfany
leftany
valueTmpstring

tryStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

switchStmt(self: any, node: any) → void

argtypedescription
selfany
nodeany

stmtOrBlock(self: any, node: any) → void

argtypedescription
selfany
nodeany

blockBody(self: any, body: { any }) → boolean

A block body: pre-declare its lexical bindings, initialize function declarations (hoisted: callable before their source position), then compile the remaining statements. Compilation stops after a Luau control terminator (return/break/continue) — Luau forbids statements after one in a block, and the dropped JS statements are unreachable. Returns true when the emitted block ended in a terminator.

argtypedescription
selfany
body{ any }

block(self: any, body: { any }) → boolean

argtypedescription
selfany
body{ any }

compile(source: string, sourceName: string?) → void

Entry points

argtypedescription
sourcestring
sourceNamestring?

collectDeclNames(decl: any, out: { string }) → void

Collect the bound names of a declaration statement (VarDecl patterns, function/class ids) — the names an `export <decl>` exposes.

argtypedescription
declany
out{ string }

compileModule(source: string, id: string, importNames: { string }, parsedAst: any?) → void

Compile a module body to a Luau chunk. The chunk takes (rtc, imports) — `imports` maps local import names to their resolved values — and returns { exports = { exportedName = value }, hasDefault, default }: the same completion snapshot the interpreter's evalModuleBody builds. Module-level bindings are chunk locals (module scope dies with the module), so the function-level type inference applies to module code. `parsedAst` (when the caller already parsed the module) skips the re-parse.

argtypedescription
sourcestring
idstring
importNames{ string }
parsedAstany?

loadChunk(luau: string, name: string) → void

argtypedescription
luaustring
namestring

loadModule(source: string, id: string, importNames: { string }, parsedAst: any?) → void

Compile and load a module body; the chunk takes (rtc, imports).

argtypedescription
sourcestring
idstring
importNames{ string }
parsedAstany?

load(source: string, sourceName: string?) → void

Compile and load: returns a chunk taking the runtime companion `rtc`.

argtypedescription
sourcestring
sourceNamestring?

runOn(rt: any, globalObj: any, source: string, sourceName: string?) → any

Convenience: compile `source` and run it against realm `rt` + `globalObj`, returning the JS completion value (not marshaled).

argtypedescription
rtany
globalObjany
sourcestring
sourceNamestring?

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

Showing up to 3 levels deep. Open a part to see what it holds further down.

18+items
❒
package · born here
❒asset
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 ```luau local zerojs = require("~zerojs.api") ``` `~zerojs` is this package's alias, registered from the `name` in its `package.yaml` wherever the package sits. The same spelling therefore works from the world that authors the package and from a world that installed it, at any depth. Every module is reachable the same way — `~zerojs.parser`, `~zerojs.stdlib.promise` — and the package's own modules reference each other with those ids. ## 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. Raises directing to `runAsync` when the script leaves a timer armed or a coroutine suspended across a frame. | | `vm:runAsync(src, opts?)` | Execute `src`, driving its event loop across engine frames until it settles. Returns a `RunHandle` immediately. `opts.timeoutMs` rejects the run if it outlasts that many milliseconds. Only one `runAsync` may be in flight per VM at a time; a second call while the first is unsettled raises. | | `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. | ### `RunHandle` (returned by `vm:runAsync`) | Field | Description | |-------|-------------| | `done` | `false` until the run reaches a terminal state, then `true`. | | `ok` | Once `done`, `true` for a resolved run and `false` for a rejection or timeout. | | `value` | The marshaled completion value on a resolved run. | | `error` | The rendered message text on a rejected or timed-out run. | | `lastError` | The structured `{ name, message, stack }` payload for a failed run. | | `thread` | The engine `task.spawn` driver pumping the loop each frame — present only while the run is still pumping, and `nil` once the run settles on its arming frame (a synchronous or microtask-only completion needs no per-frame driver). | | `handle:await(maxFrames?)` | From a yieldable Luau context, poll `done` frame-by-frame until the handle settles, then return it. | A `runAsync` stays pending while the loop has work: an armed `setInterval` keeps it pending exactly as an un-`unref`'d handle keeps Node alive — clear the interval or bound the run with `timeoutMs`. ## 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 - 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`; `switch` with fallthrough - `async`/`await` — real event-loop semantics: an async function returns a promise, runs synchronously up to the first `await`, and resumes from a microtask when its awaited operand settles - Property enumerability: `for-in` yields only own enumerable keys; object rest excludes prototype methods ### Asynchrony and the event loop - `Promise` with the full ES surface: `then`/`catch`/`finally`, `resolve`/`reject`, and the combinators `all`, `allSettled`, `race`, and `any` (with `AggregateError` when every input to `any` rejects) - `queueMicrotask` for scheduling a microtask directly - Timers: `setTimeout`/`clearTimeout` and `setInterval`/`clearInterval`, with extra arguments forwarded to the callback - `vm:runAsync(src, opts?)` drives a script's timers, microtasks, and promise settlements across engine frames and returns a `RunHandle` (see the VM table above) - A long synchronous loop under `runAsync` yields at each step-budget boundary and resumes on a later frame instead of raising `RangeError`; the same script under `vm:run` still raises ### Standard library - `Object`: callable coercion plus `keys`, `values`, `entries`, `assign`, `freeze`, `isFrozen`, `create`, `getPrototypeOf`, `defineProperty`, `fromEntries`, `hasOwn`, and the `Object.prototype` methods (`hasOwnProperty`, `toString`, `isPrototypeOf`) - `Function.prototype`: `call`, `apply`, `bind` - Global conversions and predicates: `parseInt`, `parseFloat`, `isNaN`, `isFinite`, `String`, `Number`, `Boolean` - `Array` and `Array.prototype`: construction, `isArray`, `from`, `of`, and the iteration/mutation/query methods (`map`, `filter`, `reduce`, `forEach`, `find`, `some`, `every`, `slice`, `splice`, `concat`, `join`, `indexOf`, `includes`, `sort`, `reverse`, `push`, `pop`, `shift`, `unshift`, `flat`, `fill`, `keys`, `values`, `entries`) - `String.prototype`: `slice`, `substring`, `substr`, `split`, `indexOf`, `includes`, `startsWith`, `endsWith`, `repeat`, `padStart`, `padEnd`, `trim`, `trimStart`, `trimEnd`, `toUpperCase`, `toLowerCase`, `charAt`, `charCodeAt`, `codePointAt`, `at`, `concat`, `replace`, `replaceAll`, `match`, `matchAll`, `search` - `Number`: `isInteger`, `isSafeInteger`, `isFinite`, `isNaN`, `parseFloat`, `parseInt`, `MAX_SAFE_INTEGER`, `MIN_SAFE_INTEGER`, `MAX_VALUE`, `MIN_VALUE`, `EPSILON`, `POSITIVE_INFINITY`, `NEGATIVE_INFINITY`, `NaN`, and `Number.prototype` (`toFixed`, `toString`, `toPrecision`) - `Math`: the constants and functions (`abs`, `floor`, `ceil`, `round`, `trunc`, `sign`, `min`, `max`, `pow`, `sqrt`, `cbrt`, `hypot`, `exp`, `log`, `log2`, `log10`, the trig family, `random`) - `Date`: construction as `new Date()` (now) and `new Date(ms)` (epoch milliseconds), `now`, `getTime`, `getFullYear`, `getMonth`, `getDate`, `getHours`, `getMinutes`, `getSeconds`, `getMilliseconds`, `getDay`, `toISOString`, `toJSON` - `JSON`: `parse` and `stringify` (indent argument and array replacer whitelist) - `Map` and `Set`: construction from iterables, `get`/`set`/`has`/`delete`/`clear`, `add`, `size`, `forEach`, `keys`, `values`, `entries`, insertion-order iteration - `RegExp`: literals and the constructor, `test`, `exec`, `lastIndex`, `source`, `flags`, `global`, `ignoreCase`, `multiline`, `dotAll`, and the `String` regex methods above - Errors: `Error`, `TypeError`, `RangeError`, `ReferenceError`, `SyntaxError` constructors and inheritance; `console.log`/`warn`/`error`; `globalThis`, `NaN`, `Infinity` ### Out of scope by design - Generators and iterators (`function*`, `yield`) - `Proxy` and `Reflect` - Labeled statements and `with` - Tagged template literals - Optional chaining (`?.`) and nullish coalescing (`??`) The full divergence list — where ZeroJS behavior differs from a browser engine — lives in the guide's divergence section. ## Test suites Seven suites ship with the package, run via `tools.tests.run`: ```luau tools.tests.run({ suite = "zerojs_lexer" }) -- tokenization tools.tests.run({ suite = "zerojs_parser" }) -- AST construction and error recovery tools.tests.run({ suite = "zerojs_semantics" }) -- runtime semantics end-to-end tools.tests.run({ suite = "zerojs_stdlib" }) -- the standard-library surface tools.tests.run({ suite = "zerojs_regex" }) -- the regex engine and RegExp methods tools.tests.run({ suite = "zerojs_async" }) -- the event loop, promises, and timers tools.tests.run({ suite = "zerojs_smoke" }) -- unmodified real-world JS programs ```
▲ 1↑ born
▣
module · born here
❒asset
# values The JavaScript value model: the `undefined` and `null` sentinels, their predicates, and `jsTypeof`, which classify the primitive and reference values the interpreter operates on.
▲ 0↑ born
▣
module · born here
❒asset
# parser The JavaScript parser: `parser.parse(src, sourceName)` lexes the source and builds the abstract syntax tree the interpreter walks, applying operator precedence, automatic semicolon insertion, and syntax-error reporting.
▲ 0↑ born
▣
module · born here
❒asset
# errors Construction and propagation of JavaScript errors: `makeError` builds a JS Error object, `throwJs`/`throwError` raise a thrown JS value across the Luau boundary, and `isJsThrow` recovers it, so JS exceptions round-trip as Luau errors.
▲ 0↑ born
▣
module · born here
❒asset
# stdlib The JavaScript standard-library surface installed onto a realm's global object. `stdlib.install(rt, globalObj)` applies each submodule installer. `object.luau` owns the `Object` callable and its statics, `Object.prototype`, `Function.prototype` (call/apply/bind), a minimal `Number.prototype.toString`, and the global conversion and parsing functions (`parseInt`, `parseFloat`, `isNaN`, `isFinite`, `String`, `Number`, `Boolean`).
▲ 0↑ born

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

These counts cover only the parts this page shows. Problems on the parts it leaves out are not counted here.

1+problem

Inside

1 problem across 1 item
▲
dep.dangling.checksum_drift · L17
dep `~zerojs.stdlib.promise` -> 4b552cd1-c4b2-495d-afe8-008fe0ceb08a no longer resolves (checksum_drift)
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.