Supported syntax
Every unit of source lamassu-js compiles is treated as an ES module and executes under strict-mode semantics — there is no sloppy mode, no mode switch, and no "use strict" directive to write (it's already on).
Declarations
letandconst— yes.var— no. It's a reserved word that produces a targeted error ('var' is not supported; use 'let' or 'const') rather than a generic parse failure, and it is never silently aliased tolet(their hoisting and redeclaration semantics differ, and this engine treats a silent behavior difference from real JS as the worst possible failure mode for a templating language).- Block-scoped
functiondeclarations are hoisted within their block, same as real JS. - Assigning to an undeclared variable is a compile-time
ReferenceError, not an implicit global (a strict-mode rule the engine applies unconditionally).
Control flow
if/else, for, while, do...while, for...of, switch — all supported. for...in is not (a targeted parse error points you at for...of: SyntaxError: for-in is not supported; use for-of).
Functions
- Regular functions, arrow functions, default parameters, rest parameters (
...args), spread in call arguments. - Closures and upvalues work as expected; the interpreter never uses the C stack for JS calls, so recursion depth is bounded and checked, not a segfault risk.
thisin a plain function isundefined(strict-mode semantics, not the global object).arguments.callee/arguments.callerare not supported.- Duplicate parameter names are a compile error.
Objects, arrays, and constructors
- Object and array literals, computed property names, shorthand properties, spread (
{...obj},[...arr]), destructuring (including defaults and nested patterns) in both declarations and assignments. newworks, with real prototype chains:Ctor.prototypeis a genuine, script-visible object, an instance's[[Prototype]]is set to it at construction, and property lookup walks the chain — the same mechanism built-in instance methods (Array, Date, Map, Set, RegExp) use to reach their own prototype's methods.Object.getPrototypeOf/Object.setPrototypeOfare available.__proto__as an accessor property is not.- Classes are not supported. Use constructor functions and
Ctor.prototypeinstead — see the example below.
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.length = function () {
return Math.sqrt(this.x * this.x + this.y * this.y);
};
const p = new Point(3, 4);
p.length(); // 5Strings
Template literals (including tagged-less interpolation and multi-line strings) are supported. Strings are UTF-16 internally, matching JS .length/indexing semantics exactly.
Error handling
try/catch/finally and throw are fully supported, including finally blocks that run on every exit path (return, break, continue, rethrow).
Async
async/await, including top-level await in a module. See Async & host calls for how this connects to native/host functions.
Modules
import / export, including named exports, export default, export * from, export { a as b } from, and export * as ns from. Cyclic and diamond import graphs are supported. See the Deviations page for the edge cases (TDZ on cyclic reads, snapshot vs. live re-exports).
Regular expressions
Supported, ECMAScript-flavored, via a dedicated backtracking VM (baru-re) compiled into the engine. Catastrophic backtracking is bounded by an engine-side step budget — a pathological pattern throws a catchable RangeError: regular expression step budget exhausted instead of hanging.
Explicit non-goals
These are permanent scoping decisions, not a "not yet implemented" list:
evaland theFunctionconstructor. Both would let guest code synthesize and run new source at runtime, which is exactly what a sandbox for untrusted scripts needs to prevent.- Sloppy (non-strict) mode. Every unit of source is a module; there is no script goal to make sloppy.
for...in, labeled statements,with.- Advanced built-ins:
Reflect,Proxy,Symbol, generators, typed arrays,Intl. - Full spec conformance. Where the subset overlaps real JS, behavior is meant to match Node closely enough for differential testing — edge-case fidelity beyond that isn't a goal. See Deviations from real JS for the specifics.
- Native code generation. Bytecode interpretation is the execution model; it's also the only practical option running inside WebAssembly (no runtime codegen in linear memory).