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
@@ -138,6 +138,32 @@ The shell already had the other half. `LineFailed` exists because a script stops
line that did not work, so every command in the system was already saying whether it had
worked, for a different reason.
**And two loops, which 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.
```text
#! script
for colour in red green blue
echo it is $colour
end
set n go
while same $n go
echo round once
set n stop
end
```
The script reader keeps the position of **every** line before reading it, which is what makes
that possible: by the time a line has been read the reader is past it, and a line is not a
fixed size to subtract.
A `while` is taken away at its `end` and its line asks the question again. 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 - a byte in a block rather than a copy of the list in every one of
them. A `for` with no words runs no times, and a loop inside a branch nobody is taking runs
no times either.
Blocks nest eight deep. A branch that is not being taken is **not even looked at**: the
skipping happens before names are filled in, so `$whatever` inside a branch nobody is running
is not a mistake, and a line nobody is running cannot fail.
@@ -305,6 +331,8 @@ CosmOS currently provides these built-in commands:
| `if <command>` | Run the lines after it only if that command worked. See Lines Run Sometimes. |
| `else` | Run them only if it did not. |
| `end` | Close the block. |
| `while <command>` | Run the lines after it for as long as that command keeps working. |
| `for <name> in <words>` | Run them once for each word, with the name set to it. |
| `same <a> <b>` | Fails when the two are different, which is how `if` asks about a value. |
| `monitor` | Enter monitor mode, in which the prompt becomes `*` and the commands below are also available. |
| `help` | Show the built-in command summary. |