loom
loom is the environment that runs compiled Luce. It opens a program, hands it the world, and gets out of the way. There is no engine inside it, no code generator, and no state of its own — ordinary files, the real terminal, and one honest boundary.
Luce is the language. luce is
its compiler. loom is where a Luce program is a program — the
thing you type at, the thing that starts it, and the thing it asks when it wants
to print a line or read a key.
Thirty seconds
Write a program, run it, look at what appeared beside it.
func main(args: list(string)):
print("hello, loom")
for name in args:
print(name)$ loom luce hello.luc world hello, loom world $ ls hello.lc hello.luc $ loom run hello.lc one two hello, loom one two
loom luce compiled the source and ran it. What it left behind —
hello.lc — is machine code: a tagged shared library.
loom run hello.lc is one dlopen, one symbol lookup, one
call. No compiler is consulted, nothing is decoded, and the second run does not
need the source file at all. It takes milliseconds, and almost all of them are
the operating system's.
Run loom with no arguments and you get the same commands at a
prompt instead.
$ loom
loom — the luce environment. help lists commands.
loom ▸ help
run PROGRAM.lc [ARGS] run a compiled Luce program
luce PROGRAM.luc [ARGS] compile and run a Luce source file
edit FILE open the Luce editor (LOOM_EDITOR overrides)
clear clear the screen
exit leave loom
a bare PROGRAM.lc or .luc path runs it directly
loom ▸ exitThe four parts
loom is one small binary made of four things, and this site has a page for each of them.
.lc and calls it. Compiles a .luc first and caches the
result beside the source. Refuses an artifact built for another machine, another
host ABI or another code generator — by name, before a single instruction of it
runs.
The shellFive commands and a
bare program path. Colour when a terminal is reading, none when a log file is.
An interactive shell always leaves cleanly; a piped script exits with the worst
status any line produced.
The editorA full-screen
editor with per-line Luce syntax highlighting, written entirely in Luce, carried
inside the loom binary so loom edit never needs a
path.
The hostEvery effect a
program can have — printing, files, the terminal, the clock, the command line —
is a service loom hands it. A service the host does not offer refuses; it never
guesses.
What loom is not
Most of what makes loom fast is what is missing from it.
- No engine. There is no interpreter and no bytecode inside
loom. A
.lcis machine code and loom calls it. (The interpreter exists, but it ships in nothing: it is the differential oracle the test suite compares the compiled path against.) - No code generator. loom links no LLVM at all. Building is
luce's job, and loom runs that binary when it needs a program compiled. A machine that only runs Luce programs needs no LLVM installed and, once the artifacts are built, noluceeither. - No disk image, no database, no registry. Programs read and write ordinary OS files. There is nothing to initialise, nothing to migrate, and nothing loom keeps between runs except the artifact cache — which is content-keyed and safe to delete at any time.
- No state of its own. The shell has no variables, no history
file, no configuration and no
cd. Everything durable belongs to the programs and to the filesystem.
What loom does keep is a promise: a program's behaviour must not
depend on who started it. A program run under loom run, a
standalone binary built with luce build --emit=exe, and the same
program under the test oracle all report a failure in the same words and exit
with the same number.
Programs to run
The repository ships userland written in Luce, compiled and linked by the freshly built compiler on every build, so none of it can quietly rot:
| Program | What it is |
|---|---|
editor.lc | The full-screen editor this site has a page about |
adventure.lc | A text adventure in five files — the first Luce program written as a project, with a save file |
life.lc | Conway's Game of Life on a multi-dimensional array, drawn on the terminal |
calc.lc | A recursive-descent expression calculator, and the worked example for recoverable errors |
bf.lc, dice.lc, sort.lc,
stats.lc, wordcount.lc, hello.lc |
Smaller programs, each one proving something the language can do |
$ loom run build/programs/life.lcBuilding it
loom is built from the LuciaOS repository along with the compiler, in one command:
$ ./build.sh $ ls build lib loom luce programs
Everything is Zig 0.16. LLVM is a build prerequisite of
luce and of nothing else — the code generator calls
libLLVM in process — and a C compiler driver (cc) is a prerequisite
of building at all, because producing a compiled program is a link. loom itself
links neither.
The build installs build/loom, build/luce,
build/lib/libluce_rt.a (Luce's semantics as a linkable library,
which every compiled artifact carries) and build/programs/*.lc. Put
build/ on your PATH and the two binaries find each
other: loom looks for the compiler beside its own executable first and on
PATH after, which is how a toolchain finds its tools.
The language itself — types, ownership, failure, the standard library — is documented at luce.luciaos.com. This site is about the tool that runs it, and about where that tool is going.