ZeroJS
Commits
Every published commit of this world, on every branch, newest first.
a85afb711czerojs: ?. ?? ??= ||= &&=, errors print as name: message, console formats values like a JavaScript console and takes host writers, Date.now reads the wall clock, performance.now, a timed-out run keeps the value it returned
---
zerojs: ?. ?? ??= ||= &&=, errors print as name: message, console formats values like a JavaScript console and takes host writers, Date.now reads the wall clock, performance.now, a timed-out run keeps the value it returned
---
world entrypoint: require the zui theme from its current path, so the world publishes
---
merge origin/main: keep the ZeroJS language fixes over the contributed pin, which they extend
---
zJs asset type: say what it is for, how it works and how it is used
---
world entrypoint: point the camera defaults at the assets the default world template usesde08d2c959Merge pull request #2: Contribution: /zero/source/zerojs.package/parser.module, /zero/source/zerojs.package/runtime.module, /zero/source/zerojs.package/bridge.module/init.luau, /zero/source/zerojs.package/api.module/init.luau, /zero/source/zerojs.package/bridge.module, /zero/source/zerojs.package, /zero/source/zerojs.package/api.module, /zero/source/zerojs.package/runtime.module/init.luau, /zero/source/zerojs.package/parser.module/init.luau691f3d45faContribution from world f317f2f4-c3a7-4eb5-bb56-1a7416651dfc8c60f068cfMerge pull request #1: Contribution: /zero/source/zerojs.package/api.module, /zero/source/zerojs.package, /zero/source/zerojs.package/api.module/init.luau, /zero/source/zerojs.package/bridge.module, /zero/source/zerojs.package/bridge.module/init.luau97c99709f1Contribution from world f317f2f4-c3a7-4eb5-bb56-1a7416651dfce51851522ere-derive reference tables against the literals the sources carry91a6406174restage so every cross-boundary site records its container edge349278651erestage so every reference site re-derives its pin89f772d578restage so every reference site is re-derivedfd1a3ae3e7the readme names the import form a consumer can use
require("zerojs.init") resolves only from a world root holding a package under
that name, so it was the one spelling that failed for anyone who installed the
package. The alias form ~zerojs.api resolves wherever the package sits.0259d04488package portability: internal requires use relative identity form (.sibling / ..uncle / .stdlib.child) so installs resolve from any location, including /source/deps/
---
requires name the package alias, so the package resolves wherever it is installed
Every intra-package require now reads ~zerojs.<tail> — the alias the package
registers from its package.yaml name — instead of the world-root identity
zerojs.<tail>, which only resolves from a root literally named zerojs and so
left the package unusable once installed under /source/deps/.
One uniform form across all 87 sites also gives each module a single identity:
reaching the same file under two different literals loaded it twice, which is
what the semantics suite's undefined-sentinel comparisons were failing on.
1220/1220.4e8c980df9compiler+runtime: mcallv inline proto-chain method lookup (accessors/proxies/primitives fall through); nonEnum allocated lazily on first non-enumerable mark (one fewer table per object)cbf554236bzerojs: compiled execution tier over the shared realm
Dense integer-indexed array storage in the runtime (1-shifted Luau
array-part with sparse/named fallback, rt.iget/rt.iset fast paths),
a JS-to-Luau compiler covering the full parsed language against the
same realm value model as the interpreter, and an auto engine in the
api that runs every script compiled-first with a loud interpreter
fallback on compile bail. Full suite green compiled-first; 18x on
array-heavy scripts before type-directed emission.
---
zerojs compiler: local type inference for native emission
Per-function prescan classifies locals provably number-typed (every
assignment produces a number, fixpoint over the candidate set, closures
that mutate a name demote it) and array-typed (array-literal bindings).
Number-typed operands compile to native Luau arithmetic and comparisons,
loop counters increment natively, test positions elide the truthiness
call for boolean-typed expressions, and integer-indexed element access
on known arrays dispatches straight to the runtime's dense fast path.
20k-element fill+sum inside a function: 611ms interpreted, 30.6ms
compiled.
---
zerojs: compiled module evaluation
Module bodies compile to Luau chunks taking (rtc, imports): imports bind
as const chunk locals (assignment traps with the interpreter's exact
TypeError, as do const declarations generally), export declarations
lower to plain statements with an export-name snapshot returned at
completion, dynamic import() and import.meta compile against the realm
hook, and the module graph tries the compiled chunk first with the same
loud interpreter fallback the api engine uses. Module-level bindings are
chunk locals, so the function-level type inference applies to module
code.
---
zerojs compiler: register-pool temps
Transient operand temps come from a per-function register pool declared
once at the function head and reassigned, with the counter resetting at
each statement; construct-persistent values (loop step functions, switch
state, try results) keep dedicated locals. Large minified module bodies
previously exhausted Luau's 200-local limit at loadstring and bailed to
the interpreter; they now compile.
---
zerojs compiler: chunk large literals and argument lists, pooled discards
An array literal or call with hundreds of elements compiled to one Luau
table constructor whose element expressions exhaust the register file;
both now build incrementally past 100 elements. Expression statements
discard through a recycled pool slot (or a bare call statement) instead
of minting a fresh throwaway local each time.
---
zerojs: module graph hands its parsed AST to the compiler
The graph already parses each module for import resolution; the compiled
tier now reuses that AST instead of re-parsing multi-megabyte sources.
---
zerojs compiler: pool watermark recycling and chain slot reuse
Element and property temps in large literals rewind the pool counter per
item; logical chains reuse the left result's slot; operands already held
in a temp pass through instead of copying to a fresh slot. A thousand-
element data literal or a two-hundred-term guard chain now costs a
handful of registers instead of exceeding the register file.
---
zerojs compiler: module-binding spill table
A module whose top-level binding count would exhaust Luau's local or
upvalue register files (200 each) keeps every module-scope binding in a
single spill table: nested functions capture one upvalue instead of one
per referenced constant. Literal and argument fast paths drop to 30
elements so nested constructors stay clear of the register file.
---
zerojs compiler: destination-threaded conditionals, template accumulator
A Cond or Logical in another's arm position writes into the shared
destination temp instead of allocating its own, so right-nested ternary
and guard chains cost one register per chain; arm scratch rewinds once
the result lands. Templates past eight interpolations accumulate into a
single temp instead of one concatenation expression.
---
zerojs compiler: budget every compiled body
A compiled function invoked on a thread with no budget state (a timer or
host callback outside any run) seeds one, honouring the realm's
frame-slicing opt-in. The interpreter budgets every body; a runaway
compiled callback now raises RangeError or parks per slice the same
way instead of holding the frame unbounded.
---
zerojs compiler: parking is exclusive to loop-spawned async bodies
A synchronous compiled callback runs inline on the thread that pumps
the timers; parking there suspends the pump its own resume depends on.
Unseeded callback threads now get a plain RangeError guard, matching
the interpreter's synchronous bodies.
---
zerojs compiler: inline dense element access and loop budget back-edges
A proven array binding with a numeric index reads its dense slot inline
(hole/gap/fractional falls back to the runtime read) and writes inline
for overwrites and boundary appends — a gap write marks the array sparse
so appends near unabsorbed entries reconcile through the runtime. Loop
back-edges fetch the coroutine's budget state once and decrement inline
with a rare slow call. 20k fill+sum: 611ms interpreted, 5.1ms compiled.
---
zerojs: Math intrinsics and own-property fast paths
Math.<fn> on the unshadowed global compiles to the native library call
for the methods whose Luau semantics match JS exactly (floor, ceil, abs,
sqrt, trig, exp, log, pow, zero-arg random); non-number operands coerce
through the runtime. Member reads resolve an own data property in two
table reads before full dispatch, and writes to an existing own data
property store directly — own presence shadows prototype setters, and
frozen objects, proxies, typed arrays, and array length bookkeeping keep
the full path.
---
zerojs: Math.imul/max/min intrinsics
imul multiplies exactly in split 16-bit halves (a double product loses
low bits past 2^53 — mulberry32-class PRNG sequences depend on them);
two-argument max/min coerce and propagate NaN per JS. One runtime call
replaces the global-lookup + property-get + method-call chain that
dominated seeded world generation.
---
zerojs: callback guard budget scales with the realm
The unseeded-thread guard defaulted far below the budgets hosts
configure for their runs, so a long (finite) synchronous callback
tripped RangeError where the interpreter's inherited budget survived.
The guard now reads the realm's callbackBudget knob, defaulting to the
same scale hosts use.
---
fix(compiler): ctorRet only applies to the constructor body itself — an arrow nested in a derived constructor returns its own value; regression tests
---
modules: cross-VM compiled-chunk cache — content-hash keyed; a hit skips parse, codegen, and loadstring; import/re-export/export metadata cached alongside the pure chunk
---
errors: thrown-ring entries carry the realm's current stack context
---
compiler: guarded inline arithmetic/compare — number-hot binary ops run as native Luau operators behind inline type guards; literal and proven-number sides skip their runtime check entirely
---
compiler: inline own-property reads and writes (zero-call hot path mirroring the runtime fast paths); generated chunks request O2 + native compilation + sealed env on engines that support loadstring options (gated on luauNativeSupported)
---
runtime+compiler: O(1) key-membership set on every object (kills the linear keys scan on new-key writes); plain object literals construct in one call (props/keys/keySet built directly); untouched dense arrays append inline on push. objLit 7.9x, push 11.6x measured
---
compiler: rtc.set resolves plain-object writes inline — one prototype-chain accessor consult, then a direct own data write with key bookkeeping; only accessors, proxies, typed arrays, frozen objects, and arrays route through the runtime. Constructor field writes 2.3x, entity population 2.9x
---
compiler: calling convention v2 — vararg call intrinsics (callv/mcallv/mcallcv), __direct dispatch slot, positional-param emission; budget seed confined to the call boundary; hole-safe boundary unpack; literal-receiver paren fix in inline member read/write
---
compiler: classNew v2 — rtc.newv vararg construction, __directCtor on base-class constructors (positional ctor bodies via shared directEligible), construct boundary unpacks at declared width
---
compiler+runtime: ctor field-write fast path (per-object hasAccessors + realm accGen sampling), rtc.newv direct construct for plain-function ctors, stdlib defineProperty plain-data descriptor fast path4c4469713dzerojs: typed arrays cross the bridge as zero-copy layout records
toLuau hands hosts the backing buffer + layout (with a toTable
materializer); toJs wraps a returned record back into a shared view of
its kind. Bytes are shared in both directions.402108cc1azerojs: buffer-backed ArrayBuffer, TypedArray family, and DataView
Element storage is a native Luau buffer: rt.get/rt.set/rt.hasOwn route
canonical numeric keys straight to buffer reads/writes with per-kind
ECMAScript conversions, set() between same-kind views is a byte copy,
fill() doubles a copied span, subarray() shares the buffer, and slice()
copies. DataView covers both byte orders. The bridge crosses typed
arrays to Luau as number arrays read off the buffer and Luau buffers to
JS as Uint8Array views; rt.typedArrayOf / rt.newTypedArray /
rt.newArrayBuffer give hosts direct byte access.b3a74c89dcerrors: rt.thrownRing keeps the last 20 constructed errors — the trail that survives swallowed throws9d8cda50b6event_loop: loop:bodies() live-coroutine census (weak spawn registry); interpreter: parkResumeCount pairs with parkCount for orphaned-park attribution0a69571310interpreter: a named function expression binds its own name inside its body (const-like, function-scoped)c1c8f4da7dparser: 'of' is contextual — valid as a binding name; for-of head matches the identifier form81a53acb2aperf+fix: O(n) array seeding (arraySeed), harden bridge host-call settlement, budget-park slices land one per pump frame
- runtime: rt.arraySeed seeds a fresh array O(1)/element; newArray uses it (rawSet key scan made array construction O(n^2))
- bridge: toJs marshals arrays via arraySeed; a failed deliver() now rejects the promise and balances endHostCall instead of orphaning it
- event_loop: runDueTimers only runs timers armed before the pass; a zero-delay re-arm (budget-parked body resume) runs next pass, so sliced async bodies spread across frames instead of coalescing into one unbounded pass
- interpreter: realm park stats (parkCount, lastParkStack)
- tests: pass-snapshot rule, interval catch-up, sliced-body completion under runAsync2c883d720evm:eval — evaluate against the live loop without clearing armed timers; the inspection path for mid-flight sessions74f553b299docs: zerojs phase 4 plan - zJs assetType + ES modules
---
zerojs: parser - static import/export module forms
---
zerojs: ES module graph - evaluate-once, namespaces, cycles
---
zerojs: zJs assetType - registration, scaffold, write-time diagnostics
---
ES feature pass: generators, dynamic import()/import.meta, BigInt literals, regex lookahead, Proxy get/set traps, Object statics, Math.imul/clz32/fround + precision helpers, regex literals in template interpolations, async budget-slicing5aac753416zerojs: run-boundary loop hygiene + non-JS error wrapping + docs truth3e0064739bdocs: zerojs phase 3 plan — event loop, Promise, async/await, timers
---
zerojs: event loop core — microtasks, timers, clock, queueMicrotask
---
zerojs: Promise
---
zerojs: async functions return promises, await suspends
---
zerojs: async functions return promises, await suspends
---
zerojs: timers + runAsync frame pump + budget yielding
---
zerojs: one runAsync in flight per VM
---
zerojs: yielding env functions surface as JS promises
---
zerojs: phase 3 complete — event loop, Promise, async/await, timers188c72ae6azerojs: final review fixes — lastIndex non-enumerable, parseInt radix coercion, step-guard tune, docs truth pass5a3404a456docs: ZeroJS phase 2 implementation plan (stdlib + regex engine)
---
zerojs: stdlib groundwork — natives, primitive dispatch, iteration hook, stack positions
---
zerojs: stdlib — Object, Function.prototype, global functions
---
zerojs: freeze guards delete
---
zerojs: stdlib — Array
---
zerojs: array literal elisions are holes
---
zerojs: stdlib — String
---
zerojs: lastIndexOf honors fromIndex
---
zerojs: stdlib — Number, Math, Date-lite
---
zerojs: Date.now millisecond resolution
---
zerojs: negative-zero semantics in round, cbrt, toFixed
---
zerojs: stdlib — JSON, Map, Set
---
zerojs: Map constructor consumes entry pairs from map and set sources
---
zerojs: regex engine
---
zerojs: regex capture reset per iteration + JS empty-class semantics
---
zerojs: RegExp + String regex methods
---
zerojs: host-error messages + lone-surrogate rejection
---
zerojs: phase 2 complete — stdlib + regex802ac26fc6zerojs: canonical ~. requires everywhere (package-root + test suites) on the fixed resolver0778ca3733docs: ZeroJS design spec — Luau JS interpreter package + zJs assetType
---
docs: ZeroJS phase 1 implementation plan (core language)
---
zerojs: package scaffold + value sentinels
---
zerojs: lexer
---
zerojs: expression parser
---
zerojs: statement parser + ASI
---
zerojs: suppress in-operator inside for-head initializers
---
zerojs: runtime value model + coercion
---
zerojs: interpreter core
---
zerojs: await is a SyntaxError outside async functions
---
zerojs: classes, destructuring, spread
---
zerojs: property enumerability for for-in/rest + nested-pattern defaults
---
zerojs: public API + minimal globals + marshaling
---
zerojs: phase 1 complete - core language
---
zerojs: fix nlBefore latching inside tokens; align readme + module docs with shipped API
---
zerojs: add the zerojs guide (guides-tool documentation for the package)
---
zerojs: consolidate requires to canonical package forms; public API as api.module with root re-export
---
zerojs: asset-type conformance files (READMEs + .metadata) for publish
---
zerojs: internal env-cell names use % prefix (publish scanner treats @-strings as asset refs)