diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index ea6227b..27c15e0 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -116,6 +116,37 @@ 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. +## Names For Things: + +`set name value` writes one down, and `$name` anywhere on a later line stands for it. + +```text +> set apps /Apps +> echo $apps/Copy.sbx +/Apps/Copy.sbx +``` + +A name stops where a name stops - letters and digits - so it composes into a path without +anything having to be quoted. Eight of them can be set at once, names up to fifteen +characters and values up to forty seven. + +**The substitution happens on every line the shell is about to run**, typed or read from a +file, so scripts and typing behave the same and no command has to know that variables exist. +`set` on its own says what is written down. + +**A name nothing was ever set to does not run the line.** It says so, and the line counts as +failed - which stops a script, the same as any other failure. Every other shell expands an +unset name to nothing, and that is the wrong answer here: a mistyped name would quietly +become an empty path, which is the kind of silent wrong answer the rest of this system spends +its effort refusing. Somebody who genuinely wants an empty value writes `set name` with +nothing after it and gets one, so the escape hatch exists and has to be asked for. + +A name longer than fifteen characters is an error for the same reason. Cutting it short would +make two different names one variable and would put a word the person never typed into the +message about it. + +A `$` with nothing name-like after it is just a `$`. + ## Scripts: `do ` runs the lines in a file as though somebody had typed them. Every command works @@ -241,6 +272,7 @@ CosmOS currently provides these built-in commands: | ` [words]` | Any word the shell does not recognise is looked for on the disk as `.sbx`, and loaded and started if it is there. | | `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. | | `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 d4c5692..ed509aa 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -211,6 +211,19 @@ promptWhere: RSTA STA.1 + ; ---- Names filled in before anybody reads the line ---- + ; + ; Here rather than in the script reader, so that a typed line and a line out of a file + ; behave the same and no command below has to know that variables exist. A line that names + ; something nothing was ever set to does not run at all: it says so and counts as failed, + ; which is what makes a mistyped name a complaint instead of an empty path. + ; + ; THERE IS NOTHING TO TEST AFTERWARDS, and a test was written here before that was noticed: + ; 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. + CALL varExpand + SETD.0 CommandLine CALL textSplit @@ -279,6 +292,11 @@ promptWhere: CALL textSame BRQ doScript + SETD.0 CommandLine + SETD.1 SetVarName + CALL textSame + BRQ doSetVar + SETD.0 CommandLine SETD.1 HelpName CALL textSame @@ -2284,6 +2302,465 @@ tabList: CALL editRedraw BRI editKey +; ---- Things a line can be given a name for ---- +; +; Eight of them, so a script can hold a path or a half written command and compose the rest +; around it later. Each is one record of sixty four bytes: sixteen of name, then forty eight +; of value. SIXTY FOUR RATHER THAN EIGHTY, because A and B are a sixteen bit shift register +; and two rotations right turn a slot number into the offset of its slot - the same trick the +; history uses, and the reason neither of them needs a multiply this machine has not got. +; +; A slot whose name begins with a zero is free. Nothing counts them and nothing has to be +; kept in step. +; +; ---- A name that was never set is an error, and says so ---- +; +; Expanding it to nothing is what other shells do and it is the wrong answer here: a mistyped +; name would quietly become an empty path, and everything else in this system spends its +; effort on saying what went wrong. Somebody who genuinely wants an empty value writes +; "set name" with nothing after it and gets one - so the escape hatch exists, and has to be +; asked for rather than arrived at by accident. + +; DP3 to variable slot A, which is 0 to 7. +varSlotAt: + SETD.3 VarSlots + RSTB + SHR + SHR ; A and B together are the slot number times sixty four. + DPUW.3 + RET + +; DP0 names a name. Q is zero if it is there, and DP3 is left on its slot. +varFind: + SETD.1 VarWanted + STD.0.1 + RSTA + SETD.1 VarSlot + STA.1 +varFindNext: + SETD.1 VarSlot + LDA.1 + INIB 0d8 + CCF + SUB + BNC varFindNo ; Past the last slot. + + LDA.1 + CALL varSlotAt + SETD.1 VarWanted + LDD.0.1 + + LDA.3 + BRA varFindStep ; A free slot has no name to be the one wanted. +varFindMatch: + LDA.0 + BRA varFindEnded + LDB.3 + XOR + BNQ varFindStep + INCD.0 + INCD.3 + BRI varFindMatch +varFindEnded: + ; The same only if the slot's name ends here too. "path" and "pathname" are two names, and + ; comparing until the shorter runs out would call them one. + LDA.3 + BNA varFindStep + SETD.1 VarSlot + LDA.1 + CALL varSlotAt + RSTA + RSTB + CCF + ADD ; Q is zero: found. + RET + +varFindStep: + SETD.1 VarSlot + LDA.1 + INCA + STA.1 + BRI varFindNext + +varFindNo: + INIA 0x01 + RSTB + CCF + ADD ; Q is one: no such name. + RET + +; DP3 names a slot. Moves it on to that slot's value. +varValueOf: + INIA 0d16 + DPUA.3 + RET + +; DP0 names a name and DP1 its value. Q is zero if it was written down. +varSet: + SETD.2 VarKeepValue + STD.1.2 ; The value, while a slot is looked for. + + CALL varFind + BRQ varSetInto ; Already there, so it is written over. + + ; A free one, which is any whose name begins with a zero. + RSTA + SETD.1 VarSlot + STA.1 +varSetFree: + SETD.1 VarSlot + LDA.1 + INIB 0d8 + CCF + SUB + BNC varSetFull + LDA.1 + CALL varSlotAt + LDA.3 + BRA varSetInto + SETD.1 VarSlot + LDA.1 + INCA + STA.1 + BRI varSetFree + +varSetInto: + ; Which slot it is, is in VarSlot either way: varFind leaves the one it found there, and + ; the search above leaves the free one it stopped on. So it is worked out again rather than + ; carried in a pointer through two calls that would each put it back. + SETD.1 VarSlot + LDA.1 + CALL varSlotAt + PSHD.3 + POPD.1 + INIA 0d15 + CALL varCopy ; DP0 is still the name. + + SETD.1 VarSlot + LDA.1 + CALL varSlotAt + CALL varValueOf + PSHD.3 + POPD.1 + SETD.2 VarKeepValue + LDD.0.2 + INIA 0d47 + CALL varCopy + + RSTA + RSTB + CCF + ADD ; Q is zero: it is written down. + RET + +varSetFull: + INIA 0x01 + RSTB + CCF + ADD ; Q is one: there is no room for another. + RET + +; DP0 to DP1, at most A characters and then the zero that ends them. +varCopy: + SETD.2 VarRoom + STA.2 +varCopyNext: + SETD.2 VarRoom + LDA.2 + BRA varCopyDone + DECA + STA.2 + LDA.0 + BRA varCopyDone + STA.1 + INCD.0 + INCD.1 + BRI varCopyNext +varCopyDone: + RSTA + STA.1 + RET + +; A holds a character. Q is zero if it is one a name may be made of, which is what decides +; where a name written in the middle of a path stops: "$where/file" is a name and a path. +varNameChar: + INIB 0x30 + CCF + SUB + BRC varNameCharNo ; Below a digit. + INIB 0x3A + CCF + SUB + BRC varNameCharYes ; A digit. + INIB 0x41 + CCF + SUB + BRC varNameCharNo + INIB 0x5B + CCF + SUB + BRC varNameCharYes ; A capital. + INIB 0x61 + CCF + SUB + BRC varNameCharNo + INIB 0x7B + CCF + SUB + BRC varNameCharYes ; A small letter. +varNameCharNo: + INIA 0x01 + RSTB + CCF + ADD + RET +varNameCharYes: + RSTA + RSTB + CCF + ADD + RET + +; ---- The line, with every name in it replaced by what it stands for ---- +; +; Done here, on its way from wherever it was read to whoever runs it, so that a script line +; and a typed line behave the same and no command has to know that variables exist at all. +; The same shape as the line editing: one place the whole system already flows through. +; +; WHERE THE OUTPUT HAS GOT TO IS KEPT IN MEMORY rather than in a pointer. There are four +; pointers and this needs the line being read, the name being gathered, the value being +; copied and somewhere to put each character - and the moment the output position lived in +; one of them, gathering a name reset it to the start of the line. +; +; Q is zero if the line is ready to run. +varExpand: + SETD.0 VarLine + SETD.1 VarPut + STD.0.1 + RSTA + SETD.1 VarUsed + STA.1 + + SETD.0 CommandLine +varExpandNext: + LDA.0 + BRA varExpandDone + INIB 0x24 + XOR + BRQ varExpandName + CALL varExpandPut + BNQ varExpandLong + INCD.0 + BRI varExpandNext + +varExpandName: + ; Past the marker, and then as much of a name as follows it. + INCD.0 + SETD.2 VarName + RSTA + SETD.1 VarNameLen + STA.1 +varExpandNameChar: + LDA.0 + CALL varNameChar + BNQ varExpandNamed + SETD.1 VarNameLen + LDA.1 + INIB 0d15 + CCF + SUB + BNC varExpandNameLong ; One more and there would be nowhere to put it. + LDA.0 + STA.2 + INCD.2 + INCD.0 + LDA.1 + INCA + STA.1 + BRI varExpandNameChar + +varExpandNamed: + RSTA + STA.2 ; The zero that ends the gathered name. + + SETD.1 VarNameLen + LDA.1 + BNA varExpandLookUp + + ; A marker with nothing after it is just a marker, and goes through as one rather than + ; being an error about a variable nobody mentioned. + INIA 0x24 + CALL varExpandPut + BNQ varExpandLong + BRI varExpandNext + +varExpandLookUp: + SETD.1 VarKeepLine + STD.0.1 ; Where the line has got to, across the search. + SETD.0 VarName + CALL varFind + BNQ varExpandNoSuch + CALL varValueOf + SETD.1 VarKeepLine + LDD.0.1 + +varExpandValue: + LDA.3 + BRA varExpandNext + CALL varExpandPut + BNQ varExpandLong + INCD.3 + BRI varExpandValue + +varExpandDone: + RSTA + CALL varExpandPut ; The zero that ends the built line. + BNQ varExpandLong + + ; And back where everything downstream looks for it. + SETD.0 VarLine + SETD.1 CommandLine + INIA 0d127 + CALL varCopy + RSTA + RSTB + CCF + ADD + RET + +; A holds a character. Puts it where the built line has got to. Q is one if there is no room, +; which is a line that grew past what the shell can hold once its names were filled in. +varExpandPut: + SETD.2 VarHold + STA.2 + SETD.2 VarUsed + LDA.2 + INIB 0d127 + CCF + SUB + BNC varExpandNoRoom + + SETD.2 VarPut + LDD.1.2 + SETD.2 VarHold + LDA.2 + STA.1 + INCD.1 + SETD.2 VarPut + STD.1.2 + + SETD.2 VarUsed + LDA.2 + INCA + STA.2 + RSTA + RSTB + CCF + ADD + RET +varExpandNoRoom: + INIA 0x01 + RSTB + CCF + ADD + RET + +; ---- A name too long to be one is not a shorter name ---- +; +; Cutting it off at fifteen characters is what this did, and it is the quiet wrong answer +; this whole feature was built to avoid: two names that differ only after the fifteenth +; character would be ONE variable, and the message about a missing one would name something +; the person never typed. +varExpandNameLong: + SETD.0 VarNameLong + CALL printString + CALL newLine + CALL commandFailed ; Which does not come back. + +varExpandLong: + SETD.0 VarTooLong + CALL printString + CALL newLine + CALL commandFailed ; Which does not come back. + +varExpandNoSuch: + SETD.0 VarNoSuch + CALL printString + SETD.0 VarName + CALL printString + CALL newLine + CALL commandFailed ; Which does not come back. + +; ---- set ---- +; +; "set name value" writes one down, "set name" gives it an empty value on purpose, and "set" +; on its own says what is written down already - because a name that fails loudly when it was +; never set needs somewhere to go and look. +doSetVar: + SETD.1 TextRest + LDD.0.1 + LDA.0 + BRA setVarList ; Nothing after the word, so this is asking what is set. + + ; DP0 is still on the rest of the line - reading a byte through a pointer does not move it - + ; so the name starts where it already points. + SETD.1 SetVarWhich + STD.0.1 + CALL textSplit + + SETD.0 SetVarWhich + LDD.0.0 + SETD.1 TextRest + LDD.1.1 + CALL varSet + BNQ setVarFull + BRI prompt + +setVarFull: + SETD.0 SetVarNoRoom + CALL printString + CALL newLine + CALL commandFailed + BRI prompt + +setVarList: + RSTA + SETD.1 VarSlot + STA.1 +setVarListNext: + SETD.1 VarSlot + LDA.1 + INIB 0d8 + CCF + SUB + BNC setVarListDone + LDA.1 + CALL varSlotAt + LDA.3 + BRA setVarListStep ; A free slot has nothing to say. + + PSHD.3 + POPD.0 + CALL printString + SETD.0 SetVarIs + CALL printString + SETD.1 VarSlot + LDA.1 + CALL varSlotAt + CALL varValueOf + PSHD.3 + POPD.0 + CALL printString + CALL newLine +setVarListStep: + SETD.1 VarSlot + LDA.1 + INCA + STA.1 + BRI setVarListNext +setVarListDone: + BRI prompt + ; ---- A command that did not work ---- ; ; The one place a failure is recorded, so that the thing reading lines out of a file can @@ -6449,15 +6926,27 @@ ExitName: "exit" MonitorName: "monitor" +SetVarName: +"set" ; How many of them, since a run of strings does not say where it stops. ShellNameCount: - 0d15 + 0d16 SbxText: ".sbx" AppsPath: "/Apps" +VarNoSuch: +"nothing is set called " +VarTooLong: +"that line is too long once its names are filled in" +VarNameLong: +"that name is longer than a name can be" +SetVarNoRoom: +"there is no room for another name" +SetVarIs: +" is " ; 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. @@ -6837,6 +7326,37 @@ TabWasCwd: TabWasDrive: 0x00 +; ---- What a name stands for ---- +; +; Eight records of sixty four bytes: sixteen of name, then forty eight of value. +VarSlots: + #Reserve 0d512 +VarSlot: + 0x00 +VarWanted: + 0x00 0x00 +VarKeepValue: + 0x00 0x00 +VarKeepLine: + 0x00 0x00 +VarRoom: + 0x00 +VarHold: + 0x00 +; The line with its names filled in, built here and copied back when it is whole. +VarLine: + #Reserve 0d128 +VarPut: + 0x00 0x00 +VarUsed: + 0x00 +VarName: + #Reserve 0d16 +VarNameLen: + 0x00 +SetVarWhich: + 0x00 0x00 + ; ---- What the fault screen is saying ---- ; ; Whether this cause names an entry as well as itself, and which one. Only the two faults diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index ddb0b93..a19d23f 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`. 199 tests, of which 137 run, 35 +everything it printed against a file in `Tests/expected`. 200 tests, of which 138 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/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index a935c79..4e4e9be 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -23,6 +23,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -35,7 +36,7 @@ outer.script 376 inner.script 44 loop.script 35 crossed.txt 560 -22 files, 1 directory +23 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index 21fd2b1..e53044c 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -13,6 +13,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -24,7 +25,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > drive 1 > dir other.txt 28 diff --git a/Tests/expected/cosmosFault.out b/Tests/expected/cosmosFault.out index 586c052..8ddfb64 100644 --- a/Tests/expected/cosmosFault.out +++ b/Tests/expected/cosmosFault.out @@ -30,6 +30,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -41,7 +42,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosFaultSystem.out b/Tests/expected/cosmosFaultSystem.out index 249d421..cac08e0 100644 --- a/Tests/expected/cosmosFaultSystem.out +++ b/Tests/expected/cosmosFaultSystem.out @@ -1,8 +1,11 @@ CosmOS > monitor x examine, d disassemble, a assemble, s set, b bank, g go, exit leaves -* g 3F00 -that byte is not an instruction, at 3F00 +* b program +bank 00 +* s 4F00 00 +* g 4F00 +that byte is not an instruction, at 4F00 A 01 B 7F Q 00 that was the system itself, so there is nowhere to carry on from. Start the machine again. Execution halted. diff --git a/Tests/expected/cosmosGrid.out b/Tests/expected/cosmosGrid.out index ab00e8a..d6846da 100644 --- a/Tests/expected/cosmosGrid.out +++ b/Tests/expected/cosmosGrid.out @@ -20,6 +20,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -31,7 +32,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosMonitor.out b/Tests/expected/cosmosMonitor.out index b29caa6..004ebdb 100644 --- a/Tests/expected/cosmosMonitor.out +++ b/Tests/expected/cosmosMonitor.out @@ -106,6 +106,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -117,7 +118,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosMonitorRun.out b/Tests/expected/cosmosMonitorRun.out index a932ae9..075c64b 100644 --- a/Tests/expected/cosmosMonitorRun.out +++ b/Tests/expected/cosmosMonitorRun.out @@ -25,6 +25,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -36,7 +37,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > exit halted Execution halted. diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index b3462c2..94a0543 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -13,6 +13,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -24,7 +25,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > load load what? > load nosuch.sbx diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index b5d863b..761c7ff 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -11,6 +11,7 @@ Grid.sbx 559 Press.sbx 872 Mode.sbx 48 Crash.sbx 632 +vars.script 50 tune.sbx 306 notes.txt 21 Apps @@ -22,7 +23,7 @@ nonl.script 38 outer.script 376 inner.script 44 loop.script 35 -21 files, 1 directory +22 files, 1 directory > load Say.sbx loaded, starting at 5000 > run the disk took its time diff --git a/Tests/expected/cosmosVars.out b/Tests/expected/cosmosVars.out new file mode 100644 index 0000000..1bf83b0 --- /dev/null +++ b/Tests/expected/cosmosVars.out @@ -0,0 +1,27 @@ +CosmOS +> set apps /Apps +> echo $apps +/Apps +> set +apps is /Apps +> echo $apps/Copy.sbx +/Apps/Copy.sbx +> echo $nope +nothing is set called nope +> set apps +> echo [$apps] +[] +> echo $ 5 +$ 5 +> echo $aNameFarLongerThanFifteen +that name is longer than a name can be +> do vars.script +> echo before +before +> echo $nosuchname +nothing is set called nosuchname +stopped: that line did not work +> exit +halted +Execution halted. +[exit 0] diff --git a/Tests/input/cosmosFaultSys.in b/Tests/input/cosmosFaultSys.in index 03aff30..59995a6 100644 --- a/Tests/input/cosmosFaultSys.in +++ b/Tests/input/cosmosFaultSys.in @@ -1,2 +1,4 @@ monitor -g 3F00 +b program +s 4F00 00 +g 4F00 diff --git a/Tests/input/cosmosVars.in b/Tests/input/cosmosVars.in new file mode 100644 index 0000000..45d5b12 --- /dev/null +++ b/Tests/input/cosmosVars.in @@ -0,0 +1,11 @@ +set apps /Apps +echo $apps +set +echo $apps/Copy.sbx +echo $nope +set apps +echo [$apps] +echo $ 5 +echo $aNameFarLongerThanFifteen +do vars.script +exit diff --git a/Tests/makedisks.sh b/Tests/makedisks.sh index f38feba..53a1dd2 100755 --- a/Tests/makedisks.sh +++ b/Tests/makedisks.sh @@ -129,6 +129,10 @@ for i in 1 2 3 4 5 6 7 8; do "$TOOL" put "$DISKS/sbfs.img" "filler$i.txt" >/dev/ "$ROOT/Assembler" -I "$ROOT/Programs/CosmOS/Source" \ "$ROOT/Programs/CosmOS/Apps/Crash.asm" -o "$WORK/Crash.sbx" >/dev/null "$TOOL" put "$DISKS/cosmos.img" "$WORK/Crash.sbx" >/dev/null +# 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 +"$TOOL" put "$DISKS/cosmos.img" vars.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 6dccc8b..cf1d7e1 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -341,9 +341,13 @@ cosmosNoData | CosmOS/Source/cosmos.asm | run | cosmosNoD # that failed: those two faults are the only ones where the instruction did dispatch and it # was the entry that was empty. cosmosFault | CosmOS/Source/cosmos.asm | run | cosmosFault.in | - | disks/cosmos.img -# And a fault in the system's own code, which has nowhere to go back to. Reached through the -# monitor by jumping into the unwritten space above CosmOS and below where programs load, -# which is zeroes - so it faults at once and corrupts nothing on the way. +# And a fault in the system's own code, which has nowhere to go back to. +# +# THE BYTE IS PUT THERE RATHER THAN FOUND THERE. This used to jump into the space above +# CosmOS and below where programs load, on the grounds that it was zeroes - which stopped +# being true the moment CosmOS grew into it, and the test then jumped into the middle of the +# shell and did something else entirely. Writing the byte first means the address is the +# system's half of memory and nothing more is assumed about it. cosmosFaultSystem | CosmOS/Source/cosmos.asm | run | cosmosFaultSys.in | - | disks/cosmos.img # A word the MONITOR does not know. There was nothing at the end of its command list, so an # unrecognised word fell through into sayPrompt - a routine, whose RET then had nothing of its @@ -400,6 +404,16 @@ cosmosTab | CosmOS/Source/cosmos.asm | run | cosmosTab # Offering what the shell would not find would be finishing a word into something that then # does not work. cosmosTabPath | CosmOS/Source/cosmos.asm | run | cosmosTabPath.in | - | disks/cosmos.img +# Names for things, which is what makes a script able to compose a command rather than only +# to contain one. The expansion happens on every line the shell is about to run, typed or read +# from a file, so no command below has to know that variables exist. +# +# A NAME NOTHING WAS SET TO DOES NOT RUN THE LINE. Every other shell expands it to nothing, +# and that is the wrong answer here: a mistyped name would quietly become an empty path, +# which is exactly the kind of silent wrong answer the rest of this system spends its effort +# refusing. Somebody who wants an empty value writes "set name" and gets one - the escape +# hatch exists and has to be asked for. +cosmosVars | CosmOS/Source/cosmos.asm | run | cosmosVars.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.