From f44fb502bea3925358016dab65ee5f691da5e7a0 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 10 Feb 2026 17:02:22 -0600 Subject: [PATCH] string literal error --- fd.c | 12 ++++-- internal/engine.cm | 1 + internal/engine.mach | Bin 22596 -> 22693 bytes source/runtime.c | 11 ++++-- vm_suite.ce | 89 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 7 deletions(-) diff --git a/fd.c b/fd.c index a8a48915..252610f3 100644 --- a/fd.c +++ b/fd.c @@ -668,17 +668,21 @@ JSC_CCALL(fd_realpath, #ifdef _WIN32 char resolved[PATH_MAX]; DWORD len = GetFullPathNameA(path, PATH_MAX, resolved, NULL); - JS_FreeCString(js, path); if (len == 0 || len >= PATH_MAX) { - return JS_ThrowInternalError(js, "realpath failed for %s: %s", path, strerror(errno)); + JSValue err = JS_ThrowInternalError(js, "realpath failed for %s: %s", path, strerror(errno)); + JS_FreeCString(js, path); + return err; } + JS_FreeCString(js, path); return JS_NewString(js, resolved); #else char *resolved = realpath(path, NULL); - JS_FreeCString(js, path); if (!resolved) { - return JS_ThrowInternalError(js, "realpath failed for %s: %s", path, strerror(errno)); + JSValue err = JS_ThrowInternalError(js, "realpath failed for %s: %s", path, strerror(errno)); + JS_FreeCString(js, path); + return err; } + JS_FreeCString(js, path); JSValue result = JS_NewString(js, resolved); free(resolved); return result; diff --git a/internal/engine.cm b/internal/engine.cm index 0c6fd3b1..011fdbbc 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -818,6 +818,7 @@ function enet_check() actor_mod.setname(_cell.args.program) var prog = _cell.args.program +if (ends_with(prog, '.ce')) prog = text(prog, 0, -3) var package = use_core('package') diff --git a/internal/engine.mach b/internal/engine.mach index 774ef07b1b7ef1f182142b0ec96ab555a9bd4ce7..3ec759ecba7c77442ea719aeb236c4b65ce1631c 100644 GIT binary patch delta 1064 zcmZ|O(M}UV6b9gb_H>H^QbCBeO%VjOR4IvukSGEY6fj#eyGvW3D3%6=f(eOSc-L3Z z>@$#f;e`a_6Zl$2|7q)X!Fcg?&(5ARb9Q$6^P4(3Ri9F7`!qceOACN}ZP$wNdc6Db z*y>_%RIMFU-v#rrV^u%<9y^IOvasDe;1!Y6mdfflMs=wk+^$ zGfycyqXAt+d?~Lj2e1lY%^+-l2{W!*AJQ(ex|=l_*dE8U+OQpstYdSnO~hTti)$|2 zaLpvz{kNEn6e{iHLM!>dxxH-q66|sw`I5pd{}r(I8g{XSoNp=H^GyR=CP#V7#J;U9 zOnEt+-Ru4mYfOucX-Uvf#5m&#nxY4x8RpH%jnE^;#$%4p%2hm(IQ5@1Cs!~hcS7^h zg#}5sjlN)zZCYgUB8#Jzqz}&|)i%QG-KJ&cE;Bc3B{)iqC09kTDm_h(C^*vHa`rXR z_qqf{P2PWyyTm7OfWWMQ3c)?;PTBpF6VIxk2M{`jECX#`5G0e#OEcs-Y`F* zvJ7CIy>7_mwn1KvRK#t@IhqP>af2bO&D9;sg_1Rw%N_LB-dddRvA+)Z-46$O*baGEjQ5NU zEBL&U3DT22!H05x(v$n#ylHwG;-42PICYZ2kFqygWm8oyu)|&3;pc3*$?HT@O?pvd LQ#I~Dl$qrZoxzh* delta 886 zcmZ|O&u$V?6bA5bdKj9bZ2{Zb(ttFrmJ+QCV~tu=B0-W4$-PjZomN_?4Io{Z=$=?2pliq~!!VNyP<7|i%yO@>s5CMv0#hYnRtk8ej04kB$XF&& zIYd}nm9Wy=&~=0hN}GBCW|eu`@M^GhoI-`;RobT-$7^zP;QsjP5=Vo3J&+mC0-vr#z-`7^y6-#W zWD^O->pq)TW^)dkS8Q_=t|Q*m*dT@`chi&=&pn*5?Rvw)pmVle9WK_9MN0jn%epSd zx{~zu*w^DX(PMs(8~g1o-+MnQCi?tXTo;TloX?G1Ov_zf*h9*XIX@fkcTc(aDJN?2 ac3OOGW4HL+8fnXQw7GbjCk^7i3cmn6GJ13X diff --git a/source/runtime.c b/source/runtime.c index 708bcf0f..efca93e0 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -8255,12 +8255,17 @@ static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc, if (!result) { FMT_CLEANUP(); return JS_EXCEPTION; } res_ref.val = JS_MKPTR (result); } else { - JSValue orig = js_sub_string_val (ctx, text_ref.val, brace_start, brace_end + 1); - if (JS_IsException (orig)) { FMT_CLEANUP(); return JS_EXCEPTION; } + /* No substitution — treat the '{' as a literal character and rescan + from brace_start + 1 so that real placeholders like {0} inside + the skipped range are still found. */ + JSValue ch = js_sub_string_val (ctx, text_ref.val, brace_start, brace_start + 1); + if (JS_IsException (ch)) { FMT_CLEANUP(); return JS_EXCEPTION; } result = (JSText *)chase (res_ref.val); - result = pretext_concat_value (ctx, result, orig); + result = pretext_concat_value (ctx, result, ch); if (!result) { FMT_CLEANUP(); return JS_EXCEPTION; } res_ref.val = JS_MKPTR (result); + pos = brace_start + 1; + continue; } pos = brace_end + 1; diff --git a/vm_suite.ce b/vm_suite.ce index 9a9a2eeb..09a42edf 100644 --- a/vm_suite.ce +++ b/vm_suite.ce @@ -738,6 +738,95 @@ run("disruption re-raise", function() { if (!outer_caught) fail("disruption re-raise failed") }) +run("disruption handler reads outer vars", function() { + var msg = "hello" + var result = null + var fn = function() { + disrupt + } disruption { + result = msg + } + fn() + if (result != "hello") fail("handler could not read outer var") +}) + +run("disruption handler modifies outer vars", function() { + var count = 0 + var name = "before" + var fn = function() { + count = count + 1 + disrupt + } disruption { + count = count + 10 + name = "after" + } + fn() + if (count != 11) fail("expected 11 got " + text(count)) + if (name != "after") fail("expected 'after' got " + name) +}) + +run("disruption handler reads function locals", function() { + var result = null + var fn = function() { + var local_val = 42 + var inner = function() { + disrupt + } disruption { + result = local_val + } + inner() + } + fn() + if (result != 42) fail("handler could not read local, got " + text(result)) +}) + +run("disruption handler with closure", function() { + var results = [] + var make_fn = function(tag) { + return function() { + disrupt + } disruption { + results[] = tag + } + } + var fn_a = make_fn("a") + var fn_b = make_fn("b") + fn_a() + fn_b() + if (length(results) != 2) fail("expected 2 results") + if (results[0] != "a") fail("first closure tag wrong") + if (results[1] != "b") fail("second closure tag wrong") +}) + +run("disruption handler modifies loop state", function() { + var total = 0 + var i = 0 + var fn = null + while (i < 3) { + fn = function() { + disrupt + } disruption { + total = total + i + } + fn() + i = i + 1 + } + if (total != 3) fail("expected 3 got " + text(total)) +}) + +run("disruption handler accesses object from outer scope", function() { + var obj = {x: 1, y: 2} + var fn = function() { + obj.x = 10 + disrupt + } disruption { + obj.y = 20 + } + fn() + if (obj.x != 10) fail("body mutation lost, x=" + text(obj.x)) + if (obj.y != 20) fail("handler mutation lost, y=" + text(obj.y)) +}) + // ============================================================================ // TYPE CHECKING WITH is_* FUNCTIONS // ============================================================================