From ce085dcdd4afb6abe507b4026318333978ef0a10 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Fri, 2 Jan 2026 16:10:08 -0800 Subject: [PATCH] compact more, add add delete operator tests --- examples/spec/delete.js | 57 +++++++++++++++++++++++++++++++++++++++++ meson.build | 2 +- src/ant.c | 15 +++++++---- tests/delete.js | 15 +++++++++++ 4 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 examples/spec/delete.js create mode 100644 tests/delete.js diff --git a/examples/spec/delete.js b/examples/spec/delete.js new file mode 100644 index 0000000..f122c3c --- /dev/null +++ b/examples/spec/delete.js @@ -0,0 +1,57 @@ +import { test, summary } from './helpers.js'; + +console.log('Delete Operator Tests\n'); + +const obj = { a: 1, b: 2, c: 3 }; + +let result = delete obj.a; +test('delete existing property returns true', result, true); +test('property removed after delete', obj.a, undefined); +test('has property after delete', 'a' in obj, false); +test('other properties remain', obj.b, 2); + +result = delete obj.nonexistent; +test('delete non-existent property returns true', result, true); + +const nested = { outer: { inner: 42 } }; +result = delete nested.outer.inner; +test('delete nested property', result, true); +test('nested property removed', nested.outer.inner, undefined); +test('parent still exists', typeof nested.outer, 'object'); + +const arr = [1, 2, 3, 4, 5]; +result = delete arr[2]; +test('delete array element returns true', result, true); +test('array element becomes undefined', arr[2], undefined); +test('array length unchanged', arr.length, 5); +test('array has hole', 2 in arr, false); + +const withUndefined = { x: undefined }; +result = delete withUndefined.x; +test('delete property set to undefined', result, true); +test('property gone after delete', 'x' in withUndefined, false); + +const computed = { foo: 'bar', baz: 'qux' }; +const key = 'foo'; +result = delete computed[key]; +test('delete with computed key', result, true); +test('computed key property removed', computed.foo, undefined); + +const proto = { inherited: true }; +const child = Object.create(proto); +child.own = 'value'; +result = delete child.own; +test('delete own property', result, true); +test('own property removed', child.own, undefined); +test('inherited property still accessible', child.inherited, true); +result = delete child.inherited; +test('delete inherited returns true but keeps it', result, true); +test('inherited still accessible after delete', child.inherited, true); + +const symbolKey = Symbol('test'); +const withSymbol = { [symbolKey]: 'symbol value' }; +result = delete withSymbol[symbolKey]; +test('delete symbol property returns true', result, true); +test('symbol property removed', withSymbol[symbolKey], undefined); + +summary(); diff --git a/meson.build b/meson.build index 56aa1a1..1e38ff5 100644 --- a/meson.build +++ b/meson.build @@ -86,7 +86,7 @@ endif build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() version_conf = configuration_data() -version_conf.set('ANT_VERSION', '0.3.1.15') +version_conf.set('ANT_VERSION', '0.3.1.16') version_conf.set('ANT_GIT_HASH', git_hash) version_conf.set('ANT_BUILD_DATE', build_date) diff --git a/src/ant.c b/src/ant.c index df58580..8e47663 100644 --- a/src/ant.c +++ b/src/ant.c @@ -2321,7 +2321,7 @@ static jsoff_t js_alloc(struct js *js, size_t size) { ofs = js->brk; if (js->brk + size > js->size) return ~(jsoff_t) 0; } else { - ANT_GC_COLLECT(); + js_gc_compact(js); ofs = js->brk; if (js->brk + size > js->size) { if (js_try_grow_memory(js, size)) { @@ -4616,8 +4616,7 @@ static jsval_t do_bracket_op(struct js *js, jsval_t l, jsval_t r) { jsoff_t off = lkp_proto(js, obj, keystr, keylen); if (off == 0) { jsval_t key = js_mkstr(js, keystr, keylen); - jsval_t prop = setprop(js, obj, key, js_mkundef()); - return prop; + return mkpropref((jsoff_t)vdata(obj), (jsoff_t)vdata(key)); } return mkval(T_PROP, off); } @@ -7670,6 +7669,7 @@ static void unlink_prop(struct js *js, jsoff_t obj_off, jsoff_t prop_off, jsoff_ jsoff_t deleted_next = loadoff(js, prop_off) & ~FLAGMASK; jsoff_t target = prev_off ? prev_off : obj_off; jsoff_t current = loadoff(js, target); + saveoff(js, target, (deleted_next & ~3U) | (current & (FLAGMASK | 3U))); increment_version(js, obj_off); } @@ -7862,11 +7862,14 @@ do_delete: { jsoff_t first_prop = loadoff(js, obj_off) & ~(3U | FLAGMASK); if (first_prop == prop_off) { unlink_prop(js, obj_off, prop_off, 0); - return js_mktrue(); + js_gc_compact(js); return js_mktrue(); } for (jsoff_t prev = first_prop; prev != 0; ) { jsoff_t next_prop = loadoff(js, prev) & ~(3U | FLAGMASK); - if (next_prop == prop_off) { unlink_prop(js, obj_off, prop_off, prev); return js_mktrue(); } + if (next_prop == prop_off) { + unlink_prop(js, obj_off, prop_off, prev); + js_gc_compact(js); return js_mktrue(); + } prev = next_prop; } return js_mktrue(); @@ -20620,6 +20623,7 @@ bool js_del(struct js *js, jsval_t obj, const char *key) { jsoff_t current = loadoff(js, obj_off); saveoff(js, obj_off, (deleted_next & ~3U) | (current & (FLAGMASK | 3U))); increment_version(js, obj_off); + js_gc_compact(js); return true; } @@ -20631,6 +20635,7 @@ bool js_del(struct js *js, jsval_t obj, const char *key) { jsoff_t prev_flags = loadoff(js, prev) & FLAGMASK; saveoff(js, prev, deleted_next | prev_flags); increment_version(js, obj_off); + js_gc_compact(js); return true; } prev = next_prop; diff --git a/tests/delete.js b/tests/delete.js new file mode 100644 index 0000000..7d5def1 --- /dev/null +++ b/tests/delete.js @@ -0,0 +1,15 @@ +const user = { + name: 'Alice', + age: 30, + active: true +}; + +console.log(Ant.gc()); + +console.log(user.age); // Output: 30 + +delete user.age; // The 'delete' operator returns true on success + +console.log(user.age); // Output: undefined +console.log(user); // Output: { name: 'Alice', active: true } +console.log(Ant.gc()); -- 2.51.2