Names for things
"set apps /Apps", and then "$apps" anywhere on a later line stands for it. A name stops where a name stops - letters and digits - so it composes into a path without anything having to be quoted, which is the whole reason a script would want one. THE SUBSTITUTION HAPPENS ON EVERY LINE THE SHELL IS ABOUT TO RUN, typed or read out of a file, so the two behave the same and no command below has to know that variables exist. Same shape as the line editing: one place the whole system already flows through, rather than a decision made twenty times. 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 the class of silent wrong answer the rest of this system spends its effort refusing. It says so and the line counts as failed, which stops a script - and the test proves that by running one, where the line after it must not appear. Somebody who wants an empty value writes "set name" and gets one, so the escape hatch exists and has to be asked for. A NAME TOO LONG IS AN ERROR RATHER THAN A SHORTER NAME. Cutting it off at fifteen characters was the first version, and it is the same fault wearing a different coat: two names differing only after the fifteenth would be one variable, and the complaint about a missing one printed a word nobody typed. Eight slots of sixty four bytes - sixteen of name, forty eight of value - and sixty four rather than eighty because A and B are a sixteen bit shift register, so two rotations turn a slot number into its offset. The same trick the history uses, and the reason neither needs a multiply this machine has not got. TWO THINGS I GOT WRONG AND ONE I FOUND: doSetVar ended in RET. It is BRANCHED to from the dispatch, not called, so that RET went wherever the Stack happened to point - the same fault that formatted a disk last week, in a command written three days after the rule was named. The new lint rule does not catch this shape: it fires on falling INTO a subroutine, not on a branch target that ends like one. And a test of the expansion's answer, which is dead code: commandFailed does not return. It marks the line and branches to the prompt, the way every failure in this shell is reported, so the only way out of the expansion is the one where it worked. Which turned up a real leak, measured and not yet fixed: every failure that goes through commandFailed abandons the frames between the prompt and the call. SP goes from FFFD to FE6D over twenty of them, twenty bytes each. Its own commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
3c76934a9a
commit
a8707f29f0
@@ -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 <file>` 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:
|
||||
| `<name> [words]` | Any word the shell does not recognise is looked for on the disk as `<name>.sbx`, and loaded and started if it is there. |
|
||||
| `delete <file>` | Remove a file from the filesystem and release its blocks. |
|
||||
| `rename <file> <to>` | 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. |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <dir>
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
@@ -1,2 +1,4 @@
|
||||
monitor
|
||||
g 3F00
|
||||
b program
|
||||
s 4F00 00
|
||||
g 4F00
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
+17
-3
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user