feat(v4.0.0): every error is raised and ends the line (D-18)

Ruled 2026-10-04: guard all errors.  The errors that set NODE-ERROR and
let the line run on now stop it at once, with a message.

- A store of a non-zero code to NODE-ERROR is a trap, a sixth kind of
  fault: nothing after it executes, the return stack is emptied, and the
  data stack is left as the word left it.  Not attached, NODE-ERROR is
  plain memory, as the tests below the prompt use it.
- The capsule's words store a code where they stored -1, and the prompt's
  (RAISED) prints its message: Negative count, Not a number, Number too
  long, Not a character, Dictionary full, Name missing, Control structure
  mismatch, Control structures too deep.
- ' and COMPILE and [COMPILE] of a word that is not there say
  UNKNOWN WORD: 'xxx', as the interpreter does.
- tests: the trap in test_exec.c; every message from the prompt, with the
  rest of the line not run and the stack kept, in test_host_quit.c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-04 20:13:23 -04:00
co-authored by Claude Opus 5.5
parent 644bfc0a25
commit dc7e37ba5c
12 changed files with 181 additions and 38 deletions
+26 -4
View File
@@ -91,6 +91,9 @@ typedef struct {
/* DSTACK-DEPTH and RSTACK-DEPTH (D-16). See v4_node_stack_regs_attach. */
v4_cell dstack_reg; /* its word address, or -1 */
v4_cell rstack_reg; /* its word address, or -1 */
/* NODE-ERROR as a trap (D-18). See v4_node_error_attach. */
v4_cell error_reg; /* its word address, or -1 */
} v4_node;
/* Zero P, A and B, empty the stacks, and clear memory. Installs every
@@ -194,8 +197,10 @@ int v4_node_addr_ok(v4_cell addr);
* and faults is one more;
* - both stacks are emptied. The handler does not return to the
* programme, and what a word stopped in the middle of its work has left
* on the data stack is not something its caller can use;
* - P becomes fault_vector + fault_kind. The handler table is five words,
* on the data stack is not something its caller can use. (A raised
* error, below, empties only the return stack: the word that raised it
* chose to, after taking its own arguments off);
* - P becomes fault_vector + fault_kind. The handler table is six words,
* one for each kind in the order below, each a jump to that kind's
* handler (capsule/quit.v4, (FAULTS)).
* With no table attached (fault_vector -1) the node stops instead: `stopped`
@@ -203,14 +208,15 @@ int v4_node_addr_ok(v4_cell addr);
* a table is attached.
*
* v4_node_reset detaches the table and clears the count. Attaching clears
* `stopped` and the count; all five words of the table must be in memory,
* `stopped` and the count; all six words of the table must be in memory,
* or `table` -1 to detach. */
#define V4_FAULT_ADDRESS 0u /* an address outside memory (D-14) */
#define V4_FAULT_DATA_OVER 1u /* a push onto a full data stack */
#define V4_FAULT_DATA_UNDER 2u /* the data stack holds too little for the opcode */
#define V4_FAULT_RET_OVER 3u /* a push onto a full return stack */
#define V4_FAULT_RET_UNDER 4u /* the return stack holds too little for the opcode */
#define V4_FAULT_KINDS 5u
#define V4_FAULT_RAISED 5u /* a programme stored an error code in NODE-ERROR (D-18) */
#define V4_FAULT_KINDS 6u
void v4_node_fault_attach(v4_node *n, v4_cell table);
@@ -232,4 +238,20 @@ void v4_node_fault(v4_node *n, unsigned kind, v4_cell addr);
* detaches both (-1); the addresses are the caller's choice (D-4). */
void v4_node_stack_regs_attach(v4_node *n, v4_cell d, v4_cell r);
/* NODE-ERROR as a trap (DECOMPOSITION.md D-18, ruled 2026-10-04: every error
* is guarded, shown, and returns the node to its prompt).
*
* A word that finds an error stores a code, which is not zero, in NODE-ERROR.
* After v4_node_error_attach(n, addr) a store of a non-zero value to `addr`
* writes that memory word, as before, and is then a fault of kind
* V4_FAULT_RAISED: the rest of the instruction word is not executed, the
* return stack is emptied, fault_addr is the code, and P becomes the sixth
* word of the fault table. The data stack is left alone. A store of zero
* -- which is how the flag is cleared -- is an ordinary store.
*
* Not attached (-1, as after v4_node_reset), NODE-ERROR is ordinary memory
* and a word that stores to it simply goes on: that is how a word can be run
* and its error seen with no prompt to return to. */
void v4_node_error_attach(v4_node *n, v4_cell addr);
#endif /* V4_NODE_H */