From 5b9f1b8f510f88cc2c5d573a4ab4477729709bb4 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Fri, 6 Jun 2025 10:31:41 -0500 Subject: [PATCH] closes #12 --- scripts/engine.cm | 18 ++++++++-------- source/qjs_blob.c | 10 +++++++++ tests/blob.ce | 55 ++++++++++++++++++++++++++--------------------- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/scripts/engine.cm b/scripts/engine.cm index 825d91b6..f8a98a2a 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -285,9 +285,14 @@ function load_actor_config(program) { var blob = use('blob') +var blob_stone = blob.prototype.stone +var blob_stonep = blob.prototype.stonep; +delete blob.prototype.stone; +delete blob.prototype.stonep; + function deepFreeze(object) { if (object instanceof blob) - object.stone() + blob_stone.call(object); // Retrieve the property names defined on object var propNames = Object.keys(object); @@ -307,14 +312,9 @@ function deepFreeze(object) { globalThis.stone = deepFreeze stone.p = function(object) { - if (object instanceof blob) { - try { - object.read_logical(0) - return true - } catch(e) { - return false - } - } + if (object instanceof blob) + return blob_stonep.call(object) + return Object.isFrozen(object) } diff --git a/source/qjs_blob.c b/source/qjs_blob.c index 0f5bd645..b5a25b5d 100644 --- a/source/qjs_blob.c +++ b/source/qjs_blob.c @@ -371,6 +371,15 @@ static JSValue js_blob_stone(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } +static JSValue js_blob_stonep(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) { + blob *bd = js2blob(ctx, this_val); + if (!bd) { + return JS_ThrowTypeError(ctx, "stone: not called on a blob"); + } + return JS_NewBool(ctx, bd->is_stone); +} + // blob.length getter // Return number of bits in the blob static JSValue js_blob_get_length(JSContext *ctx, JSValueConst this_val, int magic) { @@ -402,6 +411,7 @@ static const JSCFunctionListEntry js_blob_funcs[] = { // Other methods JS_CFUNC_DEF("stone", 0, js_blob_stone), + JS_CFUNC_DEF("stonep", 0, js_blob_stonep), // Length property getter JS_CGETSET_DEF("length", js_blob_get_length, NULL), diff --git a/tests/blob.ce b/tests/blob.ce index 67af21f0..f2d105c3 100644 --- a/tests/blob.ce +++ b/tests/blob.ce @@ -51,7 +51,7 @@ test("Write and read single bit", function() { b.write_bit(0); assertEqual(b.length, 4, "Should have 4 bits after writing"); - b.stone(); // Make it stone to read + stone(b); // Make it stone to read assertEqual(b.read_logical(0), true, "First bit should be true"); assertEqual(b.read_logical(1), false, "Second bit should be false"); assertEqual(b.read_logical(2), true, "Third bit should be true (1)"); @@ -62,7 +62,7 @@ test("Write and read single bit", function() { test("Out of range read throws error", function() { var b = new Blob(); b.write_bit(true); - b.stone(); + stone(b); var threw = false; try { @@ -88,7 +88,7 @@ test("Write and read numbers", function() { b.write_number(-42); b.write_number(0); b.write_number(1e20); - b.stone(); + stone(b); // Read back the numbers assertEqual(b.read_number(0), 3.14159, "First number should match"); @@ -103,7 +103,7 @@ test("Write and read text", function() { b.write_text("Hello"); b.write_text("World"); b.write_text("🎉"); // Unicode test - b.stone(); + stone(b); assertEqual(b.read_text(0), "Hello", "First text should match"); // Note: We need to know bit positions to read subsequent strings @@ -121,7 +121,7 @@ test("Write and read blobs", function() { b2.write_bit(false); assertEqual(b2.length, 4, "Combined blob should have 4 bits"); - b2.stone(); + stone(b2); assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(1), false); assertEqual(b2.read_logical(2), true); @@ -135,10 +135,10 @@ test("Blob copy constructor", function() { b1.write_bit(false); b1.write_bit(true); b1.write_bit(true); - b1.stone(); + stone(b1); var b2 = new Blob(b1); - b2.stone(); // Need to stone the copy before reading + stone(b2); // Need to stone the copy before reading assertEqual(b2.length, 4, "Copied blob should have same length"); assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(3), true); @@ -150,10 +150,10 @@ test("Blob partial copy constructor", function() { for (var i = 0; i < 10; i++) { b1.write_bit(i % 2 === 0); } - b1.stone(); + stone(b1); var b2 = new Blob(b1, 2, 7); // Copy bits 2-6 (5 bits) - b2.stone(); // Need to stone the copy before reading + stone(b2); // Need to stone the copy before reading assertEqual(b2.length, 5, "Partial copy should have 5 bits"); assertEqual(b2.read_logical(0), true); // bit 2 of original assertEqual(b2.read_logical(2), true); // bit 4 of original @@ -164,8 +164,8 @@ test("Create blob with fill", function() { var b1 = new Blob(8, true); // 8 bits all set to 1 var b2 = new Blob(8, false); // 8 bits all set to 0 - b1.stone(); - b2.stone(); + stone(b1); + stone(b2); for (var i = 0; i < 8; i++) { assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true"); @@ -182,7 +182,7 @@ test("Create blob with random function", function() { return sequence[index++] ? 1 : 0; }); - b.stone(); + stone(b); for (var i = 0; i < 5; i++) { assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence"); } @@ -197,7 +197,7 @@ test("Write pad and check padding", function() { b.write_pad(8); // Pad to 8-bit boundary assertEqual(b.length, 8, "Should be padded to 8 bits"); - b.stone(); + stone(b); assert(b['pad?'](3, 8), "Should detect valid padding at position 3"); assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2"); @@ -209,10 +209,10 @@ test("Read blob from stone blob", function() { for (var i = 0; i < 16; i++) { b1.write_bit(i % 3 === 0); } - b1.stone(); + stone(b1); var b2 = b1.read_blob(4, 12); // Read bits 4-11 (8 bits) - b2.stone(); // Need to stone the read blob before reading from it + stone(b2); // Need to stone the read blob before reading from it assertEqual(b2.length, 8, "Read blob should have 8 bits"); // Check the pattern @@ -224,7 +224,7 @@ test("Read blob from stone blob", function() { test("Stone blob is immutable", function() { var b = new Blob(); b.write_bit(true); - b.stone(); + stone(b); var threw = false; try { @@ -235,13 +235,18 @@ test("Stone blob is immutable", function() { assert(threw, "Writing to stone blob should throw error"); }); -// Test 15: Multiple stone calls -test("Multiple stone calls are safe", function() { +// Test 15: Multiple stone calls and stone.p check +test("Multiple stone calls are safe and stone.p works", function() { var b = new Blob(); b.write_bit(true); - b.stone(); - b.stone(); // Should be safe to call again + assert(!stone.p(b), "Blob should not be a stone before stone() call"); + stone(b); + assert(stone.p(b), "Blob should be a stone after stone() call"); + stone(b); // Should be safe to call again assertEqual(b.read_logical(0), true, "Blob data should remain intact"); + + // Verify blob.stone is not available + assert(b.stone === undefined, "blob.stone should not be available as a method"); }); // Test 16: Invalid constructor arguments @@ -282,11 +287,11 @@ test("Complex data round-trip", function() { b.write_number(-999.999); var originalLength = b.length; - b.stone(); + stone(b); // Verify we can create a copy var b2 = new Blob(b); - b2.stone(); // Need to stone the copy before reading + stone(b2); // Need to stone the copy before reading assertEqual(b2.length, originalLength, "Copy should have same length"); assertEqual(b2.read_text(0), "Test", "First text should match"); }); @@ -310,7 +315,7 @@ test("Large blob handling", function() { } assertEqual(b.length, testSize, "Should have " + testSize + " bits"); - b.stone(); + stone(b); // Verify pattern assertEqual(b.read_logical(0), true, "Bit 0 should be true"); @@ -372,7 +377,7 @@ test("Non-stone blob read methods should throw", function() { test("Empty text write and read", function() { var b = new Blob(); b.write_text(""); - b.stone(); + stone(b); assertEqual(b.read_text(0), "", "Empty string should round-trip"); }); @@ -380,7 +385,7 @@ test("Empty text write and read", function() { test("Invalid read positions", function() { var b = new Blob(); b.write_number(42); - b.stone(); + stone(b); var threw = false; try {