A complete JavaScript engine and runtime environment for classic
Amiga computers. Built from scratch in C, targeting MC68000 and
AmigaOS 2.0+. Inspired by Node.js, adapted for the Amiga platform.
Features
--------
* JavaScript engine (ES5.1 + ES6+ features)
- Arrow functions, classes with inheritance, super(), static methods
- Class fields: public, private (#field), static
- Template literals, tagged templates
- Destructuring, spread/rest, default parameters
- for-of loops, labeled break/continue
- Regex literal syntax /pattern/flags
- Optional chaining (?.), nullish coalescing (??)
- BigInt (123n, arithmetic, comparison, BigInt())
- let/const block scoping, numeric separators
- async/await, Promises, dynamic import()
- Generators (function*, yield, yield* delegation)
- Async generators (async function*, for await...of)
- Generator methods in classes and objects
- Automatic Semicolon Insertion (ASI)
- Closures, prototype chain
* Built-in objects and functions
- console (log, error, warn, dir, time/timeEnd, table,
count/countReset)
- Math (27 functions incl. cbrt/fround/clz32/imul)
- JSON (with reviver/replacer)
- Date (full API incl. UTC, getUTC*/setUTC*)
- RegExp (lookahead, non-capturing groups, quantifiers,
lazy quantifiers, named groups, lookbehind,
flags g/i/m/s/u/y)
- Buffer (hex/base64)
- Promise (then/catch/finally/all/race/allSettled)
- Map, Set, WeakMap, WeakSet, Symbol
- setTimeout/setInterval/clearTimeout
- crypto (MD5, SHA-256), structuredClone
- TextEncoder, TextDecoder
- Typed Arrays: Uint8Array, Int8Array, Uint16Array,
Int16Array, Uint32Array, Int32Array, Float32Array,
Float64Array, Uint8ClampedArray, ArrayBuffer, DataView
(from/of, forEach/map/filter/find/every/some/reduce,
set/fill/slice/subarray/reverse/indexOf/includes/join)
- fetch() global HTTP client
- performance.now() high-resolution timer
- Error.cause (ES2022)
- process.stdout.write, process.stdin.read
- process.hrtime, process.nextTick, queueMicrotask
* String methods: 29+ (charAt, indexOf, slice, split,
replace, replaceAll, trim, includes, startsWith,
padStart, normalize, localeCompare, codePointAt, etc.)
* Array methods: 37+ (push, pop, map, filter, reduce,
reduceRight, sort, find, findLast, findLastIndex,
forEach, every, some, splice, flat, flatMap, entries,
keys, values, copyWithin, at, Array.from/of/isArray,
toReversed, toSorted, toSpliced, with)
* Object: keys, values, entries, assign, create, freeze,
seal, is, fromEntries, defineProperty/ies, hasOwn,
getPrototypeOf, setPrototypeOf, getOwnPropertyNames,
getOwnPropertyDescriptor(s), preventExtensions,
isExtensible, groupBy, getOwnPropertySymbols,
getters/setters
* Number: isInteger, isFinite, isNaN, isSafeInteger,
parseInt, parseFloat, toString(radix), toFixed,
toExponential, toPrecision, constants (EPSILON,
MAX_SAFE_INTEGER, MIN_SAFE_INTEGER, NaN, Infinity)
* Global functions: encodeURIComponent, decodeURIComponent,
encodeURI, decodeURI, parseInt, parseFloat, isNaN,
isFinite, eval(), fetch()
* Symbol: Symbol(), Symbol.for/keyFor, well-known symbols,
Symbol as property key, Iterator protocol (Symbol.iterator)
* Amiga Intuition GUI bindings
- Open windows with title, size, position
- Graphics: lines, rectangles, circles, text, pixels
- Mouse and keyboard event handling
- System requesters (alert, confirm)
- Screen information query
* GadTools GUI toolkit (gui module)
- createWindow() with declarative gadget layout
- 11 widget types: button, string, text, integer,
checkbox, cycle, slider, listview, mx, number, scroller
- Resizable windows (GIMMEZEROZERO clipping)
- Percentage layout (left: "50%", width: "80%")
- Negative positioning (top: -20 = anchored to bottom)
- flex: true — gadget expands to fill available space
- minWidth/minHeight constraints
- Event-driven: waitEvent/pollEvent, gadgetup/close/key
- get/set gadget values at runtime (works on hidden gadgets)
- setTitle, listview dynamic item update
- Proper GadTools cleanup (FreeGadgets, FreeVisualInfo)
* Node.js-compatible module system
- require() with module caching
- CommonJS exports (module.exports)
- ES modules: import/export (default, named, namespace)
- Dynamic import() expression
- Native modules: fs, http, net, buffer, os,
child_process, crypto, intuition, gui, readline, dns
- JS modules: path, events, url, querystring, util,
stream, assert, repl, timers, string_decoder,
punycode, console, constants, zlib, iff
* File I/O (fs module)
- readFileSync, writeFileSync, appendFileSync
- existsSync, unlinkSync, renameSync, statSync
- readdirSync, mkdirSync, rmdirSync, copyFileSync
- readFile, writeFile (async with callbacks)
- createReadStream, createWriteStream
- Full AmigaOS path support (Volume:dir/file)
* HTTP/HTTPS server and client
- http.createServer() — non-blocking, 8 concurrent
- http.get(), http.post(), http.request()
- HTTPS via AmiSSL (build with -DENABLE_AMISSL)
- Automatic redirect following (301/302/307)
- 10-second socket timeout, dns.lookup()
- Requires bsdsocket.library (e.g. Roadshow, Miami)
* OS integration
- process.platform ("amigaos"), process.arch ("m68k")
- process.argv, process.env, process.cwd(), process.exit
- os.cpus() (detects 68000/020/030/040/060)
- os.freemem(), os.version() (Kickstart version)
- child_process.execSync() via SystemTagList()
* Interactive REPL with command history (arrow up/down)
* Error types: Error, TypeError, RangeError, ReferenceError,
SyntaxError, EvalError, URIError
* Error messages with filename and line number
* Compiler: bundle JS + interpreter into standalone executable
- NodeAmiga -compile MyApp script.js
- Automatic require() and import dependency resolution
- All JS modules bundled into single executable
- No NodeAmiga, no libs/ needed to run the output
Usage
-----
NodeAmiga script.js Execute a JavaScript file
NodeAmiga -e "code" Evaluate inline JavaScript
NodeAmiga -compile out script Compile JS to standalone executable
NodeAmiga Start interactive REPL
NodeAmiga -help Show help
NodeAmiga -v Show version
NodeAmiga --tree script.js Use tree-walking interpreter
NodeAmiga --ast script.js Print AST (debug)
Installation
------------
1. Copy NodeAmiga to C: or any directory in your path
2. Copy the libs/ directory to PROGDIR: (same directory
as NodeAmiga), or to LIBS:node/
3. Optional: copy examples/ for demo scripts
Quick test:
NodeAmiga -e "console.log('Hello Amiga!')"
NodeAmiga examples/hello.js
NodeAmiga examples/gui_hello.js
NodeAmiga examples/fibonacci.js
Compile to standalone exe:
NodeAmiga -compile Hello examples/hello.js
Hello
; Runs without NodeAmiga or libs/ !
System Requirements
-------------------
* MC68000 or higher CPU
* AmigaOS 2.04 (Kickstart 37) or higher
* Minimum 1 MB RAM (2+ MB recommended for scripts)
* bsdsocket.library for networking features
(Roadshow, Miami, AmiTCP, or similar)
* No FPU required (software floating-point)
Technical Details
-----------------
* Engine: custom-built lexer, recursive descent parser
with Pratt precedence climbing, bytecode VM (default)
with tree-walking fallback for advanced features
* Bytecode VM: ~8x faster than tree-walking on benchmarks,
lazy compilation, direct native dispatch
* Memory: reference counting (no GC pauses), arena
allocator for AST, integer cache 0-255
* Stack: auto-allocates 64 KB via StackSwap
Included Examples
-----------------
hello.js Platform info and greeting
fibonacci.js Recursive/iterative/memoized benchmark
file_io.js File read/write/append operations
http_server.js HTTP server with routing
http_client.js HTTP GET and POST requests
classes.js ES6 classes with inheritance
closures.js Closures, IIFE, module pattern
array_fun.js map/filter/reduce/sort with real data
regex.js RegExp /literal/ syntax and methods
events.js EventEmitter custom events
promises.js Promise chains, all, race
timers.js setTimeout and setInterval
buffer.js Binary data manipulation
streams.js Readable/Writable/Transform streams
sysinfo.js Full system information display
todo_app.js TODO app with file persistence
mini_grep.js Pattern search in files
url_parser.js URL and query string parsing
calculator.js Recursive descent expression parser
json_db.js JSON file-based database
myip.js Fetch public IP from internet
nettime.js Internet time via HTTP API
weather.js Weather info for a city
download.js Download file and save to disk
gui_hello.js Simplest Intuition window from JS
gui_demo.js Interactive drawing with mouse events
gui_calculator.js GadTools calculator (fits 320x200)
3d.js Rotating 3D wireframe cube (XOR, vsync)
3d_tunnel.js Wireframe tunnel fly-through
pong.js Bouncing ball (XOR, filled circle)
gui_translator.js Google Translate with GadTools GUI
gui_window.js GadTools widget gallery (all 11 gadgets)
dns_lookup.js DNS hostname resolution
readline_chat.js Interactive readline with prompt/events
iff_info.js IFF/ILBM/8SVX file information viewer
Known Limitations
-----------------
* No Proxy
* await is synchronous (spin-waits on event loop)
Version History
---------------
0.14.0 (2026-03-28) — Bytecode VM (8x faster)
- NEW: Bytecode compiler + virtual machine (default mode)
~8x faster than tree-walking on benchmarks (score 9888
vs 1262). Lazy compilation, direct native dispatch.
Use --tree for tree-walking fallback.
- NEW: gfx.setDrawMode() — JAM1/JAM2/COMPLEMENT(XOR)
- NEW: gfx.waitTOF() — vertical blank sync (vsync)
- NEW: win.innerWidth, win.innerHeight properties
- NEW: 3d_tunnel.js, pong.js examples
- FIX: NaN === NaN returned true (pointer equality bug)
- FIX: Arrays missing prototype (push/pop/map undefined)
- FIX: Buffer overflow in toFixed for numbers > 1e24
- FIX: Buffer overflow in regex replace zero-length match
- FIX: Use-after-free on borrowed refs in function calls
0.13.0 (2026-03-27) — Typed Arrays + fetch + fs streams
- NEW: Typed Arrays (Uint8Array, Int8Array, Uint16Array,
Int16Array, Uint32Array, Int32Array, Float32Array,
Float64Array, Uint8ClampedArray)
- NEW: ArrayBuffer (constructor, slice, isView)
- NEW: DataView (get/set Int8/Uint8/Int16/Uint16/Int32/
Uint32/Float32/Float64, little/big endian support)
- NEW: TypedArray.from(), TypedArray.of() static methods
- NEW: TypedArray forEach/map/filter/find/findIndex/
every/some/reduce iterator methods
- NEW: Typed array indexed assignment (u8[0]=42 updates
backing ArrayBuffer store)
- NEW: Array.toReversed(), toSorted(), toSpliced(), with()
(ES2023 immutable array methods)
- NEW: Object.getOwnPropertySymbols()
- NEW: Error.cause (ES2022 error chaining)
- NEW: fetch() global HTTP client (returns Response with
ok, status, body properties)
- NEW: fs.readFile(), fs.writeFile() (async with callbacks)
- NEW: fs.createReadStream(), fs.createWriteStream()
(EventEmitter-based, chunked reading/writing)
- NEW: TypedArray sort(), copyWithin(), toString()
- NEW: console.count(), console.countReset()
- NEW: performance.now() (20ms resolution via DateStamp)
- NEW: zlib module (pure JS DEFLATE/INFLATE, gzip/gunzip,
deflateSync/inflateSync/gzipSync/gunzipSync, CRC32)
- NEW: punycode module (RFC 3492, toASCII/toUnicode)
- NEW: constants module (signals, errno, fs constants)
- NEW: console module (require('console') wrapper)
- NEW: Resizable GUI windows with responsive layout
(percentage positions, flex gadgets, GIMMEZEROZERO)
- NEW: gui.createWindow minWidth/minHeight constraints
- NEW: Negative position values (anchor to bottom/right)
- NEW: Keyboard events: evt.key string property
- NEW: dns.resolve(), dns.resolve4(), dns.resolveSync()
- NEW: readline: on('line'/'close'), setPrompt(), prompt()
- NEW: assert.rejects(), assert.doesNotReject()
- NEW: HTTP server custom headers in res.writeHead()
- NEW: iff module (IFF/ILBM/8SVX parser, ByteRun1 RLE)
- FIX: Date.now() returns integer (was returning float)
- FIX: Buffer overflow in toFixed for numbers > 1e24
- FIX: Buffer overflow in regex replace zero-length match
- FIX: Use-after-free on borrowed refs in function calls
- FIX: BigInt mixed-type operations throw TypeError
- FIX: zlib inflate EOF handling (no infinite loop)
- FIX: punycode.decode pure ASCII input handling
- Tests: 1700+ assertions across 3 test suites
0.12.0 (2026-03-27) — Generators + Class Fields
- NEW: Generator functions (function*, yield)
- NEW: yield* delegation to sub-generators/iterables
- NEW: gen.next(value) — send values into generators
- NEW: gen.throw(err) — throw at yield point, catchable
- NEW: Generator methods in classes (*method(){}) and objects
- NEW: for...of integration with generators
- NEW: Generator loop resume (for, while, do-while, for-of)
- NEW: Array.from() with iterator protocol
- NEW: yield as identifier in non-generator contexts
- NEW: Class fields (public: x = 5, static: static y = 10)
- NEW: Private class fields (#field, #method())
- NEW: Dynamic import() expression
- NEW: Object.groupBy()
- NEW: Async generators (async function*, for await...of)
- NEW: RegExp lookbehind (?<=...), (?<!...)
- NEW: BigInt type (123n, arithmetic, comparison, BigInt())
- NEW: GadTools GUI module (require('gui'))
button, string, text, integer, checkbox, cycle,
slider, listview, mx, number, scroller widgets
- NEW: URL class and URLSearchParams (WHATWG standard)
- NEW: path.normalize, isAbsolute, parse, format, relative
- NEW: assert.deepStrictEqual, ifError, match, doesNotMatch
- NEW: stream.pipeline(), stream.finished(), backpressure
- NEW: stream.Readable.from(), cork/uncork, highWaterMark
- NEW: string_decoder module (UTF-8 boundary handling)
- NEW: timers.setInterval async iterator, timers.setImmediate
- NEW: os.endianness, os.release, os.networkInterfaces,
os.userInfo, os.devNull, os.constants
- FIX: Memory leaks in array methods (forEach, map, filter,
reduce, reduceRight, sort, flatMap, entries)
- FIX: Use-after-free in array_reduce (index arg freed too early)
- FIX: String.concat buffer overflow with multiple args
- FIX: String.match/search/matchAll/replace memory leaks
- FIX: JSON \uXXXX now produces proper UTF-8 (was '?')
- FIX: BigInt from double (AmigaOS sprintf has no %f support)
- FIX: Switch fall-through into default case
- FIX: Spread in function calls (tracked per-argument)
- FIX: ** exponentiation now right-associative (2**3**2 = 512)
- FIX: fn.call()/fn.apply() now propagate thrown exceptions
- FIX: for-of string/iterator memory leaks
- FIX: Class method memory leaks (static + instance)
- FIX: yield* delegation iterator/result leaks
- FIX: Array.from() iterator and callback leaks
- FIX: Error constructor memory leaks (name/message/stack)
- FIX: Object.entries/getOwnPropertyDescriptors leaks
- FIX: RegExp constructor leak on error paths
- FIX: crypto hash double-digest crash
- FIX: fs.statSync directory detection via AmigaOS Lock()
- FIX: Import path buffer overflow for long paths
- FIX: NULL dereference in strict/loose equality
- FIX: Object property delete getter/setter leak
- FIX: Async class methods now parsed correctly
- FIX: Math.random() seed from system time (was constant)
- FIX: encodeURI preserves reserved characters
- FIX: 60+ total bug fixes for stability and memory
- NEW: Web runtime addon (addons/web/) — run GUI scripts
in browser unmodified, Amiga WB3.x look & feel
- NEW: Edge case test suite (test_edge.js, 430+ assertions)
- FIX: Function property assignment (fn.prop = val was ignored)
- FIX: JSON.parse reviver use-after-free crash
- FIX: Spread in new expression (new Foo(...args))
- FIX: Unicode \u{XXXX} braced escapes (ES6)
- FIX: REPL arena use-after-free (closures referencing freed AST)
- FIX: Generator throw propagation (4 missing checks)
- FIX: Array.from() mapper memory leaks
- FIX: \uNNNN > 0x7F now produces proper UTF-8 (was '?')
- FIX: AmiSSL lazy initialization (saves RAM at startup)
- FIX: HTTPS check order (ssl_ensure_init before g_ssl_ok)
- FIX: Labeled break/continue in nested loops
- FIX: Buffer indexed access (buf[0] returned undefined)
- FIX: Symbol.toString() crash
- FIX: Date/RegExp/Promise instanceof
- FIX: require("buffer").Buffer self-reference
- FIX: Computed property read/write on functions
- FIX: 90+ total bug fixes for stability and memory
- Tests: 1550+ assertions across 3 test suites
0.11.0 (2026-03-25) — Mega Mega Update
- NEW: fs.readdirSync, mkdirSync, rmdirSync, copyFileSync
- NEW: Array: reduceRight, entries, keys, values,
findLast, findLastIndex, copyWithin
- NEW: Object: getOwnPropertyNames, hasOwn, getPrototypeOf,
getOwnPropertyDescriptor(s), setPrototypeOf,
preventExtensions, isExtensible, isPrototypeOf,
propertyIsEnumerable
- NEW: Number.prototype.toExponential, toPrecision
- NEW: Math: cbrt, fround, clz32, imul + constants
- NEW: String: codePointAt, fromCodePoint, localeCompare,
normalize, raw, replace with callback
- NEW: encodeURI/decodeURI, encodeURIComponent/decodeURIComponent
- NEW: console.dir (JSON-formatted output)
- NEW: ES modules (import/export) with default, named, namespace
- NEW: RegExp: {n}/{n,}/{n,m} quantifiers, lazy (*?/+?/??),
non-capturing groups (?:), lookahead (?=)/(?!),
named groups (?<name>), flags s/u/y
- NEW: Symbol as property key, Iterator protocol
- NEW: eval() global function
- NEW: EvalError, URIError error types
- NEW: Date.UTC(), getUTC*/setUTC* (15 methods)
- NEW: Class static methods
- NEW: Destructuring assignment without var/let/const
- NEW: Compiler (-compile) — bundle JS into standalone executable
- FIX: Function.prototype.bind() partial application
- FIX: ES module export function declarations
- FIX: instanceof Error for all Error subtypes
- Tests: 960+ assertions covering all features
0.10.0 (2026-03-25)
- FIX: String.fromCharCode, Number.isInteger/isFinite/
isNaN/isSafeInteger now work correctly
- FIX: Number.prototype.toString(radix) for hex/bin/oct
- FIX: querystring.unescape percent decoding
- Removed 68040/68060 builds (focus on 68000/68020)
0.9.0 (2026-03-24)
- HTTPS support via AmiSSL
- Interactive REPL with readline and history
- Buffer hex/base64 encoding
- Tagged template literals
- Promise chain fixes
0.8.0 (2026-03-23)
- Map, Set, WeakMap, WeakSet, Symbol
- Regex literal /pattern/flags syntax
- async/await support
- Destructuring, spread/rest operators
- for-of loops, optional chaining (?.)
Credits
-------
Juen/Project R3D+Appendix+Nah-Kolor
|