Loops, and the scripting language is a language

while and for. Both only mean anything in a script, because a loop goes back to
the line that opened it and a prompt has no line to go back to - and both say so
rather than doing something surprising.

THE SCRIPT READER KEEPS THE POSITION OF EVERY LINE before reading it, which is
what makes any of this possible: by the time a line has been read the reader is
past it, and a line is not a fixed size to subtract. Three words per line, and
the block is read again on the way back so the pointer into it means what it
meant - the same thing nesting one script inside another already did, for a
different reason.

THE TWO LOOPS END DIFFERENTLY, and that is the design rather than an accident. A
while is taken away at its end and its own line asks the question again, so
nothing has to be remembered. A for is not: how many words it has used is kept
in the block, and its line reads itself again and counts one more off the front.
That is a byte in a block instead of a copy of the word list in every one of
them.

Blocks grew from a byte to a record of sixteen - state, kind, words used, and
where the line that opened it was - and sixteen because A and B are a shift
register, so four rotations turn a block number into its offset. The history and
the variables are addressed the same way for the same reason.

Nested loops, an if inside a loop, a loop inside a branch nobody takes, and a for
with no words: the last two run no times rather than once, which is the case
worth having a test for.

Three things found by running it:

textSame asks whether two WHOLE strings are the same, so "in red green blue" is
not "in". The word has to be split off before it is compared.

A for typed at a prompt complained about while, because both arrive at the same
place. One message that names neither is better than one that names the wrong
one.

And docs.sh caught a naming convention nobody had written down: it recognises a
packed name by its label ending in "Name", so ForName2 was silently not counted.
It failed the right way round - saying the run was shorter than the count claims
rather than passing - but the convention now lives where the names are and not
only in the checker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-01 20:50:05 -04:00
co-authored by Claude Opus 5
parent 16f8232a35
commit 2abc8281df
16 changed files with 522 additions and 54 deletions
+28
View File
@@ -243,6 +243,21 @@ scriptLine:
STD.0.1
scriptLineAgain:
; ---- Where this line begins ----
;
; Kept before it is read, because a loop has to be able to go back to the line that opened
; it and by the time that line has been read the reader is past it. Three words, and the
; block itself is read again on the way back, which is what scriptReread is for.
SETD.0 ScriptIndex
SETD.1 ScriptLineIndex
CALL sbfsCopyWord
SETD.0 ScriptAt
SETD.1 ScriptLineAt
CALL sbfsCopyWord
SETD.0 ScriptBlocks
SETD.1 ScriptLineBlocks
CALL sbfsCopyWord
SETD.1 ScriptLength
RSTA
STA.1
@@ -539,6 +554,19 @@ ScriptIndex:
0x00 0x00
ScriptAt:
0x00 0x00
; ---- And where the line being read began ----
;
; A loop goes back to the line that opened it, and by the time that line has been read the
; reader is past it. So the position is kept before every line rather than worked out
; afterwards, which cannot be done: a line is not a fixed size and there is nothing to
; subtract.
ScriptLineIndex:
0x00 0x00
ScriptLineAt:
0x00 0x00
ScriptLineBlocks:
0x00 0x00
; Saved with the rest, so that a quiet script calling a loud one gets its quiet back when
; the loud one finishes. A new script INHERITS it rather than resetting, because a build
; that asked for quiet meant its helpers too; only the first script started from the prompt