Luce
Luce BaseSourceLuciaOS

17. Tooling

17.1 The command#

CommandDoes
luce run program.lucruns it in the interpreter, the definition of behaviour; a program importing a Base module (§16) is refused, since the interpreter runs Luce alone
luce run --sandbox ROOT program.luc -- ARGSresolves ROOT and the program, requires the program below that root, enters irreversible host filesystem/process/network confinement before parsing, then runs the Luce-only interpreter, whose console.read_line reads nothing and answers none; unavailable host containment fails closed; exit zero publishes the bounded result on stdout, while any nonzero exit makes all captured text diagnostic output
luce --sandbox-policyprints the stable policy identity recorded by package locks; policy luce-sandbox/1 uses a supervised child, a 30-second wall limit, 10-second CPU limit, 256 MiB interpreter allocation arena, one-MiB combined output limit, 16 MiB file limit, 64 descriptors, no child threads/processes or network, and rooted Luce-only imports
luce build program.luc -o nameemits a Base package and compiles it with Base's compiler; --emit=base keeps the package; --native (the default), --backend=c, --release and --profile diagnostic pass to luce-base
luce check program.lucchecks it and the modules it imports and prints every diagnostic; --package adds every other .luc module under the package's source root, as luc check does
luce test program.lucruns its tests and those of the package's modules it imports, in the interpreter, or built when the program imports a Base module; --package adds every other .luc module under the package's source root, as luc test does; --build runs them as a program luce-base compiles, native by default; --backend=c explicitly selects Base’s C comparison backend; --profile diagnostic builds them with Base's diagnostic profile and implies --build
luce fmt, luce doc, luce explainas named
luce lex, luce parse, luce --versionthe tokens, the tree, the compiler's version

17.2 Diagnostics#

Every diagnostic is file:line:column: message, one per line behind the tool's name (luce: ), the first one first, and a rejection exits with status 1. A declaration that does not check is reported and the next is checked, so one run names several; a syntax error ends the run. A crash, a hang, or a message without a position is a compiler bug. The interpreter and the emitted Base trap with the same message and the Luce position, which the emitted Base carries through Luce Base's position directive.

17.3 Tests#

test "parsing an empty document fails":
    let n = parse("") catch failure:
        assert(failure.message == "empty")
        recover -1
    assert(n == -1)

A test is a registered function that runs under luce test and never in a build. It may fail, assert, and error. A test fails when a failure leaves it, reported at the test's position with the failure's message, or when an assert written in its own body (not in a lambda in it) is false, reported at the assert with assert failed, its condition and its message; the run goes on with the next test. Any other trap, an assert in a function the test calls included, ends the run (§12.4): the test is reported FAIL name, the trap's own line follows on standard error, then the tally of the tests run so far, and the status is 1. The report is one line per test, ok name or FAIL name followed by an indented file:line:column: message, then N passed and, when any failed, M failed; the status is 1 then. A position names its file relative to the project root, the directory holding package.prisma, and a file outside any package as it was given. The interpreter and a built runner print the same report.

The tests run are those of the file and of the modules of its package it imports, an imported module's before its importer's and each module's in order; with --package, also those of every other module under the package's source root, by their paths. A dependency's tests never run.

17.4 Documentation#

luce doc program.luc prints the public declarations of the program's modules as Markdown: a heading per module, a heading per declaration with its signature, the declaration's doc comment beneath, and a type's public members (an interface's methods, an enum's cases) as a list, each with its own doc comment. A doc comment is the ## lines directly above a declaration or a member (§3.3); one anywhere else documents nothing. The ## lines opening a file with a blank line after them are the module's doc comment, beneath its heading.

17.5 Explanations#

luce explain program.luc:line:column names what the identifier at that place is: a binding, a parameter, a function or method, a type, a member or a module, with its type and where it was declared, as one line file:line:column: name is a … of type T, declared at file:line:column.

17.6 Formatting#

luce fmt program.luc prints the module in the canonical layout; --write puts it back in the file, --check prints nothing and exits with 1 when the file is not in that layout. The layout: four spaces per block, one statement per line, one space around a binary operator and after a comma, none inside brackets, a blank line between declarations and before a method, at most one blank line between statements where the source had one, and comments kept: one on a line of its own stays before what follows it, one after code stays after that line. The parser reads the result back into the same tree, and formatting it again changes nothing.