Let the shell run a file of commands
'do <file>' runs the lines in a file as though they had been typed. The
only thing a script changes is where the next line comes from: everything
below shellReadLine - splitting the line, matching it, loading a program -
cannot tell the difference and does not have to.
What makes a file a script is '#!' on the front of it, not its name and not
a flag in its entry. The rule this filesystem keeps is that an entry holds
only what the content cannot say about itself, and a script can say what it
is; the loader already refuses anything that is not SBEX, so the two kinds
of runnable file turn each other away without either knowing about the
other. It is also the deferred half of the file-typing design, which said
to wait for a second kind of runnable thing before building any of it. This
is that second kind.
'#' is a directive and ';' is a comment, as in SplitBit assembly - one rule
across the machine rather than two dialects. Not Unix's convention: there
'#!' really is a comment that only the kernel reads, while here the shell
requires it and refuses the file without it, so calling it a comment would
be a lie about what it does.
A script stops at the first line that does not work, which is what the
LineFailed groundwork was for. Comments and blank lines are dropped by the
reader rather than by the dispatch, so they are not echoed either. A script
running out hands back to the console rather than ending the shell, because
running out of file and running out of typing are not the same thing. The
interactive assembler reads through the same path, so a script can contain
a block of assembly.
Three things this cost that were not obvious:
- RET puts A and B back, so a routine cannot answer in them. scriptByte
returning the character in A assembled, ran, and handed the caller its
own A back every time. It answers in memory now.
- A last line with no newline is still a line. Text files do not reliably
end with one and an editor eating it is a bad way to find out a command
did not run.
- Not LastStatus. See the commit before this one.
Six checks in three tests, two of which are about byte positions rather
than behaviour - a command lying across the boundary between two blocks,
and that missing newline - so their fixtures are generated rather than
committed, where an editor cannot helpfully repair them.
Nesting is not in yet: a script cannot run a script. That wants a stack of
positions rather than the one the reader keeps.
Also derives native.sh's self-hosting source list from cosmos.asm's own
#Include lines. It was a hand written list and went stale the moment
script.asm existed - the fourth time a list beside a thing has drifted from
the thing - so it now asks the thing.
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
fc56e815fc
commit
2466d79d9c
@@ -116,6 +116,56 @@ 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.
|
||||
|
||||
## Scripts:
|
||||
|
||||
`do <file>` runs the lines in a file as though somebody had typed them. Every command works
|
||||
the same way it does at the prompt, because the only thing a script changes is where the next
|
||||
line comes from - the shell splits it, matches it and runs it without knowing the difference.
|
||||
|
||||
```
|
||||
#! script
|
||||
; Build the system and put it where the machine will find it.
|
||||
cd /Source/CosmOS
|
||||
Asm cosmos.asm
|
||||
```
|
||||
|
||||
**The first two bytes must be `#!`**, or the shell refuses the file and says so. That is what
|
||||
tells a script from anything else, and it is deliberately not the name and not a flag in the
|
||||
directory entry: the rule this filesystem keeps is that an entry holds only what the content
|
||||
cannot say about itself, and a script can say what it is. The loader already refuses anything
|
||||
that does not begin `SBEX`, so the two kinds of runnable file turn each other away without
|
||||
either of them having been told about the other.
|
||||
|
||||
What follows the `#!` is ignored. It is where the name of an interpreter goes if there is ever
|
||||
a second one; today there is one and it is this shell.
|
||||
|
||||
**`#` is a directive and `;` is a comment, exactly as in SplitBit assembly.** One rule across
|
||||
the machine rather than two dialects: `#` means this line is about the file, `;` means ignore
|
||||
this line. Comments and blank lines never reach the shell at all - they are dropped by the
|
||||
reader, so they are not echoed and the dispatch never sees a line it would have to know to
|
||||
ignore. This is not Unix's convention and is not trying to be; there `#!` genuinely is a
|
||||
comment that only the kernel looks at, while here the shell requires it.
|
||||
|
||||
**Each line is echoed as it runs**, after the prompt, so that a script reads exactly like
|
||||
somebody typing it and a script that stops says where.
|
||||
|
||||
**A script stops at the first line that does not work.** A build whose first step failed and
|
||||
whose second step ran anyway produces something wrong and reports success, which is the whole
|
||||
reason the shell now remembers whether a line worked. What counts as not working is a command
|
||||
that failed, a name the shell does not know, or a program that exited with a status. Nothing
|
||||
is printed but `stopped: that line did not work` - whatever failed has already said what was
|
||||
wrong in words.
|
||||
|
||||
**A script running out is not the same as typing running out.** The console ending means
|
||||
there is nobody there and the shell stops; a script ending means go back to whoever asked for
|
||||
it, so the next line comes from the console again.
|
||||
|
||||
The interactive assembler reads its lines the same way, so a script can contain a block of
|
||||
assembly and end it with a `.` just as you would by hand.
|
||||
|
||||
**A script cannot yet run another script.** That is the next thing, and it wants a stack of
|
||||
positions rather than the single one the reader keeps today.
|
||||
|
||||
## Shell Commands:
|
||||
|
||||
CosmOS currently provides these built-in commands:
|
||||
@@ -125,6 +175,7 @@ CosmOS currently provides these built-in commands:
|
||||
| `dir` | List the files on the mounted disk and their sizes. |
|
||||
| `load <path>` | Read and validate an SBEX application, then place its code and data where its header requests. |
|
||||
| `run [words]` | Start the loaded application and make the rest of the line available to it as an argument. |
|
||||
| `do <script>` | Run the lines in a file as though they had been typed. See Scripts. |
|
||||
| `cd [path]` | Go to a directory, or to the root with nothing after it. |
|
||||
| `mkdir <path>` | Make a directory. |
|
||||
| `rmdir <path>` | Remove one, if it is empty. |
|
||||
|
||||
Reference in New Issue
Block a user