Author: Claude Code

0

SATELLITE.LIBRARY

Some values are part of how a program is set up rather than something it works out: the oven temperature in a recipe, the number of players in a game, the name of a file to save to. You want to write them once, near the top where they are easy to find and change, and read them anywhere. In satellite that is satellite.library.

Writing values at the top of a file

A library value is one line, outside every capsule: satellite.library., a name of your choosing, =, and a value. Every capsule in the file can then read it as satellite.library. and that name, anywhere a value can go: in a line, a condition, a loop, or a capsule inside a namespace.

bake.satlSATELLITE 004 Download
Library values of several kinds, read from main and from a namespace
satellite.include(satellite)

satellite.library.oven = 180
satellite.library.minutes = 23
satellite.library.cake = "lemon drizzle"
satellite.library.sugar = 1/3
satellite.library.tip = 15%
satellite.library.icing = satellite.bool.true

satellite.namespace timer
{
    satellite.capsule countdown()
    {
        satellite.variable.number left = satellite.library.minutes
        satellite.statement.while (left > 20)
        {
            satellite.console.display(left.to_string() + " minutes left")
            left = left - 1
        }
    }
}

satellite.capsule satellite.main()
{
    satellite.console.display("baking a " + satellite.library.cake + " at " + satellite.library.oven.to_string())
    satellite.console.display(satellite.library.sugar)
    satellite.console.display(satellite.library.tip)
    satellite.statement.if (satellite.library.icing)
    {
        satellite.console.display("with icing")
    }
    timer.countdown()
    satellite.return(satellite)
}
OUTPUT
baking a lemon drizzle at 180
1/3
15%
with icing
23 minutes left
22 minutes left
21 minutes left

A library value can be any value you can write down: a number, a float, text, a binary, a hex, a percentage, a fraction, or satellite.bool.true or satellite.bool.false, with a minus sign in front if it has one. A colour is written as the hex it holds, such as x1E2A3A.

Notice the name. satellite.library.oven starts with satellite, because the library is part of the language, and ends with oven, which is yours. Each name is written once in a file. Writing the same one twice is refused.

Values, not variables

A library value never changes. That is the whole point: a value that any capsule could change would be a global, and a global can be changed by any part of a program at any time, which makes a program hard to follow. satellite has no globals.

To work with a library value, copy it into a variable of your own. The variable changes; the library value does not. A library value can also be a spacesuit field’s first value.

scoreboard.satlSATELLITE 004 Download
Copy a value into a variable to change it, and use one as a field's first value
satellite.include(satellite)

satellite.library.players = 4
satellite.library.start_lives = 3

satellite.spacesuit player()
{
    satellite.protected
    {
        satellite.variable.number lives = satellite.library.start_lives
    }

    satellite.public
    {
        satellite.capsule lose_one()
        {
            lives = lives - 1
        }

        satellite.capsule call_lives()
        {
            satellite.return(lives)
        }
    }
}

satellite.capsule satellite.main()
{
    satellite.variable.number seats = satellite.library.players
    seats = seats + 1
    satellite.console.display(seats)
    satellite.console.display(satellite.library.players)

    player ann
    ann.lose_one()
    satellite.console.display(ann.call_lives())
    satellite.console.display(satellite.library.start_lives)
    satellite.return(satellite)
}
OUTPUT
5
4
2
3

Changing a library value from inside a capsule is refused before anything runs, and the report says what to do instead:

hotter.satlSATELLITE 004 Download
Changing a library value is refused
satellite.include(satellite)

satellite.library.oven = 180

satellite.capsule satellite.main()
{
    satellite.library.oven = 200
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S250: LIBRARY_VALUE_IS_FIXED
satl(check): in satellite.main, satellite.library.oven is written at the top of
its file and never changes -- a value every capsule could change would be a
global, and satellite has none. Copy it into a variable of your own and change
that

directory: hotter.satl:7
syntax: satellite.library.oven = 200
        /\

a satellite.library value is written down at the top of its file -- one number,
text or other literal -- and nothing works it out or changes it afterwards. A
value every capsule could change would be a global, and satellite has none.
machine code 54 library_value_is_fixed -- satl exits with this.

--------------------------------------------------------------------------------

Written down, never worked out

Nothing runs outside a capsule, so there is no moment when 90 * 2 could be worked out at the top of a file. A library value must be written as the value itself:

worked_out.satlSATELLITE 004 Download
A sum at the top of a file is refused
satellite.include(satellite)

satellite.library.oven = 90 * 2

satellite.capsule satellite.main()
{
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S250: LIBRARY_VALUE_IS_FIXED
satl(check): satellite.library.oven is given something to work out, and a
satellite.library value is written down: one number, float, text, binary, hex,
percentage or fraction, or satellite.bool.true or .false. Nothing runs outside a
capsule, so there is no moment for it to be worked out in -- work it out in the
capsule that needs it

directory: worked_out.satl:3
syntax: satellite.library.oven = 90 * 2
                                 /\

a satellite.library value is written down at the top of its file -- one number,
text or other literal -- and nothing works it out or changes it afterwards. A
value every capsule could change would be a global, and satellite has none.
machine code 54 library_value_is_fixed -- satl exits with this.

--------------------------------------------------------------------------------

Another file’s values

Library values are handy for a settings file. A program that includes settings.satl reads that file’s values through the file’s name: a value written in settings.satl as satellite.library.players = 4 is read by the program as satellite.library.settings.players. The capsules inside settings.satl itself still read it as satellite.library.players. A file reaches the values of the files it includes itself, and no others, the same way it reaches their capsules.

Where next

The FULL REFERENCE has the complete rules. Including a settings file is covered in INCLUDING FILES AND NAMESPACES, and the settings satl itself runs with are in THE ARGUMENTS VARIABLE.

THE ARGUMENTS VARIABLE 1

THE ARGUMENTS VARIABLE

When satl starts a program, it already knows a great deal: the words you typed after the file name, its own settings, and facts about the machine it is running on, such as your user name, how much memory there is and what the processor can do. The arguments variable hands all of it to your program as one variable.

Asking for it

satellite.main hands the variable over when you declare it between main’s brackets. The type is satellite.variable.arguments, and the name is yours to choose: arguments, args, anything.

TEXT Download
satellite.capsule satellite.main(satellite.variable.arguments args)

A program whose main is written satellite.main(), with nothing between the brackets, simply does not ask for it. The older spelling, satellite.container.list<satellite.variable.string> arguments, gives you the same variable.

Each piece of information is a row, read by its name after the variable’s name, with no brackets: args.program, args.username, args.memory.total.

The words you started it with

satl greet.satl mum dad runs greet.satl and hands it two words. The program sees them as rows:

  • args.program is the file’s name, greet.satl.
  • args.argument_1 is mum, and args.argument_2 is dad.
  • args.length counts them all, the program included, so here it is 3.

A row that is not there is refused, so check args.length before you read a word that may not have been given:

greet.satlSATELLITE 004 Download
Read the words after the file name, if there are any
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    satellite.console.display(args.program)
    satellite.console.display(args.length)
    satellite.statement.if (args.length > 1)
    {
        satellite.console.display("hello, " + args.argument_1)
    }
    satellite.statement.else
    {
        satellite.console.display("hello, whoever you are")
    }
    satellite.return(satellite)
}

Run with no words, satl greet.satl prints:

OUTPUT
greet.satl
1
hello, whoever you are

and with two:

BASH Download
Two words after the file name
satl greet.satl mum dad
OUTPUT
greet.satl
3
hello, mum

satl’s settings and the machine’s facts

The same variable holds satl’s own settings and what satl found out about the machine. satellite.console.display(args) shows every row there is, several dozen of them. A few you may like:

  • args.version and args.revision, the satellite you are running
  • args.username, args.session.home and args.session.shell
  • args.memory.total, args.memory.used and args.memory.free, in bytes
  • args.machine.cores, args.machine.cpu and args.machine.pointer_bits
  • args.cpu.architecture and args.cpu.features, what the processor can run
  • args.system.distribution and args.disk.free
  • args.float.decimal, how many digits a float keeps after the point

Most rows are gathered once, when satl starts. A few, such as memory.used and memory.free, are read fresh every time you ask, so they tell you what the machine is using right now.

machine.satlSATELLITE 004 Download
A few of satl's settings and the machine's facts, on a 64-bit PC
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    satellite.console.display(args.version)
    satellite.console.display(args.revision)
    satellite.console.display(args.float.decimal)
    satellite.console.display(args.memory.used > 0)
    satellite.console.display(args.machine.pointer_bits)
    satellite.console.display(args.cpu.features.contains("sse2"))
    satellite.console.display(satellite.library.main.arguments.machine.pointer_bits)
    satellite.return(satellite)
}
OUTPUT
4
8
128
true
64
true
64

args.cpu.features is a list, so every list word works on it. The last line shows that the same facts are also words of the language, spelled in full: satellite.library.main.arguments.machine.pointer_bits needs no variable at all.

satl --debug greet.satl mum dad prints every row as satl starts, with the program’s own words among them. It is a quick way to see what your machine says.

Rows of your own

A row whose name is your own can be written, just like a variable. args.score = 5 adds a row, and a second args.score = 6 changes it. A row can hold a list too.

notes.satlSATELLITE 004 Download
Add rows of your own and change them
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    args.score = 5
    args.score = args.score + 1
    satellite.console.display(args.score)

    args.visitors = satellite.container.list()
    args.visitors.append("ann")
    args.visitors.append("bo")
    satellite.console.display(args.visitors)
    satellite.console.display(args.visitors[2])
    satellite.return(satellite)
}
OUTPUT
6
{"ann", "bo"}
bo

A row that satl holds, such as username, memory.total, argument_1 or float.decimal, is read and never written. The machine, the command line or your settings file says what it is, and a line that tries to write one is refused before the program runs:

rename.satlSATELLITE 004 Download
A row satl holds cannot be written
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    args.username = "someone else"
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S220: WORD_TAKES_NO_ASSIGNMENT
satl(check): in satellite.main, args.username is a row satl holds, and a program
reads it but does not write it -- the machine, the command line or config.ini
says what it is. A name of the program's own is written: args.my_username = ...

directory: rename.satl:5
syntax: args.username = "someone else"
        /\

this is not a place a program can write: a word that is not a setting and not a
variable, or a row of the arguments that the machine, the command line or
config.ini says -- a program reads it, and gives a name of its own a value
instead.
machine code 35 word_takes_no_assignment -- satl exits with this.

--------------------------------------------------------------------------------

Changing satl’s settings: config.ini

satl’s settings that you may change live in a plain text file of your own, ~/.satl/config.ini: one key = value a line, with # for a comment. The rows satl reads from it today include float.whole and float.decimal, the digits a float keeps before and after its point, directory.default, the folder satl’s own console starts in, and the switch access.

config.iniTEXT Download
~/.satl/config.ini: a comment, then two settings
# keep 64 digits after a float's point instead of 128
float.decimal = 64
access = true

Save the file, and the next program you run reads args.float.decimal as 64 and keeps floats to 64 digits. A missing config.ini is fine: satl prints a notice, S010, and uses its built-in settings. satl --rebuild writes one for you.

access is the one setting a program can also write: args.access = satellite.bool.false rewrites that row in your config.ini, and leaves every other line of the file as it was. That change lasts after the program ends, so only write it when you mean it. HISTORY AND ACCESS says what the switch is for.

Where next

Every row satl holds is listed in the FULL REFERENCE. For how to start satl with words after the file name, and its other options, see THE SATL COMMAND.

HISTORY AND ACCESS 0

HISTORY AND ACCESS

satl’s own help lists two topics that let you look at your program’s names: satellite.access, “on by default, type/value for last instance”, and satellite.history, “off by default, record of everything”. This post shows where each stands in satellite 004. satellite.access(name) works. satellite.history(name) is not built yet, and satl refuses it. Both have switches, settings that say whether each one is on or off.

Asking about a name: satellite.access

satellite.access(name) tells you what a name is, what it holds now, and the exact code to reach into it, worked out from the name’s declaration. A line that is nothing but satellite.access(name) prints it. Anywhere else it answers the same text as a string, so satellite.console.display(satellite.access(name)) prints it too, and a program can keep it.

ask_access.satlSATELLITE 004 Download
What a name is, what it holds, and how to reach into it
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.number score = 10
    satellite.access(score)

    satellite.container.map<satellite.variable.string, satellite.container.list<satellite.variable.number>> scores = {"ann": {7, 9}, "bo": {4}}
    satellite.access(scores)
    satellite.return(satellite)
}
OUTPUT
score is a number
  value  10
scores is a map (string -> list of numbers), 2 keys
  value                    {"ann": {7, 9}, "bo": {4}}
  scores["key"]            a list of numbers, "key" a string, one of "ann", "bo"
  scores["key"][n]         a number, n counting from 1
  scores["key"] = {1}      puts a list of numbers under "key"
  scores["key"].append(1)  adds a number
  scores.size              how many keys it holds
  scores.keys              the keys of it, as a list

For a container it shows one line for every level you can reach, with n, m and so on standing for positions (which count from 1) and "key" for a key. Then it shows a line that fills each level, with a value of the right shape written out, and .size and .keys. Every one of those lines is real code: satl’s own tests run each line satellite.access prints, for thousands of container shapes. For an object of a spacesuit, it shows the object’s fields and their values, and the capsules you can call on it. The name must be one the line can see; anything else in the brackets is refused before the program runs. ANY CONTAINER IN ANY CONTAINER uses it on deeper shapes.

Asking about the past: satellite.history, not built yet

satellite.history(name) is refused before your program runs. satl checks the whole file first, so nothing is printed before the report.

ask_history.satlSATELLITE 004 Download
satellite.history(name) is refused today
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.number score = 10
    satellite.console.display(satellite.history(score))
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S110: LINE_NOT_UNDERSTOOD
satl(check): in satellite.main, no capsule named history

directory: ask_history.satl:6
syntax: satellite.console.display(satellite.history(score))
        /\

satellite has no scenario for this line -- it is spelled in a shape the language
does not have a meaning for.
machine code 13 satl_line_not_understood -- satl exits with this.

--------------------------------------------------------------------------------

The access switch

The access switch is built, and a program can read it. Its full name is satellite.library.main.arguments.access. It is a word the language owns, so it starts with satellite. It is also a row of the arguments variable, so a main that asks for that variable can read it short, as args.access. It is true unless you have turned it off.

access_switch.satlSATELLITE 004 Download
Read the access switch, by its full name and as a row
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    satellite.console.display(satellite.library.main.arguments.access)
    satellite.console.display(args.access)
    satellite.statement.if (satellite.library.main.arguments.access)
    {
        satellite.console.display("access is on")
    }
    satellite.return(satellite)
}
OUTPUT
true
true
access is on

The switch lives in your settings file, ~/.satl/config.ini, as the row access = true or access = false. With no row, it reads true. A program can write it too: satellite.library.main.arguments.access = satellite.bool.false rewrites that row and leaves every other line of the file as it was. Only satellite.bool.true and satellite.bool.false are accepted. Writing it is a lasting change to your settings, not just to one run.

The switch is for a store that is not built yet: the last value of every name, kept so you could ask about it after the program has stopped. Until that store exists, the switch changes nothing, and satellite.access(name) works whatever it says.

The history switch

History’s switch is a row in the same file, history = true or history = false. A missing row means false. A program cannot read or write it yet: reading satellite.library.main.arguments.history stops with “there is no value here to work with”, and writing it is refused before the program runs.

satl –rebuild and the feature register

What satl acts on when it starts is not those rows but one line in the same file that sums up every switch, features = b.... satl --rebuild writes that line from the rows. Run it after you change a switch by hand:

BASH Download
Fold the switches in config.ini into one line
satl --rebuild

It prints a table of every switch, whether it is on, and whether it is built yet. With access = true and history = true in config.ini, it prints, among its other lines:

OUTPUT
    bit  feature              state     built  what it does
    ---  -------------------  --------  -----  ------------------------------------
      0  access               ON        yes    keep the last known name, type and value of everything
      1  history              ON        NO     write every value a name ever held to disk

    turned on but NOT BUILT YET, so nothing will happen:
        history

The “yes” beside access means the switch itself is built; the store it will turn on is not. If you change a row and forget to run satl --rebuild, every run prints a notice, S011 REGISTER_IS_STALE, and keeps using the old line until you do. Nothing breaks: it is a reminder.

Where next

The FULL REFERENCE marks what is built and what is not. The arguments variable, which carries the access switch as a row, is in THE ARGUMENTS VARIABLE, and help on any part of the language is in THE HELP SYSTEM.

THE HELP SYSTEM 3

THE HELP SYSTEM

satellite carries its own help. You ask for it at the satl prompt, the place where you type one line and see it run straight away, and it answers with a page of plain text about one part of the language: what it is, the rules, and an example program.

Opening the prompt and asking

Start the prompt with satl --repl. Then type satellite.help() on a line of its own to see every topic there is:

BASH Download
Start the satl prompt
satl --repl
TEXT Download
Then type, at the prompt
satellite.help()
OUTPUT
--------------------------------------------------------------------------------
 THE SATELLITE HELP SYSTEM
--------------------------------------------------------------------------------
 usage: type satellite.help(include) or satellite.help(satellite.include)
 to bring up info on including other files
TOPICS:

1) satellite.include (other files)

2) satellite.help (the help system)

3) satellite.capsule (functions)

The list goes on through 28 topics, from numbers and strings to spacesuits, windows and the terminal. To read one, put its name between the brackets. You can name a topic in several ways:

  • by its whole name: satellite.help(satellite.include)
  • by its last part: satellite.help(include) finds the same topic
  • by a second spelling: satellite.help(colour) finds satellite.variable.color, and satellite.help(double) finds satellite.variable.float
  • by the start of its last part: satellite.help(percentage) finds satellite.variable.percent

satellite.help(help) brings up the help system’s own page. exit, quit or Ctrl-D leaves the prompt.

When a name fits two topics, or none

Two topics end in window, so satl will not guess which one you meant. It names both and lets you choose:

TEXT Download
Asking for a topic two topics answer to, and one that does not exist
satellite.help(window)
satl(prompt): window is more than one topic -- write satellite.help(satellite.variable.window) or satellite.help(satellite.window)
satellite.help(unicorns)
satl(prompt): there is no help on unicorns yet -- satellite.help() lists the topics there are

Help is for the prompt, not for a program

satellite.help is something you ask satl, not a statement your program runs. Written inside a program, it is refused before the program starts:

ask_for_help.satlSATELLITE 004 Download
satellite.help inside a program is refused
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.help(library)
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S210: NOT_BUILT_YET
satl(check): in satellite.main, satellite.help has no library built for it yet

directory: ask_for_help.satl:5
syntax: satellite.help(library)
        /\

this word is numbered in the language and the library behind it does not exist
yet. The word is right; there is nothing yet to run.
machine code 14 not_built_yet -- satl exits with this.

--------------------------------------------------------------------------------

At the prompt it also has to be the whole line: satellite.console.display(satellite.help()) is refused, and satl says that help is written on a line of its own.

Every topic ends in a program you can run

Each topic finishes with an example. The examples are real programs: save one as a .satl file and run it with satl. This is the example from satellite.help(library):

rounds.satlSATELLITE 004 Download
The example program from the library topic
satellite.include(satellite)

satellite.library.rounds = 4
satellite.library.label = "rounds counted"

satellite.capsule satellite.main()
{
    satellite.variable.number count = 0
    satellite.statement.while (count < satellite.library.rounds)
    {
        count = count + 1
    }
    satellite.console.display(satellite.library.label)
    satellite.console.display(count)
    satellite.return(satellite)
}
OUTPUT
rounds counted
4

Comments in an example, such as // 42, often show what a line prints, so you can check your run against the page.

Help is plain text, and it is yours

Every topic is a plain text file, read at the moment you ask for it and never built into satl. That means you can open them, read them in any editor, and change them. The next time you ask, you get your version.

The files live in a folder named satellite.help:

  • satellite.help/help.txt is the list that satellite.help() prints.
  • Each topic is a folder named after it, holding a file called help_text.txt. The include topic is satellite.help/satellite.include/help_text.txt.
  • A new folder is a new topic. Make satellite.help/my_notes/help_text.txt, and satellite.help(my_notes) shows it. Add a line to help.txt if you want it in the list too.

satl looks for the satellite.help folder beside the satl program, or one folder up from it. If it finds neither, it tells you so and names both places it looked:

TEXT Download
What the prompt says when the help folder is not beside satl
satellite.help(include)
satl(prompt): the help files are not beside satl -- looked in ~/.satl/satellite.help and ~/.satl/../satellite.help

Where next

The FULL REFERENCE collects the whole language on one page. For the prompt and satl’s other options, see THE SATL COMMAND. The library example above is explained in SATELLITE.LIBRARY.

THE SATL COMMAND 0

THE SATL COMMAND

satl is the satellite interpreter: the program that reads a .satl file and runs it. Most of the time you only need one way to start it, satl hello.satl. This post covers the rest: the banner, the words you can hand a program, the prompt, satl’s own console window, and the options that do other jobs.

Running a program

Give satl the file, and it checks the whole program and then runs it:

hello.satlSATELLITE 004 Download
The program the rest of this post runs
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.console.display("hello")
    satellite.return(satellite)
}
OUTPUT
hello

In a terminal, satl hello.satl shows four lines before hello. This is the banner:

TEXT Download
The banner satl prints as it starts
THE SATELLITE PROGRAMMING LANGUAGE
VERSION 004 REVISION 08 BUILD 0043
CLANG++ 24 ALMALINUX 10.2
---------------------------------------------------------------

The second line is the version, the revision and the build number of the satl you are running. The third names the compiler that built it and the system it was built on, so yours may read differently.

The banner goes to the terminal’s error stream, not to its normal output. Your program’s output stays exactly what your program printed, which matters when you save it to a file or hand it to another program. To see the output alone, send the error stream away:

BASH Download
Run hello.satl without the banner
satl hello.satl 2> /dev/null

Handing words to a program

Everything after the file name belongs to the program, even words that look like satl’s own options. The program reads them through the arguments variable.

echo_words.satlSATELLITE 004 Download
Show every word the program was given
satellite.include(satellite)

satellite.capsule satellite.main(satellite.variable.arguments args)
{
    satellite.console.display(args.program + " was given " + (args.length - 1).to_string() + " words")
    satellite.statement.for(satellite.variable.number i = 1; i < args.length; i++)
    {
        satellite.console.display(args["argument_" + i.to_string()])
    }
    satellite.return(satellite)
}
OUTPUT
echo_words.satl was given 0 words
BASH Download
Two words that look like options go to the program
satl echo_words.satl --version --debug
OUTPUT
echo_words.satl was given 2 words
--version
--debug

Every option

satl --help lists these, and it is the one to trust if this page and your satl ever disagree:

  • satl on its own prints the banner and three lines on how to start.
  • satl <file.satl> [words...] runs a program, handing it the words.
  • satl --run <file> [words...] does the same, for a file whose name begins with -.
  • satl --debug <file.satl> [words...] runs it and shows every state and every argument as satl starts.
  • satl --repl opens the prompt: type a line, see it run.
  • satl --console [file.satl] [words...] does the same in a console window of satl’s own: the program, or with no file, the prompt.
  • satl --rebuild folds the switches in your ~/.satl/config.ini into the one line satl reads when it starts.
  • satl --config [most] measures, once, what this machine can do, such as how many threads it can hold, and keeps the answer for later runs.
  • satl --feedback shows what satellite.feedback has kept on this machine.
  • satl --license [n|name|all] shows the licences: satellite’s own, and those of the projects built into satl. --licence, --licenses and --licences work too.
  • satl --version or -V shows the version, revision and build.
  • satl --help or -h shows the list.

--debug and --console come before the file, --run or --repl. --version and --help must be the whole command line. A word satl does not know is refused, and it names the word:

TEXT Download
A mistyped option
satl --rum hello.satl
[satellite] satl(command line): "--rum" is not a word satl takes (a file whose name begins with - runs as satl --run --rum) -- satl --help lists every way to start satl (machine_code: 23 command_line_not_understood)

How a run ends: the exit status

When a program runs to its end, satl exits with 0. When something stops it, satl prints a report and exits with the report’s machine code, so a script that runs satl can tell what happened.

stop.satlSATELLITE 004 Download
A program that stops, and the code satl exits with
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.container.list<satellite.variable.number> scores = {7, 9}
    satellite.console.display(scores[3])
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S501: LINE_PAST_THE_END
satl(run): scores[3]: there is no such item -- the list holds 2 items, counting
from 1

directory: stop.satl:6
syntax: satellite.console.display(scores[3])
                                        /\

a line was read by its number and the file has no line with that number. Lines
count from 1, and the last one is the file's size.
machine code 47 line_past_the_end -- satl exits with this.

--------------------------------------------------------------------------------

The last line of the report says it: machine code 47. In a terminal, echo $? straight afterwards prints 47. A code that does not fit an exit status is written in full and satl exits 255. READING AN ERROR REPORT goes through a report line by line.

The prompt

satl --repl opens the prompt. It greets you with one line of instructions, then shows three things in square brackets, satellite, your user name and the folder you are in, followed by >>. Type a statement and press Enter, and it runs at once:

TEXT Download
A short session: each line typed at the prompt, and what satl answers
satellite.console.display(6 * 7)
42
run hello.satl
THE SATELLITE PROGRAMMING LANGUAGE
VERSION 004 REVISION 08 BUILD 0043
CLANG++ 24 ALMALINUX 10.2
---------------------------------------------------------------

hello
exit

The prompt runs a statement a line, and keeps what you declare until you leave: a variable declared on one line is there on the next.

It takes a whole block too. Type a line that opens one — satellite.capsule twice(satellite.variable.number n), satellite.statement.if(x > 3), a while or a for — and press Enter, and the prompt writes the { for you and starts the next line one step in. Type the body, then } (it steps back under the line that opened the block). A spacesuit gets more: satellite.spacesuit dog() and Enter writes its {, satellite.constructor() and the constructor’s {, and after each } you type it writes the next section, satellite.protected and then satellite.public, each with its {. What a block declares — a capsule, a spacesuit — is kept for the session, so later lines can call it or make objects of it. An if, a while or a for runs as soon as its last } is typed; an if waits for one more line, in case it is an else.

TEXT Download
Declaring a capsule at the prompt, and calling it
satellite.capsule twice(satellite.variable.number n)
... {
...     satellite.return(n * 2)
... }
satellite.console.display(twice(21))
42

run hello.satl, or interpret hello.satl, runs a whole program just as satl hello.satl would, banner and all. exit, quit or Ctrl-D leaves. The prompt is also where you ask for help: see THE HELP SYSTEM.

satl’s own console window

satl can open a console window of its own, so it works even where there is no terminal. satl --console hello.satl runs the program in that window, and satl --console with no file opens the prompt there.

satl also opens its console by itself when it is started with no terminal to write to, for example by double-clicking a .satl file or choosing satellite from a menu, as long as there is a screen to show a window on. If the output is going to a file or into another program, satl writes there instead and opens nothing.

When a program ends cleanly, its console closes. When it stops on an error, the window stays open with the report, and a last line says which machine code it stopped on and to press any key to close. A prompt session in the console ends the same way, with “the session is over — press any key to close”.

The options that print something and exit, --rebuild, --config, --feedback and --license, do not take --console: run them in a terminal. A script or a launcher that must never get a window can set the environment variable SATL_NO_WINDOW=1, and satl then never opens a console by itself.

Where next

The FULL REFERENCE lists everything satl understands. The words a program is handed are covered in THE ARGUMENTS VARIABLE, and installing satl is on the INSTALL page.

DISPLAYING TEXT 9

DISPLAYING TEXT

Almost every program you write will show something to the person running it. In satellite that is one word: satellite.console.display. It writes one line to the screen, and it is the first word most people learn.

The name follows satellite’s one big rule. A dotted path that starts with satellite names something the language owns: satellite.console is the console, and .display is what it does. A bare name, like apples or greeting, is something you own.

One value, any kind

satellite.console.display takes one value in its brackets and shows it on a line of its own. The value can be any kind: text is shown as it is, a number as its digits, a comparison as true or false, and a list with its curly brackets and commas.

show_anything.satlSATELLITE 004 Download
Display shows every kind of value
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.number apples = 4
    satellite.console.display("hello")
    satellite.console.display(apples)
    satellite.console.display(apples + 1)
    satellite.console.display(apples > 3)
    satellite.console.display(3.5)
    satellite.console.display(50%)
    satellite.console.display({1, "two", 3})
    satellite.console.display("")
    satellite.console.display("an empty string makes an empty line")
    satellite.return(satellite)
}
OUTPUT
hello
4
5
true
3.5
50%
{1, "two", 3}

an empty string makes an empty line

Notice that apples + 1 is worked out first, and then the answer is shown. Whatever you put in the brackets is a value, and display shows the value.

Staying on the same line with end=

Each display ends its line, so the next display starts on a new one. When you want to keep going on the same line, add end= after the value. What you give it is written instead of the line ending. end="" writes nothing at all, and end=" " writes a space.

countdown.satlSATELLITE 004 Download
end= keeps the next display on the same line
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.statement.for(satellite.variable.number i = 5; i > 0; i - 1)
    {
        satellite.console.display(i, end=" ")
    }
    satellite.console.display("lift off!")
    satellite.console.display("Loading", end="...")
    satellite.console.display(" done")
    satellite.return(satellite)
}
OUTPUT
5 4 3 2 1 lift off!
Loading... done

The countdown’s numbers share one line because each ends with a space instead of a line break. The last display, "lift off!", has no end=, so it finishes the line.

Several values on one line

Display takes exactly one value. To show several things together, join them into one string with + first. Satellite never converts a value behind your back, so a number joins text only once you turn it into text yourself, with .to_string(). The other way is several displays, each with end=, and a last one to finish the line.

introductions.satlSATELLITE 004 Download
Two ways to put several values on one line
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string name = "Ada"
    satellite.variable.number age = 36
    satellite.console.display(name + " is " + age.to_string() + " years old")
    satellite.console.display(name, end=" is ")
    satellite.console.display(age, end=" years old")
    satellite.console.display("")
    satellite.return(satellite)
}
OUTPUT
Ada is 36 years old
Ada is 36 years old

If you hand display two values separated by a comma, satl refuses the program before a single line runs, and tells you why:

two_values.satlSATELLITE 004 Download
display takes one value, not two
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.console.display("one", "two")
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S110: LINE_NOT_UNDERSTOOD
satl(check): in satellite.main, satellite.console.display takes one argument,
and was given 2

directory: two_values.satl:5
syntax: satellite.console.display("one", "two")
        /\

satellite has no scenario for this line -- it is spelled in a shape the language
does not have a meaning for.
machine code 13 satl_line_not_understood -- satl exits with this.

--------------------------------------------------------------------------------

The same goes for joining text and a number without .to_string(): that is refused too, with S301, rather than guessed at.

Things worth knowing

  • \n is a new line inside a string, and \t a tab: "one\ntwo" shows two lines. The six escapes are \" \\ \n \t \r and \'; any other backslash stays in the text as you wrote it. A separate display, or end=, controls lines too.
  • Your output is yours alone. The title block satl prints when it starts goes to standard error, and what your program displays goes to standard output. So you can save exactly what your program printed into a file:
BASH Download
satl countdown.satl > countdown.txt
  • Display can add colour and style. After the value it also takes foreground=, background=, bold= and italic=. They are covered in COLOR ON THE CONSOLE. Into a file or a pipe, like the one above, the text always goes plain.

Where next

Every option display takes is listed in the FULL REFERENCE. To let the person answer back, read READING INPUT, and for the text itself, STRINGS.

READING INPUT 0

READING INPUT

A program that only talks is half a conversation. satellite.console.input is the other half: it waits for the person at the keyboard to type a line and press Enter, then hands that line to your program as a string.

Asking a question

Put a prompt in the brackets, and satl writes it with no line break after it, so the cursor waits right beside your question. The answer comes back as a satellite.variable.string, without the Enter at the end. Leave the brackets empty, satellite.console.input(), and it waits without writing a prompt.

This program waits for the keyboard, so it has no output box:

greet.satlSATELLITE 004 Download
Ask for a name and answer it
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string name = satellite.console.input("What is your name? ")
    satellite.console.display("Hello, " + name + "!")
    satellite.return(satellite)
}

At a terminal, typing Ada and pressing Enter looks like this:

TEXT Download
What is your name? Ada
Hello, Ada!

The prompt also takes the same style options as display: foreground=, background=, bold= and italic=. So satellite.console.input("Your move? ", foreground=xFF8800, bold=satellite.bool.true) asks in bold orange. COLOR ON THE CONSOLE has the details.

Turning an answer into a number

What a person types is always text, even when it is digits. Satellite never converts a value behind your back, so "41" + "1" joins two strings into "411". To do arithmetic, read the number out of the text first with .number:

text_to_number.satlSATELLITE 004 Download
Text is text until you ask for its number
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string typed = "41"
    satellite.console.display(typed + "1")
    satellite.variable.number n = typed.number
    satellite.console.display(n + 1)
    satellite.return(satellite)
}
OUTPUT
411
42

.number reads a whole number: an optional minus sign, then digits. Anything else is refused rather than guessed at, and the report says what happened:

not_a_number.satlSATELLITE 004 Download
Words are not a number
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string typed = "forty-two"
    satellite.console.display(typed.number)
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S120: NUMBER_NOT_READ
satl(run): typed.number: that text is not a whole number this can read

directory: not_a_number.satl:6
syntax: satellite.console.display(typed.number)
        /\

this is not a number satellite can read. A number is an optional '-' then
digits, with no spaces or separators, and a float has one point in it: 12.34.
machine code 3 int_error -- satl exits with this.

--------------------------------------------------------------------------------

Putting both together, you can read the number straight off the call. Again, this one waits for the keyboard:

add_two.satlSATELLITE 004 Download
Add two numbers the person types
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.number first = satellite.console.input("first number: ").number
    satellite.variable.number second = satellite.console.input("second number: ").number
    satellite.console.display("together they make " + (first + second).to_string())
    satellite.return(satellite)
}

Input from a file or a pipe

satellite.console.input reads standard input, so the lines do not have to come from a keyboard. You can pipe them in, which is handy for testing a program without typing the same answers again and again:

BASH Download
printf '12\n30\n' | satl add_two.satl
OUTPUT
first number: second number: together they make 42

The prompts run together here because nobody typed anything: at a terminal, your own typing and the Enter key are what move the cursor to the next line.

When the input runs out

A piped file ends, and a person can press Ctrl-D to say “no more”. Either way there will never be another line, so satl stops with S830 INPUT_ENDED and exits with 55. It does not answer an empty line forever. Here is greet.satl again, run with nothing to read, as it is when you run satl greet.satl < /dev/null:

greet_nothing.satlSATELLITE 004 Download
With nothing to read, input stops the program
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string name = satellite.console.input("What is your name? ")
    satellite.console.display("Hello, " + name + "!")
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S830: INPUT_ENDED
satl(run): in name = ..., satellite.console.input(prompt) waited for a line, and
the input has ended

directory: greet_nothing.satl:5
syntax: satellite.variable.string name = satellite.console.input("What is your name? ")
                                                                                       /\

satellite.console.input() waited for a line and the input has ended -- a file
piped in ran out, or Ctrl-D was pressed. There will never be another line, so
this stops rather than answering an empty one forever.
machine code 55 input_ended -- satl exits with this.

--------------------------------------------------------------------------------

An empty line is different: a person pressing Enter on its own gives your program the empty string "", and the program carries on.

Where next

Every console word is in the FULL REFERENCE. To keep asking until the person is done, see IF, WHILE AND FOR, and for what you can do with the text you get back, STRINGS.

COLOR ON THE CONSOLE 1

COLOR ON THE CONSOLE

Plain text gets the job done, but colour makes a program easier to read at a glance: green for “it worked”, orange for “careful”. Satellite gives you three ways to colour what your program shows, plus a few words about the screen itself.

A colour is written as six hex digits after an x, two each for red, green and blue: xFF0000 is red, x00FF00 is green, xFF8800 is orange. You can also keep one in a satellite.variable.color (or satellite.variable.colour, both spellings work) and use its name. COLORS explains colours in full.

The output boxes on this page show plain text. When satl writes into a pipe or a file, as it does when these examples are checked, the colours are left out and only the words go through. At a terminal, you see the colours.

Styling one line

satellite.console.display takes named options after the value, each written name=value:

  • foreground= the colour of the text
  • background= the colour behind it
  • bold=satellite.bool.true and italic=satellite.bool.true

The style lasts for that one line, and the next line is plain again.

styled_lines.satlSATELLITE 004 Download
One line in orange and bold, one in a colour held by name
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.console.display("careful", foreground=xFF8800, bold=satellite.bool.true)
    satellite.variable.color sky = x87CEEB
    satellite.console.display("a clear day", foreground=x000000, background=sky)
    satellite.console.display("a thought", italic=satellite.bool.true)
    satellite.console.display("and this line is plain")
    satellite.return(satellite)
}
OUTPUT
careful
a clear day
a thought
and this line is plain

A colour written straight into the line must be six hex digits. foreground=xFFF or foreground="red" is refused with S301 before a single line of the program runs, so a typo never waits until halfway through to show itself.

Colouring one word

Sometimes only one word should stand out. A string has its own .foreground(c) and .background(c), which answer the same string in that colour. Join it into a line like any other string:

status.satlSATELLITE 004 Download
Only the OK is green
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.string ok = "OK".foreground(x00FF00)
    satellite.console.display("status: " + ok)
    satellite.variable.color warning = xFF8800
    satellite.console.display("disk: " + "nearly full".foreground(warning))
    satellite.console.display(ok == "OK")
    satellite.return(satellite)
}
OUTPUT
status: OK
disk: nearly full
false

Why is the last line false? Because the colour is really part of the string. It is stored as the terminal’s own colour codes around the letters, so ok is not the same two letters as "OK". Display leaves those codes out when it writes into a pipe or a file, or when the NO_COLOR setting is on. A string you save into a file yourself keeps them, so colour your words at the moment you show them.

Colouring every line after

satellite.console.foreground(c) sets the colour for every line display writes from then on, and satellite.console.background(c) does the same behind the text. Written with empty brackets, satellite.console.foreground() puts the terminal’s own colour back. A line’s own foreground= still wins while it is set.

green_console.satlSATELLITE 004 Download
Every line green until you say stop
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.console.foreground(x33FF33)
    satellite.console.display("every line is green now")
    satellite.console.display("this one too")
    satellite.console.display("except this one", foreground=xFF0000)
    satellite.console.foreground()
    satellite.console.display("and back to normal")
    satellite.return(satellite)
}
OUTPUT
every line is green now
this one too
except this one
and back to normal

This colours your program’s lines. To change the colours of the whole terminal window, empty rows included, see THE TERMINAL.

The screen: width, height, clear and home

satellite.console.width and satellite.console.height, with no brackets, answer how many characters fit across the terminal and how many lines fit down it. They are asked fresh every time, so they follow the window when someone resizes it. When there is no terminal, they answer 80 and 24, which is what the example below shows because it was checked without one:

screen_size.satlSATELLITE 004 Download
How big is the screen?
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.number across = satellite.console.width
    satellite.variable.number down = satellite.console.height
    satellite.console.display("the screen is " + across.to_string() + " characters across")
    satellite.console.display("and " + down.to_string() + " lines down")
    satellite.return(satellite)
}
OUTPUT
the screen is 80 characters across
and 24 lines down

Two more words move things on the screen:

  • satellite.console.clear() empties the screen and puts the cursor in the top-left corner.
  • satellite.console.home() only moves the cursor to the top-left corner and leaves the screen as it is, so the next thing you display is drawn over the last.

Both write the terminal’s own codes for this, even when the output goes into a file.

Where next

Every option and colour word is in the FULL REFERENCE. For more on display itself, read DISPLAYING TEXT, and for colour values, COLORS.

THE TERMINAL 1

THE TERMINAL

When you run a satellite program, it runs inside a terminal: the window around the text. That might be the terminal program you use every day, or the console window satl opens by itself. In satellite, that window is satellite.terminal.

It is a different thing from satellite.console. The console is the stream of lines your program writes and reads. The terminal is the window they appear in. So satellite.console.foreground colours your program’s lines, and satellite.terminal.foreground colours the terminal itself.

Changing the terminal’s colours

satellite.terminal.foreground(c) and satellite.terminal.background(c) change the terminal’s own colours. That means everything drawn in its default colour, and the empty rows too, not only the lines written after them. A colour is six hex digits, like x101010, or a satellite.variable.color held by name.

night_mode.satlSATELLITE 004 Download
Green text on near-black, for the whole window
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.terminal.background(x101010)
    satellite.terminal.foreground(x33FF33)
    satellite.console.display("green on near-black, the whole terminal")
    satellite.console.display("and your own colours come back when this ends")
    satellite.return(satellite)
}
OUTPUT
green on near-black, the whole terminal
and your own colours come back when this ends

The output box shows only the words. The colours are a change to the terminal, not to the text, so they never appear in what your program prints.

Putting the colours back

Write the same words with empty brackets, satellite.terminal.foreground() and satellite.terminal.background(), and the terminal’s own colours come back straight away. Here the colours live in names, so they are easy to change in one place:

reading_lamp.satlSATELLITE 004 Download
Set the colours from names, then put them back
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.color paper = xFFF8E7
    satellite.variable.color ink = x3B2F2F
    satellite.terminal.background(paper)
    satellite.terminal.foreground(ink)
    satellite.console.display("dark ink on warm paper")
    satellite.terminal.foreground()
    satellite.terminal.background()
    satellite.console.display("your own colours again")
    satellite.return(satellite)
}
OUTPUT
dark ink on warm paper
your own colours again

You do not have to remember to do this. satl puts back whatever it changed when the program ends, however it ends: when it finishes, when it stops on an error, when you press Ctrl-C, or when it crashes. A program never leaves your shell orange.

One thing to know: “back” means the colours from your terminal’s own settings. If your shell had already changed the terminal’s colours in the same way, satl does not remember that change, and you get the terminal’s settings instead.

When nothing changes

The terminal is only touched when there is one to touch:

  • When your program’s output goes into a pipe or a file, satl does not change any colours. That is why the examples on this page could be checked without a terminal at all.
  • When the NO_COLOR setting is on, satl leaves the terminal’s colours alone.

A colour that is not a colour

A colour must be six hex digits or a colour held by name. Text is refused before the program starts, so nothing is half changed:

orange_words.satlSATELLITE 004 Download
A colour's name in words is not a colour
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.terminal.foreground("orange")
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S301: TYPES_DO_NOT_MEET
satl(check): in satellite.main, satellite.terminal.foreground takes a colour --
six hex digits like xFF8800, or a satellite.variable.color -- and was given text

directory: orange_words.satl:5
syntax: satellite.terminal.foreground("orange")
        /\

this operator has no scenario for the two kinds it was given. Nothing was
guessed at, because a guess here is an answer that is wrong and does not say so.
machine code 27 types_do_not_meet -- satl exits with this.

--------------------------------------------------------------------------------

satl’s own console

If you start a program without a terminal, for example from a desktop launcher, satl opens a console window of its own to run it in. You can also ask for one:

BASH Download
satl --console night_mode.satl

That console is a terminal like any other, so satellite.terminal colours it the same way. Your program’s input and output are that window, and when the program finishes, the window closes. If a program stops on an error, the window stays open and says so, so you can read the report, and closes when you press a key. Setting SATL_NO_WINDOW stops satl from opening a console by itself.

Where next

Every terminal and console word is in the FULL REFERENCE. To colour single lines and words instead of the whole window, read COLOR ON THE CONSOLE, and for everything the satl command can do, THE SATL COMMAND.

FILES 0

FILES

Programs forget everything when they end, unless they write it down. Satellite’s files are built on one simple idea: a text file is a list of lines that lives on the disk. Line 1 is the first line, each line is a string, and most of what you can do to a list you can do to a file, spelled the same way.

A file is held in a satellite.variable.file. You get one from satellite.file.new or satellite.file.open, and after that you work through its name.

Making a file and reading it back

  • satellite.file.new("name.txt") makes a new, empty text file and opens it. It never replaces a file that is already there.
  • f.append("text") adds a line at the end.
  • f[n] reads line n, counting from 1. f.first and f.last read the first and last lines, and f.size says how many lines there are.
  • f.close() saves and closes the file, and answers true when the changes reached the disk.
shopping.satlSATELLITE 004 Download
Write three lines, then read them back
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file shopping = satellite.file.new("shopping.txt")
    shopping.append("bread")
    shopping.append("milk")
    shopping.append("eggs")
    satellite.console.display(shopping.size)
    satellite.console.display(shopping[1])
    satellite.console.display(shopping.last)
    satellite.console.display(shopping.close())
    satellite.return(satellite)
}
OUTPUT
3
bread
eggs
true

After this runs, shopping.txt sits beside the program with bread, milk and eggs on three lines. A path without a / at the front is found in the folder of the .satl file that uses it, wherever you ran satl from.

Opening a file and changing it

satellite.file.open("name.txt") opens a text file that is already there. These change its lines:

  • f.insert(n, "text") puts a new line in as line n, and everything from there down moves down one.
  • f.replace(n, "text") makes line n say something else.
  • f.replace("old", "new") changes the first place old appears in the file into new. A number first means a line, and text first means text.
  • f.remove_at(n), f.remove("a line"), f.remove_first(), f.remove_last(), f.truncate(n) and f.clear() take lines out.

And these find things without changing anything:

  • f.index_of("a line") answers the number of the first line that is exactly that text, and f.search("text") the first line that contains it anywhere. When nothing matches, both answer 0, which is never a line.
  • f.contains("a line") answers true or false.
  • f.read_all answers the whole file as one string, line endings included.

To walk every line, count from 1 up to f.size:

shopping_edit.satlSATELLITE 004 Download
Make a file, open it again, change it and walk it
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file shopping = satellite.file.new("shopping.txt")
    shopping.append("bread")
    shopping.append("milk")
    shopping.append("eggs")
    shopping.close()

    satellite.variable.file again = satellite.file.open("shopping.txt")
    again.insert(2, "butter")
    again.replace(1, "brown bread")
    again.replace("milk", "oat milk")
    satellite.console.display(again.search("milk"))
    satellite.console.display(again.index_of("cheese"))
    satellite.console.display(again.contains("butter"))
    satellite.statement.for(satellite.variable.number i = 1; i <= again.size; i + 1)
    {
        satellite.console.display(i.to_string() + ". " + again[i])
    }
    satellite.return(satellite)
}
OUTPUT
3
0
true
1. brown bread
2. butter
3. oat milk
4. eggs

Notice there is no again.close() at the end. Satellite saves and closes every file that is still open when the program ends, so forgetting to close loses nothing. You can also save part way through with f.save().

A save is whole or not at all. Satellite writes the new version beside the old one and swaps it in, so if the program is stopped in the middle of a save, the file holds either the old lines or the new ones, never a mixture.

When a file will not open

Opening or making a file never stops your program. Instead, the file you get back is not open, and you can ask it:

  • f.ok answers whether it is open.
  • f.error says why not, in words.
  • satellite.file.exists("name.txt") answers whether a file is there at all.
careful_opening.satlSATELLITE 004 Download
open never makes a file, and new never replaces one
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file missing = satellite.file.open("no_such_file.txt")
    satellite.console.display(missing.ok)
    satellite.console.display(satellite.file.exists("no_such_file.txt"))

    satellite.variable.file diary = satellite.file.new("diary.txt")
    diary.append("day one")
    diary.close()
    satellite.variable.file second = satellite.file.new("diary.txt")
    satellite.console.display(second.ok)

    satellite.variable.file reopened = satellite.file.open("diary.txt")
    satellite.console.display(reopened[1])
    satellite.return(satellite)
}
OUTPUT
false
false
false
day one

open never makes a file, so a misspelled name cannot quietly become an empty one. new never replaces one, so your diary survives: the second new came back not open, and the first day is still there.

What is refused

A few things stop the program, because any answer to them would be made up:

  • Reading a line that is not there, like line 2 of a one-line file, is S501 LINE_PAST_THE_END.
  • Asking about the lines of a file that is not open, like missing.size, is S503 FILE_NOT_OPEN. Check f.ok first.
  • A method a file does not have, such as f.write("text"), or the wrong number of arguments, such as f.replace(1), is refused before the program starts. To add a line, use append or insert.
past_the_end.satlSATELLITE 004 Download
Line 2 of a one-line file
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file notes = satellite.file.new("notes.txt")
    notes.append("the only line")
    satellite.console.display(notes[1])
    satellite.console.display(notes[2])
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S501: LINE_PAST_THE_END
satl(run): notes[2]: there is no such line -- the file has 1 line, counting from
1

directory: past_the_end.satl:8
syntax: satellite.console.display(notes[2])
        /\

a line was read by its number and the file has no line with that number. Lines
count from 1, and the last one is the file's size.
machine code 47 line_past_the_end -- satl exits with this.

--------------------------------------------------------------------------------

The first line was shown before the report. The file itself is safe: notes.txt was still saved with its one line.

Only text files are built today. Asking for a binary file, satellite.file.new("data.bin", "binary"), gives a file that is not open.

Where next

Every file word is in the FULL REFERENCE. Files behave like LISTS, and two threads can share one safely with a lock: see LOCKS: SHARING AN OBJECT BETWEEN THREADS.