"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
126 lines
3.1 KiB
Plaintext
126 lines
3.1 KiB
Plaintext
CosmOS
|
|
> monitor
|
|
x examine, d disassemble, a assemble, s set, b bank, g go, exit leaves
|
|
* b nonsense
|
|
b <program|data|number>
|
|
* b 9
|
|
there is no such bank
|
|
* load greet.sbx
|
|
loaded, starting at 5000
|
|
* b program
|
|
bank 00
|
|
* d 5000
|
|
5000 47 00 30 00 SETD.0 3000
|
|
5004 72 10 SWI 10
|
|
5006 47 00 30 44 SETD.0 3044
|
|
500A 72 10 SWI 10
|
|
500C 47 00 30 7A SETD.0 307A
|
|
5010 27 1F INIB 1F
|
|
5012 72 11 SWI 11
|
|
5014 47 00 30 5D SETD.0 305D
|
|
* x 5000
|
|
5000 47 00 30 00 72 10 47 00 30 44 72 10 47 00 30 7A G.0.r.G.0Dr.G.0z
|
|
5010 27 1F 72 11 47 00 30 5D 72 10 47 00 30 7A 72 10 '.r.G.0]r.G.0zr.
|
|
5020 47 00 30 65 72 10 20 72 12 00 00 00 00 00 00 00 G.0er. r........
|
|
5030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
|
* b data
|
|
bank 01
|
|
* x 3000
|
|
3000 61 20 70 72 6F 67 72 61 6D 2C 20 6C 6F 61 64 65 a program, loade
|
|
3010 64 20 6F 66 66 20 61 20 64 69 73 6B 2C 20 72 75 d off a disk, ru
|
|
3020 6E 6E 69 6E 67 20 6F 6E 20 74 68 65 20 73 79 73 nning on the sys
|
|
3030 74 65 6D 20 74 68 61 74 20 6C 6F 61 64 65 64 20 tem that loaded
|
|
* b 2
|
|
bank 02
|
|
* x 0
|
|
0000 01 FF 00 00 00 00 00 00 01 FF 00 00 00 00 00 00 ................
|
|
0010 03 FF 08 00 00 00 00 00 01 20 01 00 00 00 00 00 ......... ......
|
|
0020 00 FF 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 ................
|
|
0030 00 FF 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 ................
|
|
* s 0 FF
|
|
that bank will not be written
|
|
* b program
|
|
bank 00
|
|
* s 8000 26 48 D1 00 26 0A D1 00 18 12
|
|
* d 8000
|
|
8000 26 48 INIA 48
|
|
8002 D1 00 OUTA 00
|
|
8004 26 0A INIA 0A
|
|
8006 D1 00 OUTA 00
|
|
8008 18 SHR
|
|
8009 12 AND
|
|
800A 00 ?
|
|
800B 00 ?
|
|
* g 8000
|
|
H
|
|
that byte is not an instruction, at 800A
|
|
A 85 B 3F Q 05
|
|
the program was stopped
|
|
* d 8000
|
|
8000 26 48 INIA 48
|
|
8002 D1 00 OUTA 00
|
|
8004 26 0A INIA 0A
|
|
8006 D1 00 OUTA 00
|
|
8008 18 SHR
|
|
8009 12 AND
|
|
800A 00 ?
|
|
800B 00 ?
|
|
* b data
|
|
bank 01
|
|
* s 8100 68 65 6C 6C 6F 2C 20 74 79 70 65 64 0A 00
|
|
* b program
|
|
bank 00
|
|
* a 8200
|
|
8200: SETD.0 8100
|
|
8204: SWI 10
|
|
8206: lda.2
|
|
8208: LDD.0.1
|
|
820B: frobnicate
|
|
no such instruction
|
|
820B: INIA
|
|
that one needs a value after it
|
|
820B: SWI 12
|
|
820D: .
|
|
* d 8200
|
|
8200 47 00 81 00 SETD.0 8100
|
|
8204 72 10 SWI 10
|
|
8206 42 02 LDA.2
|
|
8208 4A 00 01 LDD.0.1
|
|
820B 72 12 SWI 12
|
|
820D 00 ?
|
|
820E 00 ?
|
|
820F 00 ?
|
|
* g 8200
|
|
hello, typed
|
|
finished
|
|
* exit
|
|
> dir
|
|
greet.sbx 211
|
|
hello.sbx 53
|
|
Life.sbx 1396
|
|
Snake.sbx 2164
|
|
Keys.sbx 664
|
|
Say.sbx 156
|
|
Break.sbx 149
|
|
Grid.sbx 559
|
|
Press.sbx 872
|
|
Mode.sbx 48
|
|
Crash.sbx 632
|
|
vars.script 50
|
|
tune.sbx 306
|
|
notes.txt 21
|
|
Apps <dir>
|
|
hi.script 121
|
|
bad.script 45
|
|
plain.script 24
|
|
cross.script 280
|
|
nonl.script 38
|
|
outer.script 376
|
|
inner.script 44
|
|
loop.script 35
|
|
22 files, 1 directory
|
|
> exit
|
|
halted
|
|
Execution halted.
|
|
[exit 0]
|