From 16f8232a350497de82175e446dbc04c753bcfb4e Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Tue, 1 Sep 2026 20:33:33 -0400 Subject: [PATCH] Lines that are only run sometimes if, else, end, and same. IF TAKES A COMMAND, which is one rule rather than two and is why comparing values needs no syntax of its own: "same" is an ordinary command that fails when its two words differ, so "if same $a $b" falls out of the rule instead of being an exception to it. Anything else that can fail is a question too - "if load Snake.sbx" is a perfectly good one. The shell already had the other half. LineFailed exists because a script stops at the first line that did not work, so every command was already saying whether it had, for a different reason entirely. A BLOCK HAS TWO KINDS OF NOT-RUNNING. One where an else would turn it on, and one where it would not - which is what an if pushes when something above it is already being skipped. That is what makes nesting need no looking down the stack: the top of it says everything. A branch nobody is taking is not even looked at. The skipping happens BEFORE the names are filled in, so a variable mentioned in a branch that is not running is not an error - a line nobody runs must not be able to fail. AND LINES MAY BE INDENTED, which they could not be before there was anything to indent inside. Nobody writes an if inside an if without indenting what is in them, and a leading space used to make the first word empty and match nothing. Found by writing the test script the way anybody would write one. CALL commandFailed became BRI commandFailed in nine places. It never returns - it marks the line and branches to the prompt - so calling it was a lie that cost a Stack frame each time, and fourteen other sites already branched. THE LINT RULE FOUND THIS, three days after I wrote the rule and on my own code: two false positives that were really the linter being right about a CALL that is not one. It does not fix the leak on its own, since a failure inside any called routine still abandons that frame, but it removes the cause of the commonest case and makes the code true. The mechanical edit then left a BRI prompt stranded behind one of them, and the linter caught that too. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Programs/CosmOS/README.md | 33 +++ Programs/CosmOS/Source/cosmos.asm | 391 +++++++++++++++++++++++++++- SplitBit Test Manual.md | 2 +- Tests/expected/cosmosBlocks.out | 54 ++++ Tests/expected/cosmosCrossDisk.out | 3 +- Tests/expected/cosmosDrives.out | 3 +- Tests/expected/cosmosFault.out | 3 +- Tests/expected/cosmosGrid.out | 3 +- Tests/expected/cosmosMonitor.out | 3 +- Tests/expected/cosmosMonitorRun.out | 3 +- Tests/expected/cosmosRun.out | 3 +- Tests/expected/cosmosSlowDisk.out | 3 +- Tests/input/cosmosBlocks.in | 16 ++ Tests/makedisks.sh | 5 + Tests/manifest | 13 + 15 files changed, 523 insertions(+), 15 deletions(-) create mode 100644 Tests/expected/cosmosBlocks.out create mode 100644 Tests/input/cosmosBlocks.in diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index 27c15e0..1dcd781 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -116,6 +116,35 @@ an installed library and a copy of the source. The disk is rebuilt from scratch when its applications change, so its contents describe the current source tree rather than accumulating files left by older builds. +## Lines Run Sometimes: + +```text +#! script +set colour red +if same $colour red + echo it is red +else + echo it is not +end +``` + +**`if` takes a command**, and what follows runs only if that command worked. That is one rule +rather than two, and it is why comparing values needs no syntax of its own: `same` is an +ordinary command that fails when its two words differ, so `if same $a $b` falls out of the +rule instead of being an exception to it. Anything else that can fail can be asked about the +same way - `if load Snake.sbx` is a perfectly good question. + +The shell already had the other half. `LineFailed` exists because a script stops at the first +line that did not work, so every command in the system was already saying whether it had +worked, for a different reason. + +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. + +**Lines may be indented**, which they could not be before there was anything to indent +inside. Leading spaces are taken off before anything looks at the line. + ## Names For Things: `set name value` writes one down, and `$name` anywhere on a later line stands for it. @@ -273,6 +302,10 @@ CosmOS currently provides these built-in commands: | `delete ` | Remove a file from the filesystem and release its blocks. | | `rename ` | Give a file a different name without moving its contents. | | `set [name [value]]` | Give a name a value, or say what the names are. See Names For Things. | +| `if ` | 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. | +| `same ` | 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. | | `exit` | Leave monitor mode if in it, and otherwise halt the machine. | diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index 64020c8..9a479df 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -187,6 +187,32 @@ prompt: LDD.0.1 MVDS.0 + ; ---- What an "if" line's command made of it ---- + ; + ; Read here because this is where every command comes back to, and the last place a result + ; is still the result of the line that produced it. It has to happen BEFORE the stop on + ; failure below: a condition that fails is the ordinary half of a question, not a script + ; going wrong, so the flag is cleared as it is taken. + SETD.1 IfPending + LDA.1 + BRA promptNoIf + RSTA + STA.1 + SETD.1 LineFailed + LDA.1 + BRA promptIfTaken + INIA 0d1 ; It failed, so this branch is not taken and an else would be. + BRI promptIfPush +promptIfTaken: + RSTA +promptIfPush: + CALL blockPush + BNQ ifDeep + RSTA + SETD.1 LineFailed + STA.1 ; And the question is answered rather than unanswered. +promptNoIf: + ; ---- A script stops at the first line that did not work ---- ; ; Checked here, before the next line is read, because this is the one place every command @@ -251,8 +277,24 @@ promptWhere: ; commandFailed does not return. It marks the line and branches to the prompt, the way every ; command in this shell reports a failure, so the only way out of the expansion is the one ; where it worked. + ; ---- Room to indent ---- + ; + ; Leading spaces are taken off, which the shell never allowed and never needed to: a line + ; was a command and a command started at the front. Blocks change that. Nobody writes an if + ; inside an if without indenting what is inside them, and a line that began with a space + ; used to split into an empty first word and match nothing at all. + CALL lineTrim + + ; ---- And a line nobody is running is not run ---- + ; + ; Before the names are filled in, on purpose. A branch that is not being taken must not be + ; able to fail, and a name it mentions has no business existing. + CALL blockSkipping + BNQ blockPassOver + CALL varExpand +promptDispatch: SETD.0 CommandLine CALL textSplit @@ -326,6 +368,26 @@ promptWhere: CALL textSame BRQ doSetVar + SETD.0 CommandLine + SETD.1 IfName + CALL textSame + BRQ doIf + + SETD.0 CommandLine + SETD.1 ElseName + CALL textSame + BRQ doElse + + SETD.0 CommandLine + SETD.1 EndName + CALL textSame + BRQ doEnd + + SETD.0 CommandLine + SETD.1 SameName + CALL textSame + BRQ doSame + SETD.0 CommandLine SETD.1 HelpName CALL textSame @@ -2704,13 +2766,13 @@ varExpandNameLong: SETD.0 VarNameLong CALL printString CALL newLine - CALL commandFailed ; Which does not come back. + BRI commandFailed varExpandLong: SETD.0 VarTooLong CALL printString CALL newLine - CALL commandFailed ; Which does not come back. + BRI commandFailed varExpandNoSuch: SETD.0 VarNoSuch @@ -2718,7 +2780,296 @@ varExpandNoSuch: SETD.0 VarName CALL printString CALL newLine - CALL commandFailed ; Which does not come back. + BRI commandFailed + +; ---- Lines that are only run sometimes ---- +; +; "if" takes a COMMAND and runs it, and what follows is run only if that command worked. That +; is the Bourne shell's answer and it is the reason "test" exists there: one rule in if, and +; comparing two things is just another command that can fail. Here that command is "same", +; and the shell already had the other half - LineFailed, which every command sets and which +; stop-on-failure was built on. +; +; A block is one byte on a stack eight deep: +; +; 0 this branch is running +; 1 this branch is not, but an else would turn it on +; 2 this branch is not, and an else would not either +; +; The two kinds of not-running are what make nesting work without looking down the stack: an +; "if" met while something above it is being skipped pushes a 2, so the top of the stack +; always says everything, and a line runs when the stack is empty or its top is nought. +blockSkipping: + SETD.1 BlockDepth + LDA.1 + BRA blockRunning ; Nothing open, so nothing is being skipped. + DECA + SETD.3 BlockStack + DPUA.3 + LDA.3 + BRA blockRunning + INIA 0x01 + RSTB + CCF + ADD ; Q is one: skipping. + RET +blockRunning: + RSTA + RSTB + CCF + ADD ; Q is zero: running. + RET + +; A holds what to push. Q is one if there is no room for another. +blockPush: + SETD.1 BlockHold + STA.1 + SETD.1 BlockDepth + LDA.1 + INIB 0d8 + CCF + SUB + BNC blockFull + LDA.1 + SETD.3 BlockStack + DPUA.3 + SETD.1 BlockHold + LDA.1 + STA.3 + SETD.1 BlockDepth + LDA.1 + INCA + STA.1 + RSTA + RSTB + CCF + ADD + RET +blockFull: + INIA 0x01 + RSTB + CCF + ADD + RET + +; DP3 on the block on top. Q is one if there is not one. +blockTop: + SETD.1 BlockDepth + LDA.1 + BRA blockNone + DECA + SETD.3 BlockStack + DPUA.3 + RSTA + RSTB + CCF + ADD + RET +blockNone: + INIA 0x01 + RSTB + CCF + ADD + RET + +; ---- if ---- +; +; The rest of the line is a command, so the line becomes that command and is dispatched +; again, with a note saying that what it makes of it decides a block rather than being +; somebody's answer. The note is read at the top of the loop, which is where every command +; comes back to and the one place that sees a result before the next line disturbs it. +doIf: + CALL blockSkipping + BNQ ifSkipped + + SETD.1 TextRest + LDD.0.1 + LDA.0 + BRA ifWhat ; "if" with nothing to decide by. + + ; The rest of the line, moved to the front of it. Forwards, and the source is ahead of the + ; destination, so one walk does it without anything being overwritten before it is read. + SETD.1 CommandLine +ifShift: + LDA.0 + STA.1 + BRA ifShifted + INCD.0 + INCD.1 + BRI ifShift +ifShifted: + INIA 0x01 + SETD.1 IfPending + STA.1 + BRI promptDispatch + +ifSkipped: + ; Inside something that is not being taken. The condition is not run and not even looked + ; at - a line that is not being taken must not be able to fail, or a name it mentions + ; would have to exist. + INIA 0d2 + CALL blockPush + BNQ ifDeep + BRI prompt + +ifWhat: + SETD.0 IfUsage + CALL printString + CALL newLine + BRI commandFailed + +ifDeep: + SETD.0 IfTooDeep + CALL printString + CALL newLine + BRI commandFailed + +; ---- else ---- +doElse: + CALL blockTop + BNQ elseLonely + LDA.3 + BRA elseTaken ; This branch ran, so the other one does not. + INIB 0d1 + XOR + BNQ elseStays ; A two stays a two: nothing here is being taken. + RSTA + STA.3 + BRI prompt +elseTaken: + INIA 0d2 + STA.3 +elseStays: + BRI prompt +elseLonely: + SETD.0 ElseLonely + CALL printString + CALL newLine + BRI commandFailed + +; ---- end ---- +doEnd: + SETD.1 BlockDepth + LDA.1 + BRA endLonely + DECA + STA.1 + BRI prompt +endLonely: + SETD.0 EndLonely + CALL printString + CALL newLine + BRI commandFailed + +; ---- same ---- +; +; Two words, and it fails when they differ. A command rather than a form of if, so that if +; has one rule and anything that can fail can be asked about. +doSame: + SETD.1 TextRest + LDD.0.1 + SETD.1 SameFirst + STD.0.1 + CALL textSplit + + SETD.0 SameFirst + LDD.0.0 + SETD.1 TextRest + LDD.1.1 + CALL textSame + BNQ sameNot + BRI prompt +sameNot: + BRI commandFailed + +; Takes the spaces off the front of the line, by moving what is after them to the front. In +; place and forwards, with the source ahead of the destination, so one walk does it. +lineTrim: + SETD.0 CommandLine + LDA.0 + INIB 0x20 + XOR + BNQ lineTrimDone ; It does not start with one, which is almost every line. + +lineTrimSkip: + INCD.0 + LDA.0 + BRA lineTrimEmpty + INIB 0x20 + XOR + BRQ lineTrimSkip + + SETD.1 CommandLine +lineTrimMove: + LDA.0 + STA.1 + BRA lineTrimDone + INCD.0 + INCD.1 + BRI lineTrimMove + +lineTrimEmpty: + ; Nothing but spaces. It becomes an empty line, which the shell already knows to do + ; nothing about. + SETD.0 CommandLine + RSTA + STA.0 +lineTrimDone: + RET + +; DP0 names a line and DP1 a word. Q is zero if the line's FIRST WORD is that word - which +; is what lets a line be recognised without textSplit writing a zero into the middle of it, +; and a line that is being skipped must come through untouched. +lineFirstIs: + LDA.1 + BRA lineFirstEnded + LDB.0 + XOR + BNQ lineFirstNo + INCD.0 + INCD.1 + BRI lineFirstIs +lineFirstEnded: + LDA.0 + BRA lineFirstYes + INIB 0x20 + XOR + BRQ lineFirstYes +lineFirstNo: + INIA 0x01 + RSTB + CCF + ADD + RET +lineFirstYes: + RSTA + RSTB + CCF + ADD + RET + +; ---- A line inside a block that is not being taken ---- +; +; Only the three words that shape a block mean anything here, and they are matched WITHOUT +; the line being split or its names filled in: a line nobody is running must not be able to +; fail, and "$whatever" in a branch that was not taken is not a mistake. +blockPassOver: + SETD.0 CommandLine + SETD.1 IfName + CALL lineFirstIs + BRQ ifSkipped + + SETD.0 CommandLine + SETD.1 ElseName + CALL lineFirstIs + BRQ doElse + + SETD.0 CommandLine + SETD.1 EndName + CALL lineFirstIs + BRQ doEnd + + BRI prompt ; ---- set ---- ; @@ -2749,8 +3100,7 @@ setVarFull: SETD.0 SetVarNoRoom CALL printString CALL newLine - CALL commandFailed - BRI prompt + BRI commandFailed setVarList: RSTA @@ -6957,10 +7307,18 @@ MonitorName: "monitor" SetVarName: "set" +IfName: +"if" +ElseName: +"else" +EndName: +"end" +SameName: +"same" ; How many of them, since a run of strings does not say where it stops. ShellNameCount: - 0d16 + 0d20 SbxText: ".sbx" @@ -6976,6 +7334,14 @@ SetVarNoRoom: "there is no room for another name" SetVarIs: " is " +IfUsage: +"if wants a command to decide by" +IfTooDeep: +"that is more blocks than will fit inside one another" +ElseLonely: +"else with no if above it" +EndLonely: +"end with no if above it" ; Where the machine is, written out for the prompt, and where in the buffer it begins. ; Built from the end backwards, so it starts somewhere in the middle. @@ -7258,6 +7624,19 @@ SystemStack: ; And where it is when the shell is between lines, which is not the same thing. See prompt. ShellStack: 0x00 0x00 + +; ---- Which blocks are open, and whether their lines are being run ---- +BlockStack: + #Reserve 0d8 +BlockDepth: + 0x00 +BlockHold: + 0x00 +; Set while the line being run is an "if" condition rather than somebody's own command. +IfPending: + 0x00 +SameFirst: + 0x00 0x00 DirSeen: 0x00 DirSize: diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index 8724b17..897e06e 100644 --- a/SplitBit Test Manual.md +++ b/SplitBit Test Manual.md @@ -79,7 +79,7 @@ from `make`, not from here. ### 1. Recorded output `Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares -everything it printed against a file in `Tests/expected`. 201 tests, of which 139 run, 35 +everything it printed against a file in `Tests/expected`. 202 tests, of which 140 run, 35 only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image given at all. diff --git a/Tests/expected/cosmosBlocks.out b/Tests/expected/cosmosBlocks.out new file mode 100644 index 0000000..c5aa3ec --- /dev/null +++ b/Tests/expected/cosmosBlocks.out @@ -0,0 +1,54 @@ +CosmOS +> set a hello +> if same $a hello +> echo taken +taken +> else +> echo not taken +> end +> if load nosuch.sbx +no such file +> echo loaded +> else +> echo did not +did not +> end +> else +else with no if above it +> end +end with no if above it +> if +if wants a command to decide by +> do blocks.script +> set colour red +> if same $colour red +> echo it is red +it is red +> if same $colour blue +> echo and blue +> else +> echo but not blue +but not blue +> end +> else +> echo $neverSetAnywhere +> end +> if same $colour blue +> echo wrong +> else +> echo right +right +> end +> if same $colour blue +> if same $colour red +> echo deep wrong +> else +> echo deep also wrong +> end +> end +> echo done +done +> exit +halted +Execution halted. +[exit 0] diff --git a/Tests/expected/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index 4e4e9be..a116723 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -24,6 +24,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -36,7 +37,7 @@ outer.script 376 inner.script 44 loop.script 35 crossed.txt 560 -23 files, 1 directory +24 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index e53044c..6e24375 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -14,6 +14,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -25,7 +26,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > drive 1 > dir other.txt 28 diff --git a/Tests/expected/cosmosFault.out b/Tests/expected/cosmosFault.out index 8ddfb64..2e7d861 100644 --- a/Tests/expected/cosmosFault.out +++ b/Tests/expected/cosmosFault.out @@ -31,6 +31,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -42,7 +43,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosGrid.out b/Tests/expected/cosmosGrid.out index d6846da..618e1a7 100644 --- a/Tests/expected/cosmosGrid.out +++ b/Tests/expected/cosmosGrid.out @@ -21,6 +21,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -32,7 +33,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosMonitor.out b/Tests/expected/cosmosMonitor.out index 004ebdb..de88c48 100644 --- a/Tests/expected/cosmosMonitor.out +++ b/Tests/expected/cosmosMonitor.out @@ -107,6 +107,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -118,7 +119,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosMonitorRun.out b/Tests/expected/cosmosMonitorRun.out index 075c64b..e607ba2 100644 --- a/Tests/expected/cosmosMonitorRun.out +++ b/Tests/expected/cosmosMonitorRun.out @@ -26,6 +26,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -37,7 +38,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index 94a0543..4d6e679 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -14,6 +14,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -25,7 +26,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > load load what? > load nosuch.sbx diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index 761c7ff..0c5317a 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -12,6 +12,7 @@ Press.sbx 872 Mode.sbx 48 Crash.sbx 632 vars.script 50 +blocks.script 343 tune.sbx 306 notes.txt 21 Apps @@ -23,7 +24,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -22 files, 1 directory +23 files, 1 directory > load Say.sbx loaded, starting at 5000 > run the disk took its time diff --git a/Tests/input/cosmosBlocks.in b/Tests/input/cosmosBlocks.in new file mode 100644 index 0000000..2d3536b --- /dev/null +++ b/Tests/input/cosmosBlocks.in @@ -0,0 +1,16 @@ +set a hello +if same $a hello +echo taken +else +echo not taken +end +if load nosuch.sbx +echo loaded +else +echo did not +end +else +end +if +do blocks.script +exit diff --git a/Tests/makedisks.sh b/Tests/makedisks.sh index 53a1dd2..7d784dd 100755 --- a/Tests/makedisks.sh +++ b/Tests/makedisks.sh @@ -132,7 +132,12 @@ for i in 1 2 3 4 5 6 7 8; do "$TOOL" put "$DISKS/sbfs.img" "filler$i.txt" >/dev/ # A script that names something nothing was ever set to. Stop on failure is what says the # expansion really did fail rather than merely complaining: the line after it must not run. printf '#! script\necho before\necho $nosuchname\necho after\n' > vars.script +# A script with blocks in it, because that is where they are actually for. It nests, it +# takes the second branch of an outer if, and the branch nobody takes mentions a name that +# was never set - which must not be an error, because nothing there is being run. +printf '#! script\nset colour red\nif same $colour red\n echo it is red\n if same $colour blue\n echo and blue\n else\n echo but not blue\n end\nelse\n echo $neverSetAnywhere\nend\nif same $colour blue\n echo wrong\nelse\n echo right\nend\nif same $colour blue\n if same $colour red\n echo deep wrong\n else\n echo deep also wrong\n end\nend\necho done\n' > blocks.script "$TOOL" put "$DISKS/cosmos.img" vars.script >/dev/null +"$TOOL" put "$DISKS/cosmos.img" blocks.script >/dev/null # tune.sbx, which used to be a boot image and is now a program like any other. It brings a # vector of its own - the screen's, so that it has a beat to play to - which makes it the # second thing here that the version two format exists for. diff --git a/Tests/manifest b/Tests/manifest index 02a1d38..a22ec8a 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -425,6 +425,19 @@ cosmosVars | CosmOS/Source/cosmos.asm | run | cosmosVar # Break is what makes it visible, because it prints the registers. The two dumps have to # agree, and the failures between them are what would move it. cosmosStack | CosmOS/Source/cosmos.asm | run | cosmosStack.in | - | disks/cosmos.img +# Lines that are only run sometimes. "if" takes a COMMAND and what follows runs only if that +# command worked - the Bourne shell's answer, and the reason "test" exists there: one rule in +# if, and comparing two things is just another command that can fail. Here that command is +# "same", and the shell already had the other half in LineFailed. +# +# AN if INSIDE A BRANCH NOBODY IS TAKING IS NOT A QUESTION. Its else must not run either, so +# it is pushed as a block that neither branch of can be taken - which is why a block has two +# kinds of not-running rather than one, and why nesting needs no looking down the stack. +# +# THE BRANCH NOBODY TAKES IS NOT EVEN LOOKED AT. The script names a variable that was never +# set, inside the branch that is not taken, and that must not be an error - so the skipping +# happens before the names are filled in, and a line nobody is running cannot fail. +cosmosBlocks | CosmOS/Source/cosmos.asm | run | cosmosBlocks.in | - | disks/cosmos.img # The same editing offered to a PROGRAM, through osReadLine. Edit reads its lines that way, # so a word typed with two letters the wrong way round is put right without starting the line # again - which is the whole of what A4 buys.