Open
Conversation
0eb3475 to
7c1c574
Compare
75fdba5 to
527d5b9
Compare
…tring
Iterator:
- for-of/destructuring on null throws TypeError with proper message
- for-of/destructuring on undefined throws TypeError
- for-of on non-iterable values throws TypeError instead of silently
using empty iterator
Function.prototype.toString:
- Returns source code for closures/bytecode functions
- Returns 'function name() { [native code] }' for builtins
test262: 451 → 444 failures (7 more passing)
Route toPrimitive valueOf/toString calls through Invocation instead of Interpreter directly. Invocation properly manages context save/ restore and globals refresh after callbacks.
BigInt values now support .toString() returning the decimal string
representation and .valueOf() returning the BigInt value. Fixes
template literals and string coercion for BigInt values (e.g.
\`${1n}n\` in test262 harness assert._formatIdentityFreeValue).
Symbol.toPrimitive: - to_primitive now checks @@toPrimitive on the object first (per spec 7.1.1 ToPrimitive), before falling back to valueOf/toString BigInt methods: - (1n).toString() returns decimal string - (1n).valueOf() returns the BigInt value test262: 444 → 445 (1 regression in symbol coercion error identity)
get_or_create_prototype now sets __proto__ to Object.prototype on auto-created function prototypes. This ensures objects created via `new F()` inherit toString/valueOf from Object.prototype through the prototype chain: obj -> F.prototype -> Object.prototype. Also: Symbol.toPrimitive support in to_primitive, BigInt.toString/ valueOf methods, Function.prototype.toString. test262: 445 → 443 (2 more passing: this/instanceof tests)
- Infinity == Infinity now returns true (was false because :infinity atom didn't match is_number guard) - NaN == anything returns false (explicit clause) - 0n == '' returns true (empty string treated as 0 for BigInt comparison) - BigInt string comparison trims whitespace test262: 443 → 439 (4 more passing)
mod now calls to_number on non-numeric operands before computing. true % true = 0, null % 1 = 0, '1' % '1' = 0 now work correctly. Also added numeric_mod helper for infinity/NaN/zero cases: - x % ±Infinity = x (not NaN) - ±Infinity % x = NaN - x % 0 = NaN test262: 439 → 430 (9 more passing)
- safe_mul: determines overflow sign from operand signs (-1.1 * MAX_VALUE → neg_infinity, not infinity) - safe_add: determines overflow sign from operand signs - add/sub for numbers now use safe_add to handle overflow - div_inf: Infinity / 0 → Infinity (was NaN because 0 didn't match the n > 0 guard) test262: 430 → 427 (3 more passing)
BigInt comparisons: - 1n < true, 0n < true, 1n > false etc. now work by coercing booleans to numbers before comparing with BigInt - Added boolean clauses for lt/lte/gt/gte with BigInt Equality: - Infinity == Infinity is true (atoms match) - NaN == anything is false (explicit clauses) - 0n == '' is true (empty string → 0) Float overflow: - safe_mul determines overflow sign from operand signs - safe_add determines overflow sign from operand signs - Infinity / 0 returns Infinity (not NaN) test262: 430 → 425 (5 more passing from this batch)
- has_property now checks prototype chain via Get.get fallback
(fixes 'toString' in {}, 'valueOf' in {}, 'MAX_VALUE' in Number)
- has_property added for {:builtin, _, _} values
- 'in' operator throws TypeError for non-object RHS
(fixes 'x' in true, 'x' in 42, etc.)
test262: 425 → 420 (5 more passing)
typeof:
- {:builtin, _, map} when is_map(map) returns 'object' instead of
'function'. Fixes typeof Math === 'object', typeof JSON === 'object'.
Callable builtins (functions) still return 'function'.
new:
- {:builtin, _, map} namespace objects (Math, JSON) throw TypeError
when used with 'new'. Only callable builtins can be constructors.
test262: 420 → 418 (2 more passing)
When valueOf/toString throws during type coercion (e.g.
{valueOf: function(){throw 'x'}} & 1), the JS throw must be
caught by the interpreter's try/catch handling, not propagated
through the Elixir call stack.
Previously only op_add had a catch_js_throw wrapper. Now ALL
operators that can trigger toPrimitive coercion are wrapped:
- Arithmetic: add, sub, mul, div, mod, pow
- Bitwise: band, bor, bxor, shl, sar, shr, bnot
- Comparison: lt, lte, gt, gte, eq, neq
- Unary: neg, plus (to_number)
This fixes 14 test262 tests where valueOf/toString throws inside
try/catch blocks.
test262: 418 → 404 (14 more passing)
…t32 for objects
- lt/lte/gt/gte: handle BigInt vs :infinity/:neg_infinity/:nan
- abstract_eq: BigInt vs boolean coercion (0n == false → true)
- to_int32/to_uint32: call to_number for {:obj, _} and handle infinity/NaN
test262: 404 → 400
- typeof :neg_infinity returns 'number' (was falling to 'object')
- isNaN: convert non-number args via to_number before checking
(isNaN(true) now correctly returns false)
- isFinite: same to_number coercion for non-number args
- BigInt vs infinity/NaN: explicit comparison clauses for all operators
- BigInt vs boolean: abstract_eq handles 0n == false → true
- to_int32/to_uint32: call to_number for {:obj, _} values
test262: 404 → 398 (6 more passing from batched fixes)
- truthy?(-0.0) returns false (Elixir distinguishes +0.0 from -0.0 in pattern matching) - op_truthy inline helper also handles -0.0 - isNaN: converts non-number args via to_number before checking - isFinite: same to_number coercion test262: 400 → 397
- Register Function constructor with auto_proto: true, creating Function.prototype with __proto__ → Object.prototype - Fixes 'MyFunct instanceof Function' and similar checks - Only Function gets auto_proto (Boolean/Number/String cause regressions due to __proto__ interference with property resolution) Also includes: typeof :neg_infinity, -0.0 falsy, isNaN/isFinite coercion, BigInt vs infinity/NaN comparisons. test262: 404 → 396 (8 more passing from all batched fixes)
Set `this` to globalThis in eval context (was :undefined). When get_var can't find a variable in ctx.globals, check globalThis object properties as fallback. This bridges 'this.p1 = 1' with bare 'p1' variable access. Also: Object.defineProperties implementation. test262: 396 → 345 (51 tests fixed — with-statement scope tests)
- get_var_undef: checks globalThis properties when variable not found in ctx.globals (for typeof x where x is on globalThis) - put_var: syncs variable assignments to globalThis object so this.x and x stay consistent across scope boundaries test262: 345 → 344
- op_delete_var returns false (var declarations are non-configurable per spec, delete x should return false) - get_var_undef checks globalThis fallback for typeof - put_var syncs assignments to globalThis for this.x/x consistency test262: 345 → 341
Closures, bytecode functions, builtins, and bound functions now
return their toString() representation from to_primitive() instead
of the raw tuple (which caused NaN in arithmetic).
f1 + 1 → 'function f1(){return 0}1' (was NaN)
test262: 341 (no change — affected tests have other issues)
Closures, bytecode functions, builtins, and bound functions now return proper string representations from stringify() instead of '[object]'. Matches Function.prototype.toString behavior. test262: 341 (no change)
Result: {"status":"keep","failing_tests":172,"passing_tests":330}
Result: {"status":"keep","failing_tests":172,"passing_tests":330}
…r.locks, console extensions, Worker, EventSource, WritableStream fixes
…x Put.put for length on plain objects
…nceof, Promise.race, EventSource drain, Worker improvements
…ll NIF web API parity achieved.
Result: {"status":"keep","failing_tests":0,"passing_tests":502}
- 0 compiler warnings (--warnings-as-errors clean) - 0 credo issues (--strict clean) - 0 dialyzer errors (was 15) - Fix FormData encode_multipart to handle string values (not just Blob)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a second QuickJS execution backend on the BEAM.
What’s in here
:beambackend viaQuickBEAM.disasm/2mode: :beamsupport in the public APIrequire(), module loading, dynamic import, globals, handlers, and interop for the VM pathError.captureStackTraceRuntime coverage
Object,Array,Function,String,Number,BooleanMath,JSON,Date,RegExpMap,Set,WeakMap,WeakSet,SymbolPromise,async/await, generators, async generatorsProxy,ReflectTypedArray,ArrayBuffer,BigIntsuper, private fields, private methods, private accessors, static private members, brand checksValidation
QUICKBEAM_BUILD=1 MIX_ENV=test mix testMIX_ENV=test QUICKBEAM_BUILD=1 mix test test/vm/js_engine_test.exs --include js_engine --seed 0mix compile --warnings-as-errorsmix format --check-formattedmix credo --strictmix dialyzermix ex_dnazlint lib/quickbeam/*.zig lib/quickbeam/napi/*.zigbunx oxlint -c oxlint.json --type-aware --type-check priv/ts/bunx jscpd lib/quickbeam/*.zig priv/ts/*.ts --min-tokens 50 --threshold 0Current local result:
2363 tests, 0 failures, 1 skipped, 54 excluded