Installation#
Nupp is written in Nupp. A checkout carries a stage-0 compiler already lowered to Lua, so building the real one takes a LuaJIT and nothing else.
What you need#
LuaJIT 2.1.1784535649 or newer. Generated Nupp is written in the LuaJIT 3.0 syntax that 2.1 backported — ?., ??, ?:, the bit operators, compound assignment — rather than in a lowering of it. That rolling version is the first build carrying those extensions. bin/nupp reads luajit -v and says which build is wanted, so an older interpreter fails with a sentence instead of a syntax error on a line nobody wrote.
Everything else is optional and buys one feature each:
Component Needed for Installed by
───────────── ──────────────────────────────── ─────────────────────
lua-cjson --json output and the LSP server luarocks install
lunamark nupp doc nupp doc
Scintillua highlighting in generated sites nupp doc
Rust toolchain building the binary host stub rustupThat table is about a checkout. A stamped binary carries all three of the first ones already — see the binary — and needs nothing installed to check, compile, run or document a project.
From a checkout#
git clone https://github.com/nupp-lang/nupp
cd nupp
./bin/nupp buildbin/nupp is the entry point and it builds on demand: it runs build/nupp/compiler when that exists and no source is newer, and compiles the compiler first when it does not. An edit to the compiler is picked up by the next command rather than by the next person who remembers to build.
The one thing it cannot do is start from nothing, since compiling Nupp needs a Nupp compiler. bootstrap/nupp.lua is that compiler, tracked in the repository, and it is what a fresh clone uses for its first build.
Optional libraries#
Nothing to run: lunamark and Scintillua are declared in nupp.lua as dependencies of the documentation target, so the command that needs them installs them.
./bin/nupp docThat installs both and their declared rocks into a project-local .rocks tree that bin/nupp and tests/run put on the search path. Nupp's own binaries use their pure PEG compatibility frontend for the LPeg calls in those libraries; they do not carry LPeg's C module. Two checkouts can hold different versions without either disturbing the other, and nothing lands in a global tree. See rock dependencies for declaring your own.
nupp doc needs lunamark and stops with a message when it cannot install or load it. Scintillua degrades instead: a fence in a language it cannot load renders as escaped text without highlighting.
lua-cjson comes from wherever your LuaJIT already looks:
luarocks install lua-cjsonEvery command's --json output and the language server read it.
Putting nupp on PATH#
Inside a checkout, run ./bin/nupp. Everywhere else, either put the checkout's bin on your path, or build a self-contained binary.
A self-contained binary#
./bin/nupp build --target distThat writes build/dist/nupp, a single file carrying the compiler, its standard library, and what it documents with, needing no LuaJIT installed alongside:
Carried How For
─────────────────── ─────────────────────────── ──────────────────────
LuaJIT linked into the stub running anything
lua-cjson detected and linked --json and the LSP
Nupp PEG frontend emitted in the payload legacy LPeg pattern calls
luautf8 detected and linked nupp doc's entities
lunamark in the payload nupp doc's markdown
Scintillua (45) in the payload highlighting fencesThe lexers are a chosen set rather than all hundred and sixty Scintillua ships — the languages a technical document actually fences, listed at the top of nupp.lua. A fence in something else renders as escaped text, which is what it does with no Scintillua at all. See distribution for the stub-and-payload format, and rock dependencies for carrying your own.
Checking that it works#
./bin/nupp check
./bin/nupp testcheck type-checks the project configured in nupp.lua. test builds and runs the suite, which is plain LuaJIT with no framework behind it.
Your first project#
Two files:
hello/
├── nupp.lua
└── src/
└── app/
└── main.nuppsrc/app/main.nupp:
nupp.lua, the project manifest:
return {
include = { "src" },
build = {
outDir = "build",
default = "app",
targets = {
app = {
kind = "modules",
entries = { "app.main" },
},
},
},
}include names the roots where modules live, so app.main resolves to src/app/main.nupp, and generated Lua keeps that path under build/.
Then, from the project root:
nupp check # type-check the project, writing nothing
nupp build # compile the default target
nupp run src/app/main.nupp # compile and run one fileCheck the whole project rather than the file you just edited. That is what lets Nupp verify module boundaries, ownership contracts, and lint settings together.
Build system documents every manifest key.
Next#
- A tour of Nupp — the whole language in one pass.
- Reasons to use Nupp — what each feature is for.