diff --git a/capsules/v4/sys/quit.f18 b/capsules/v4/sys/quit.f18 index 4a764bc5..b1512d54 100644 --- a/capsules/v4/sys/quit.f18 +++ b/capsules/v4/sys/quit.f18 @@ -84,10 +84,20 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro \ there is one, is given the number of the node that is gone, in (ONE), so \ that the GONE goes on down the birth graph (MESH.md 9a.2, ruling 7; \ capsules/v4/centre.4th, GONE-DOWN). 0 there, as at switch-on: nothing. -\ As (DEFINED) does (dict.f18): the xt goes on the return stack and ; -\ goes there, so the word returns to whoever called this. +\ The word is called, not jumped to, and (ONE) is put back when it +\ returns: what called this -- AWAIT, with the node it waits on -- reads +\ (ONE) after, and a GONE the word sends writes it. (Found by the depth +\ sweep of MESH.md 9a.6: a word that handed on a GONE about another node +\ left AWAIT waiting for ever.) + +\ ( n xt -- ) the word whose xt it is, given n. It returns to whoever +\ called this, as (DEFINED) does (dict.f18). +: (RUN) push ; + : (DOWN) - (GONE-HOOK) b! @b if NONE (ONE) a! @ SWAP push ; + (GONE-HOOK) b! @b if NONE + drop (ONE) a! @ dup push (GONE-HOOK) b! @b (RUN) + pop (ONE) a! ! ; NONE: drop ; \ ( -- flag ) A GONE has been taken: its seven words are in (IN), the diff --git a/v4/tests/test_host_depth.c b/v4/tests/test_host_depth.c index 0771c7ac..52ee4a71 100644 --- a/v4/tests/test_host_depth.c +++ b/v4/tests/test_host_depth.c @@ -218,10 +218,10 @@ static void fill(char *text, size_t cap, unsigned count) for (bit = 8; bit; bit >>= 1) if (count >= bit) { at += (size_t)snprintf(text + at, cap - at, "P%u ", bit); count -= bit; } } -#define PATHS 10u +#define PATHS 11u static const char *const path_name[PATHS] = { "a text that prints", "SEND", "SEND with no way", "AWAIT answered", "AWAIT ended by a GONE", "passing on while its text waits for room", "AWAIT broken by a line from the console", "a refusal while its text waits for room", "GONE", - "a spent message refused while its text waits" }; + "a spent message refused while its text waits", "AWAIT ended by a GONE that is handed on" }; static char numbers[8192]; /* what 1200 0 DO I . LOOP prints */ /* A row made afresh for one path; node 11 is given the word ACT that takes it, and the words that fill the @@ -239,6 +239,7 @@ static int made(unsigned path) ": ACT 1200 0 DO I . LOOP ;", ": ACT 44 12 GONE ;", ": ACT 1200 0 DO I . LOOP ;", + ": ACT 77 AWAIT DROP ;", }; char line[64]; unsigned k; @@ -250,6 +251,11 @@ static int made(unsigned path) } if (path == 2 && !told(11, "NO-ROUTES 1 2 ROUTE 10 2 ROUTE 12 3 ROUTE")) return 0; /* no way for any node it has not been told of */ if (path == 4 && !told(12, ": LL 400000 0 DO LOOP ;")) return 0; + /* path 10: node 11 waits on a node 77 that never answers; its centre says 77 is gone, and node 11 hands the + * believed GONE on (MESH.md 9a.2, ruling 7) -- a GONE about 44 to node 12, which knows a way to 44. (Not + * about 12: believing a GONE about 12 makes node 11 forget its way to 12, and a GONE-DOWN never tells a node + * of its own going.) */ + if (path == 10 && !told(11, "VARIABLE FWD : DOWN DROP 44 12 GONE 1 FWD +! ; ' DOWN (GONE-HOOK) !")) return 0; if (path == 5 && !told(10, ": SLOW 500000 0 DO LOOP ; : BUSY SLOW S\" 1 DROP\" 12 SEND SLOW ;")) return 0; if (path == 9 && !told(10, ": SLOW 500000 0 DO LOOP ; : BUSY SLOW SLOW ;")) return 0; /* 320 characters: more than fits beside what node 11 itself is waiting to print */ @@ -280,12 +286,16 @@ static int one(unsigned path, const char *what, unsigned depth, const char *text runs++; step_cap = 60000000; if (path == 8 && !told(12, "44 2 ROUTE")) why = "node 12 did not take a way"; + if (path == 10 && !(told(11, "0 FWD !") && told(12, "44 NO-ROUTE 44 2 ROUTE"))) why = "node 11 did not clear FWD, or node 12 did not take a way to 44"; ways12 = pool[far].n.mem[ROUTE_COUNT]; forget(); saw_room_wait = 0; saw_passed = 0; clock12 = pool[far].es.anticlock; if (why) { } - else if (path == 4) { /* node 12 is busy for a long while and sends no answer; node 11 waits; its centre says 12 is gone */ + else if (path == 10) { /* node 11 waits on 77; its centre says 77 is gone */ + if (!put_text(11, text) || !run()) why = "it did not come to wait"; + else if (!put_text(10, "77 11 GONE") || !run()) why = "the nodes did not come to rest"; + } else if (path == 4) { /* node 12 is busy for a long while and sends no answer; node 11 waits; its centre says 12 is gone */ stuck = 1u << far; if (!put_text(12, "LL") || !put_text(11, text) || !run()) why = "it did not come to wait"; else if (!put_text(10, "12 11 GONE") || !run()) why = "the GONE was not done"; @@ -340,6 +350,17 @@ static int one(unsigned path, const char *what, unsigned depth, const char *text clean_error = over && is_cut_short(printed, numbers, over) && pool[far].n.mem[REFUSED] == refused12 + 1; break; /* whoever refused it, node 12 was told */ case 8: works = how11 == V4_TEXT_COMPLETED && printed_len == 0 && left == values && pool[far].n.mem[ROUTE_COUNT] == ways12 - 1; clean_error = over && strcmp(printed, over) == 0; break; + case 10: { + int down = pool[far].n.mem[ROUTE_COUNT] == ways12 - 1; /* node 12 believed the GONE node 11 handed on */ + works = how11 == V4_TEXT_ERROR && strcmp(printed, "Node gone\n") == 0 && left == values && down; + clean_error = over && strcmp(printed, over) == 0; + if (works) works = strcmp(tell(11, "FWD @ ."), "1 ") == 0; + else if (clean_error) { + int fwd1 = strcmp(tell(11, "FWD @ ."), "1 ") == 0, fwd0 = strcmp(printed, "0 ") == 0; + clean_error = down ? (fwd1 || fwd0) : fwd0; + } + break; + } case 9: works = how11 == V4_TEXT_COMPLETED && strcmp(printed, numbers) == 0 && left == values && saw_room_wait > 0 && pool[mid].n.mem[LOST] == lost11 + 1 && pool[far].n.mem[REFUSED] == refused12 + 1; clean_error = over && is_cut_short(printed, numbers, over) && pool[mid].n.mem[LOST] == lost11 + 1 && pool[far].n.mem[REFUSED] == refused12 + 1; break; /* it was dropped: its sender was told */ @@ -420,7 +441,7 @@ int main(void) first_error = 0; for (k = V4_RET_DEPTH - 18u; k <= V4_RET_DEPTH + 1u; k++) { snprintf(text, sizeof text, "N%u", k); - r = one(path, "calls deep", k, text, 0, k + ((path == 5 || path == 7 || path == 9) ? 16u : 11u) <= V4_RET_DEPTH); + r = one(path, "calls deep", k, text, 0, k + ((path == 5 || path == 7 || path == 9) ? 16u : path == 10 ? 14u : 11u) <= V4_RET_DEPTH); if (r == 0 && !first_error) first_error = k; } printf(" calls: works to %u deep; %u worked, %u clean errors, %u failures\n", first_error ? first_error - 1u : (unsigned)(V4_RET_DEPTH + 1u), worked - w0, refused_clean - e0, bad - before); diff --git a/v4/tests/test_host_mesh.c b/v4/tests/test_host_mesh.c index f2ef1a4d..a400a1de 100644 --- a/v4/tests/test_host_mesh.c +++ b/v4/tests/test_host_mesh.c @@ -1128,15 +1128,16 @@ int main(void) * (Hera's KILL does: test_host_unit.c). Its wait is ended by the line it is then typed, "Interrupted", * and it answers. */ { - static const struct { const char *what, *set10, *set11, *set12; v4_cell node; const char *text; } ex[3] = { + static const struct { const char *what, *set10, *set11, *set12; v4_cell node; const char *text; } ex[4] = { { "text from the console for node 12, what it prints and how it ended", "1 DROP", "1 DROP", ": A 7 8 * . ;", 12, "A" }, { "node 11 SENDs node 12 text and waits for its answer", "1 DROP", ": T S\" Q\" 12 SEND 12 AWAIT . ;", "1 DROP", 11, "T" }, + { "a GONE node 10 sends node 11, which node 11 hands on to node 12", ": G 44 11 GONE ;", ": DOWN 12 GONE ; ' DOWN (GONE-HOOK) ! 44 3 ROUTE", "44 2 ROUTE", 10, "G" }, { "a message node 12 has no way for, and its NACK to node 10", "55 2 ROUTE : N S\" 1 DROP\" 55 SEND ;", "55 3 ROUTE", "NO-ROUTES 1 2 ROUTE 10 2 ROUTE 11 2 ROUTE", 10, "N" } }; static const char *const how_name[4] = { "", "node 11 removed", "node 12 removed", "the wire between nodes 11 and 12 cut and made again" }; unsigned e, g, whole, tried, wrong, first, all = 0; step_cap = 2000000; - for (e = 0; e < 3; e++) { + for (e = 0; e < 4; e++) { CHECK(row() && told(10, ex[e].set10) && told(11, ex[e].set11) && told(12, ex[e].set12) && told(10, ASK) && told(11, ASK) && told(12, ASK), "a row made afresh for: %s", ex[e].what); step_cap = 2000000; keep();