From 384a6c1cd2936d0ad5cffb49f609857432298d1e Mon Sep 17 00:00:00 2001 From: rajames Date: Mon, 5 Oct 2026 11:31:32 -0400 Subject: [PATCH] feat(v4.0.0): logging, as v3 - capsule/log.v4: the level constants LOG-ERROR .. LOG-DEBUG, LOG-LEVEL! and LOG-LEVEL@, LOG-ERROR" .. LOG-DEBUG" and LOG-ERROR-STR .. LOG-DEBUG-STR. A message is printed if its level is at or below LOG-LEVEL, as v3's line -- colour, level, text -- without the time of day, which a node has not got. - LOG-xxx" compiles like ." : the level, a call to (LOG"), the text. SEE shows it as text. COLD puts LOG-LEVEL back to LOG-INFO. - tests/test_host_quit.c: ten transcripts of the v3 binary, every level at every setting. Co-Authored-By: Claude Opus 5.5 --- docs/v4.0.0/DECOMPOSITION.md | 22 ++++++++--- v4/capsule/log.v4 | 72 ++++++++++++++++++++++++++++++++++++ v4/capsule/system.v4 | 2 +- v4/capsule/tools.fth | 3 +- v4/tests/host_map.h | 2 + v4/tests/test_host_quit.c | 41 ++++++++++++++++++-- 6 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 v4/capsule/log.v4 diff --git a/docs/v4.0.0/DECOMPOSITION.md b/docs/v4.0.0/DECOMPOSITION.md index bd852f4d..55bd9361 100644 --- a/docs/v4.0.0/DECOMPOSITION.md +++ b/docs/v4.0.0/DECOMPOSITION.md @@ -760,7 +760,7 @@ call would bury what it works on. A **compile-only** word may not be executed by `v4/capsule/forth.v4` holds the first words of the vocabulary flagged this way (`DUP`, `+`, `>R`, `I`, `LEAVE`, `@`, the in-line variables and so on). -**The vocabulary at the prompt.** The host node's capsule is `v4/capsule/`, loaded in this order: `core.v4` (bytes, console, strings the rest rest on), `input.v4`, `dict.v4`, `codegen.v4`, `compile.v4`, `quit.v4` (the prompt, faults and errors), `forth.v4` (stack, arithmetic, division, `DEPTH` `PICK` `ROLL`), `numout.v4` (number output, `.S`), `system.v4` (vocabularies, `WORDS`, `FORGET`, `COLD`, `DEFER`), then the two files of FORTH source the node compiles itself, `editor.fth` and `tools.fth` (`SEE`); `blocks.v4` (mass storage and `LOAD`), `qmath.v4` (the Q48.16 words of §5.26: `Q.FROM-INT Q.TO-INT Q.1 Q.0 Q.SCALE Q.+ Q.- Q.* Q./ Q.ABS Q.NEG Q.= Q.< Q.> Q.0= Q.MAX Q.MIN Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS Q.PRINT`; `DUMP` is in `numout.v4`) and `words.v4` (the stack, comparison, shift, double, mixed and string words of §5.1–5.9: `2SWAP 2OVER 2ROT 2>R 2R> 2R@ 2@ 2! -! 0<> 0> <> <= >= U< U> ABS MAX MIN WITHIN LSHIFT RSHIFT D- DABS D0= D0< D= D2* D2/ D< DMAX DMIN M+ M- CMOVE> MOVE FILL ERASE BLANK -TRAILING COMPARE SEARCH SCAN SKIP ?TERMINAL TRUE FALSE INVERT NOP`). Each is the definition this document gives; `tests/test_host_quit.c` runs them from the prompt against transcripts of the v3 binary. From the prompt, 122 results of the Q words printed by `Q.PRINT` — which shows all sixteen bits of a fraction — are digit for digit v3's, at both cell widths. Under D-18, `Q./` by zero and `Q.SQRT` and `Q.LOG` outside their domain leave the result D-11 and D-12 give and then raise an error (codes 11 `Division by zero` and 12 `Argument out of range`); v3 returns 0 and says nothing. As v3, `LSHIFT` and `RSHIFT` with a count that is negative or as large as the cell is wide are an error (D-18, code 9, `Shift count out of range`). `M+`, like `M-` and `M/MOD`, takes its double in the standard order, low cell first; v3 takes it low cell on top. +**The vocabulary at the prompt.** The host node's capsule is `v4/capsule/`, loaded in this order: `core.v4` (bytes, console, strings the rest rest on), `input.v4`, `dict.v4`, `codegen.v4`, `compile.v4`, `quit.v4` (the prompt, faults and errors), `forth.v4` (stack, arithmetic, division, `DEPTH` `PICK` `ROLL`), `numout.v4` (number output, `.S`), `system.v4` (vocabularies, `WORDS`, `FORGET`, `COLD`, `DEFER`), then the two files of FORTH source the node compiles itself, `editor.fth` and `tools.fth` (`SEE`); `blocks.v4` (mass storage and `LOAD`), `log.v4` (logging), `qmath.v4` (the Q48.16 words of §5.26: `Q.FROM-INT Q.TO-INT Q.1 Q.0 Q.SCALE Q.+ Q.- Q.* Q./ Q.ABS Q.NEG Q.= Q.< Q.> Q.0= Q.MAX Q.MIN Q.EXP Q.SQRT Q.LOG Q.SIN Q.COS Q.PRINT`; `DUMP` is in `numout.v4`) and `words.v4` (the stack, comparison, shift, double, mixed and string words of §5.1–5.9: `2SWAP 2OVER 2ROT 2>R 2R> 2R@ 2@ 2! -! 0<> 0> <> <= >= U< U> ABS MAX MIN WITHIN LSHIFT RSHIFT D- DABS D0= D0< D= D2* D2/ D< DMAX DMIN M+ M- CMOVE> MOVE FILL ERASE BLANK -TRAILING COMPARE SEARCH SCAN SKIP ?TERMINAL TRUE FALSE INVERT NOP`). Each is the definition this document gives; `tests/test_host_quit.c` runs them from the prompt against transcripts of the v3 binary. From the prompt, 122 results of the Q words printed by `Q.PRINT` — which shows all sixteen bits of a fraction — are digit for digit v3's, at both cell widths. Under D-18, `Q./` by zero and `Q.SQRT` and `Q.LOG` outside their domain leave the result D-11 and D-12 give and then raise an error (codes 11 `Division by zero` and 12 `Argument out of range`); v3 returns 0 and says nothing. As v3, `LSHIFT` and `RSHIFT` with a count that is negative or as large as the cell is wide are an error (D-18, code 9, `Shift count out of range`). `M+`, like `M-` and `M/MOD`, takes its double in the standard order, low cell first; v3 takes it low cell on top. **The stacks and the compiler.** The interpreter and compiler run on the same stacks as the user's words, with the user's values beneath them. The capsule was written for stacks of ten cells and nine @@ -914,15 +914,25 @@ index should use them; they cost one instruction per iteration. ### 5.25 Logging +A message has a level, and is printed if its level is at or below `LOG-LEVEL`. Source in +`v4/capsule/log.v4`; executed on the golden model's host node (2026-10-05) against transcripts of the v3 +binary. + | Word | Fate | Notes | | --- | --- | --- | -| `LOG-ERROR` … `LOG-DEBUG` (levels) | IN | Constants. | -| `LOG-LEVEL!` `LOG-LEVEL@` | CAP | Variable. | -| `LOG-ERROR"` … `LOG-DEBUG"` | CC | | -| `LOG-*-STR` | DEV | Log-ring service on the recorder (the ARM). | -| `(do-log-*)` | CC | | +| `LOG-ERROR` … `LOG-DEBUG` (levels) | IN | Constants, as v3: `LOG-ERROR` 0, `LOG-WARN` 1, `LOG-INFO` 2, `LOG-TEST` 3, `LOG-DEBUG` 4. | +| `LOG-LEVEL!` `LOG-LEVEL@` | CAP | A variable, 2 (`LOG-INFO`) at switch-on and after `COLD`. As v3, `LOG-LEVEL!` takes a level below 0 as 0 and one above 4 as 4. | +| `LOG-ERROR"` … `LOG-DEBUG"` | CC | `LOG-xxx" text"` logs the text now, if interpreting, or when the word it is compiled into runs. Compiled as `."` is: the level as a literal, a call to `(LOG")`, and the text after it. | +| `LOG-*-STR` | DEV | `( baddr u -- )`: log a string at that level. On the mesh this is the log-ring service on the recorder (the ARM); until then it goes to the console. | +| `(LOG")` | CC | The run-time word of `LOG-xxx"`, compile-only. It stands for v3's five `(do-log-*)`. | | `(LOG-APPEND-RAW)` | DEV | | +**What is printed** is v3's line without its time of day, which a node has not got: the level's colour, its +name and a colon, the colour off, the text, a new line — `ESC[32mINFO: ESC[0mtext` — with red for `ERROR`, +yellow `WARN`, green `INFO`, magenta `TEST`, blue `DEBUG`. v3's `LOG-DEBUG` level also turns on the +interpreter's own trace of every word; v4 has no such trace. A string logged with a negative length is +D-18's `Negative count` when its level is shown, and is ignored when it is not. + ### 5.26 Q48.16 fixed-point math A Q48.16 value is 64 bits, so on a 32-bit node it occupies **two cells** and every Q word is a double diff --git a/v4/capsule/log.v4 b/v4/capsule/log.v4 new file mode 100644 index 00000000..56f5b986 --- /dev/null +++ b/v4/capsule/log.v4 @@ -0,0 +1,72 @@ +\ log.v4 -- logging, as v3: a message has a level, and is printed if the +\ level is at or below LOG-LEVEL. +\ +\ DECOMPOSITION.md 5.25: the level constants LOG-ERROR LOG-WARN LOG-INFO +\ LOG-TEST LOG-DEBUG (0 .. 4), LOG-LEVEL! LOG-LEVEL@, LOG-ERROR" ... LOG-DEBUG" +\ and LOG-ERROR-STR ... LOG-DEBUG-STR. Part of the compiler capsule; rests +\ on core.v4, codegen.v4 and quit.v4. +\ +\ WHAT IS PRINTED is v3's line without its time of day, which a node has +\ not got: the level's colour, the level's name and a colon, the colour off, +\ the text, a new line -- +\ ESC [32m INFO: ESC [0m text +\ On the mesh a message will go to the recorder's log ring (5.25); until +\ then it goes to the console. +\ +\ Constants the loader supplies: +\ (LOG-LEVEL) word address of the variable: 2, LOG-INFO, at switch-on + +header LOG-ERROR inline : LOG-ERROR 0 ; +header LOG-WARN inline : LOG-WARN 1 ; +header LOG-INFO inline : LOG-INFO 2 ; +header LOG-TEST inline : LOG-TEST 3 ; +header LOG-DEBUG inline : LOG-DEBUG 4 ; + +header LOG-LEVEL@ +: LOG-LEVEL@ ( -- n ) (LOG-LEVEL) a! @ ; +\ ( n -- ) as v3: a level below 0 is 0, one above 4 is 4 +header LOG-LEVEL! +: LOG-LEVEL! + -if POS drop 0 jump SET + POS: dup -5 + -if BIG drop jump SET + BIG: drop drop 4 + SET: (LOG-LEVEL) a! ! ; + +\ ( baddr u level -- ) the message, if the level is at or below LOG-LEVEL +: (LOG) + dup inv (LOG-LEVEL) a! @ + 1 + -if SHOW drop drop drop drop ; \ LOG-LEVEL - level + SHOW: drop + if P0 -1 + if P1 -1 + if P2 -1 + if P3 -1 + if P4 + drop jump OUT + P0: drop $31335B1B (EMIT4) $6D (EMIT4) $4F525245 (EMIT4) $203A52 (EMIT4) $6D305B1B (EMIT4) jump OUT + P1: drop $33335B1B (EMIT4) $6D (EMIT4) $4E524157 (EMIT4) $203A (EMIT4) $6D305B1B (EMIT4) jump OUT + P2: drop $32335B1B (EMIT4) $6D (EMIT4) $4F464E49 (EMIT4) $203A (EMIT4) $6D305B1B (EMIT4) jump OUT + P3: drop $35335B1B (EMIT4) $6D (EMIT4) $54534554 (EMIT4) $203A (EMIT4) $6D305B1B (EMIT4) jump OUT + P4: drop $34335B1B (EMIT4) $6D (EMIT4) $55424544 (EMIT4) $203A47 (EMIT4) $6D305B1B (EMIT4) jump OUT + OUT: TYPE jump CR + +header LOG-ERROR-STR : LOG-ERROR-STR ( baddr u -- ) 0 jump (LOG) +header LOG-WARN-STR : LOG-WARN-STR ( baddr u -- ) 1 jump (LOG) +header LOG-INFO-STR : LOG-INFO-STR ( baddr u -- ) 2 jump (LOG) +header LOG-TEST-STR : LOG-TEST-STR ( baddr u -- ) 3 jump (LOG) +header LOG-DEBUG-STR : LOG-DEBUG-STR ( baddr u -- ) 4 jump (LOG) + +\ ( level -- ) the run time of LOG-xxx" : the text is after the call, as +\ for ." ; log it at that level and go on after it. +header (LOG") compile-only +: (LOG") + pop 4* dup C@ over + 4/ 1 + push \ level baddr R: the cell after the text + COUNT ROT jump (LOG) + +\ ( level -- ) LOG-xxx" text" logs the text -- now, if interpreting; when +\ the word it is compiled into runs, if compiling. (Q)+3 holds the level. +: (LOG-QUOTE) + (Q)+3 a! ! 34 (PARSE) drop + STATE a! @ if NOW + drop (Q)+3 a! @ (LIT,) &(LOG") (CALL,) jump (STRING,) + NOW: drop WBUF COUNT (Q)+3 a! @ jump (LOG) +header LOG-ERROR" immediate : LOG-ERROR-QUOTE 0 jump (LOG-QUOTE) +header LOG-WARN" immediate : LOG-WARN-QUOTE 1 jump (LOG-QUOTE) +header LOG-INFO" immediate : LOG-INFO-QUOTE 2 jump (LOG-QUOTE) +header LOG-TEST" immediate : LOG-TEST-QUOTE 3 jump (LOG-QUOTE) +header LOG-DEBUG" immediate : LOG-DEBUG-QUOTE 4 jump (LOG-QUOTE) diff --git a/v4/capsule/system.v4 b/v4/capsule/system.v4 index e890213e..49320937 100644 --- a/v4/capsule/system.v4 +++ b/v4/capsule/system.v4 @@ -141,7 +141,7 @@ header COLD (BOOT)+1 a! @ (LATEST) a! ! (BOOT) a! @ 2/ 2/ FENCE a! ! (LATEST) CONTEXT a! ! (LATEST) CURRENT a! ! 0 VOC-LINK a! ! - 10 BASE a! ! 0 SCR a! ! EMPTY-BUFFERS + 10 BASE a! ! 0 SCR a! ! 2 (LOG-LEVEL) a! ! EMPTY-BUFFERS $54524F46 (EMIT4) $39372D48 (EMIT4) $6C6F4320 (EMIT4) $74532064 (EMIT4) $747261 (EMIT4) CR $74737953 (EMIT4) $69206D65 (EMIT4) $6974696E (EMIT4) $7A696C61 (EMIT4) $2E6465 (EMIT4) CR jump ABORT diff --git a/v4/capsule/tools.fth b/v4/capsule/tools.fth index 9578ef36..a987ce0d 100644 --- a/v4/capsule/tools.fth +++ b/v4/capsule/tools.fth @@ -46,7 +46,8 @@ VARIABLE (SN) \ how many lines \ ( addr -- ) after a call to addr: if it is one of the words that are \ followed by text, show the text and count its cells with the literals : (TEXT?) - DUP ['] (.") = OVER ['] (ABORT") = OR SWAP ['] (S") = OR IF + DUP ['] (.") = OVER ['] (ABORT") = OR OVER ['] (LOG") = OR + SWAP ['] (S") = OR IF (SP) @ (SLITS) @ + 4 * COUNT 34 EMIT 2DUP TYPE 34 EMIT SPACE SWAP DROP 4 + 4 / (SLITS) +! THEN ; diff --git a/v4/tests/host_map.h b/v4/tests/host_map.h index 3bf3a72b..f316589c 100644 --- a/v4/tests/host_map.h +++ b/v4/tests/host_map.h @@ -64,6 +64,7 @@ #define SRC (BVARS + 8) #define SRC_HOOK (BVARS + 9) #define STORAGE_REG (BVARS + 10) +#define LOG_LEVEL (BUF0_W - 5) /* the level at or below which a message is printed */ #define BOOT_CELLS (BVARS + 14) /* (BOOT): DP and LATEST as the loader left them, 2 cells */ #define BUF0_W (BVARS - 2 * 256) /* the two block buffers, 256 cells each */ #define BUF1_W (BUF0_W + 256) @@ -130,6 +131,7 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned v4_text_constant(tx, "(X)", XVARS); v4_text_constant(tx, "(B)", BVARS); v4_text_constant(tx, "(BOOT)", BOOT_CELLS); + v4_text_constant(tx, "(LOG-LEVEL)", LOG_LEVEL); v4_text_constant(tx, "SCR", SCR); v4_text_constant(tx, "BLK", BLK); v4_text_constant(tx, "(SRC)", SRC); diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index ab396fa5..834a1cb4 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -101,6 +101,7 @@ static void boot_with(unsigned depth) n.mem[BOOT_CELLS] = n.mem[DP]; n.mem[BOOT_CELLS + 1] = capsule_latest; n.mem[FENCE] = DICT_W; + n.mem[LOG_LEVEL] = 2; n.mem[CONTEXT] = LATEST; n.mem[CURRENT] = LATEST; n.mem[VOC_LINK] = 0; @@ -380,6 +381,36 @@ static const transcript script[] = { { "Q.0 Q.LOG 65 EMIT\n-1 Q.FROM-INT Q.LOG\n", "Argument out of range\n ERROR\nok> Argument out of range\n ERROR\nok> ", 0 }, { "7 PAD -1 DUMP 65 EMIT\n.S\n", "Negative count\n ERROR\nok> <1> 7 \n ok\nok> ", 0 }, { "PAD 0 DUMP\n", " ok\nok> ", 1 }, + /* log.v4: v3's lines, colours and all, without its time of day */ + { "LOG-LEVEL@ . LOG-ERROR . LOG-WARN . LOG-INFO . LOG-TEST . LOG-DEBUG .\n", + "2 0 1 2 3 4 ok\nok> ", 1 }, + { "LOG-INFO\" hello info\"\nLOG-WARN\" careful\"\nLOG-ERROR\" bad\"\nLOG-DEBUG\" dbg\"\nLOG-TEST\" tst\"\n", + "\033[32mINFO: \033[0mhello info\n ok\nok> \033[33mWARN: \033[0mcareful\n ok\nok> \033[31mERROR: \033[0mbad\n ok\nok> ok\nok> ok\nok> ", 1 }, + { ": T LOG-INFO\" from a word\" 65 EMIT ; T\n", + "\033[32mINFO: \033[0mfrom a word\nA ok\nok> ", 1 }, + { "S\" a string\" LOG-INFO-STR\nS\" w\" LOG-WARN-STR S\" e\" LOG-ERROR-STR\nS\" d\" LOG-DEBUG-STR S\" t\" LOG-TEST-STR\n", + "\033[32mINFO: \033[0ma string\n ok\nok> \033[33mWARN: \033[0mw\n\033[31mERROR: \033[0me\n ok\nok> ok\nok> ", 1 }, + { "0 LOG-LEVEL! LOG-LEVEL@ . LOG-ERROR\" e0\" LOG-WARN\" w0\"\n", + /* v3 prints the 0 after the message: its log goes to stderr at once and its numbers to stdout when the line ends */ + "0 \033[31mERROR: \033[0me0\n ok\nok> ", 0 }, + { "99 LOG-LEVEL! LOG-LEVEL@ . 4 LOG-LEVEL! LOG-DEBUG\" d\" 5 LOG-LEVEL! LOG-LEVEL@ .\n", "4 \033[34mDEBUG: \033[0md\n4 ok\nok> ", 0 }, + { "7 S\" abc\" LOG-DEBUG-STR 8 PAD -1 LOG-DEBUG-STR .S\n", "<2> 7 8 \n ok\nok> ", 0 }, + { "7 PAD -1 LOG-ERROR-STR 65 EMIT\n.S\n", "\033[31mERROR: \033[0mNegative count\n ERROR\nok> <1> 7 \n ok\nok> ", 0 }, + { "LOG-WARN\" no closing quote\n", "\033[33mWARN: \033[0mno closing quote\n ok\nok> ", 0 }, + { ": L3 LOG-INFO\" abcd\" 65 EMIT LOG-DEBUG\" hidden\" 66 EMIT ; L3 .S\n", "\033[32mINFO: \033[0mabcd\nAB<0> \n ok\nok> ", 0 }, + { "(LOG\")\n", "(LOG\"): compile-only\n ERROR\nok> ", 0 }, + { "1 LOG-LEVEL! LOG-ERROR\" e1\" LOG-WARN\" w1\" LOG-INFO\" i1\"\n", + "\033[31mERROR: \033[0me1\n\033[33mWARN: \033[0mw1\n ok\nok> ", 1 }, + { "2 LOG-LEVEL! LOG-ERROR\" e2\" LOG-WARN\" w2\" LOG-INFO\" i2\" LOG-TEST\" t2\"\n", + "\033[31mERROR: \033[0me2\n\033[33mWARN: \033[0mw2\n\033[32mINFO: \033[0mi2\n ok\nok> ", 1 }, + { "3 LOG-LEVEL! LOG-INFO\" i3\" LOG-TEST\" t3\" LOG-DEBUG\" d3\"\n", + "\033[32mINFO: \033[0mi3\n\033[35mTEST: \033[0mt3\n ok\nok> ", 1 }, + { "-1 LOG-LEVEL! LOG-LEVEL@ .\n", + "0 ok\nok> ", 1 }, + { "LOG-INFO\" \"\n", + "\033[32mINFO: \033[0m\n ok\nok> ", 1 }, + { ": W LOG-ERROR\" e\" LOG-WARN\" w\" LOG-TEST\" t\" ; W 3 LOG-LEVEL! W\n", + "\033[31mERROR: \033[0me\n\033[33mWARN: \033[0mw\n\033[31mERROR: \033[0me\n\033[33mWARN: \033[0mw\n\033[35mTEST: \033[0mt\n ok\nok> ", 1 }, /* blocks.v4 */ { "20 BLOCK 1024 BLANK 65 20 BLOCK C! UPDATE SAVE-BUFFERS 20 BLOCK C@ .\n", "65 ok\nok> ", 1 }, @@ -547,8 +578,8 @@ int main(void) printf("v4 host prompt tests: V4_CELL_BITS=%d, V4_NODE_WORDS=%u\n", V4_CELL_BITS, (unsigned)V4_NODE_WORDS); { - static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4", "numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4" }; - CHECK(host_load(&tx, &n, files, 12), "the capsule assembles"); + static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4", "numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4", "log.v4" }; + CHECK(host_load(&tx, &n, files, 13), "the capsule assembles"); } CHECK(v4_text_finish(&tx), "everything is defined: %s", v4_text_error(&tx)); CHECK(v4_text_here(&tx) < DICT_W, "code stays below the dictionary space"); @@ -1065,6 +1096,7 @@ int main(void) } CHECK(is(say(": S4 .\" abcd\" 65 EMIT ; SEE S4\n"), ": S4\n call (.\") \"abcd\" \n @p 65 call EMIT \n ; \n ok\nok> "), "text that fills its last cell but for the count"); CHECK(is(say("SEE *\n"), out) && strstr(out, " +* unext drop drop a ; \n"), "the longest opcode name, in the capsule's multiply"); + CHECK(is(say(": LG LOG-WARN\" look\" 65 EMIT ; SEE LG\n"), ": LG\n @p 1 call (LOG\") \"look\" \n @p 65 call EMIT \n ; \n ok\nok> "), "a logged message is shown as text, after its level"); CHECK(is(say("SEE NOSUCH\n"), "SEE: not found\n ok\nok> ") && is(say("SEE\n"), "SEE: not found\n ok\nok> "), "a word that is not there"); CHECK(is(say("(.\")\n"), "(.\"): compile-only\n ERROR\nok> ") && is(say("(S\")\n"), "(S\"): compile-only\n ERROR\nok> "), "the string run-time words have names but cannot be run from the prompt"); @@ -1080,10 +1112,11 @@ int main(void) CHECK(is(say(": KEEPME 1 ; 1 2 3 WARM 65 EMIT\n.S KEEPME .\n"), "FORTH-79 Warm Start\nSystem restarted.\n ok\nok> <0> \n1 ok\nok> "), "WARM empties the stacks and keeps the dictionary"); { v4_cell dp = n.mem[BOOT_CELLS]; - CHECK(is(say("VOCABULARY VV VV DEFINITIONS : INVV 1 ; HEX 20 BLOCK DROP UPDATE 5 SCR !\n"), " ok\nok> "), "a vocabulary, a base, a block, a screen"); + CHECK(is(say("VOCABULARY VV VV DEFINITIONS : INVV 1 ; HEX 20 BLOCK DROP UPDATE 5 SCR !\n"), " ok\nok> ") + && is(say("4 LOG-LEVEL!\n"), " ok\nok> "), "a vocabulary, a base, a block, a screen, a log level"); CHECK(is(say("1 2 COLD 65 EMIT\n"), "FORTH-79 Cold Start\nSystem initialized.\n ok\nok> "), "COLD says so"); CHECK(n.mem[DP] == dp && n.mem[LATEST] == capsule_latest && n.mem[CONTEXT] == LATEST && n.mem[CURRENT] == LATEST && n.mem[VOC_LINK] == 0 - && n.mem[BASE] == 10 && n.mem[SCR] == 0 && n.mem[BVARS] == 0 && n.mem[FENCE] == dp / 4, "and everything is as the loader left it"); + && n.mem[BASE] == 10 && n.mem[SCR] == 0 && n.mem[BVARS] == 0 && n.mem[FENCE] == dp / 4 && n.mem[LOG_LEVEL] == 2, "and everything is as the loader left it"); CHECK(is(say("KEEPME\n"), "UNKNOWN WORD: 'KEEPME'\n ERROR\nok> ") && is(say("VV\n"), "UNKNOWN WORD: 'VV'\n ERROR\nok> ") && is(say(".S : NEW 16 . ; NEW\n"), "<0> \n16 ok\nok> "), "what was defined is gone, and the system works"); }