Skip to content

N Language

kazah-png edited this page Aug 25, 2026 · 2 revisions

N and N++ — the native languages of NyxOS

N is the native systems language of NyxOS, in the spirit that HolyC was to TempleOS: a language designed for one operating system, whose compiler knows that OS from the inside — its syscall table, its ABI, its memory map — and which ultimately lives inside the OS itself, so a program can be written, compiled and run without ever leaving NyxOS.

N++ is its planned superset. The relationship is deliberately the C/C++ one: every valid N program is a valid N++ program, and N++ compiles down through the same pipeline. N++ adds the safety-and-ergonomics layer — ownership, sum types with match, Result/?, traits, capability checking — much of which already exists in the compiler as the N++ P1–P4 work.

The language lives in lang/ in the repository. It builds on the Toolchain: the same way cc (TinyCC) compiles C in-OS and xbm installs packages from source, ncc compiles N in-OS.

See also: Toolchain, Userspace, Syscalls, Shell, Version-History

Note

N is a working v0.22 language with a real compiler and a 22-program example suite that runs inside NyxOS; N++ is the same compiler's already-landed safety layer plus a design doc for the rest. This is a hobby language, honestly scoped — it lowers to C today, not native code, and self-hosting (M5) is a growing toy compiler, not yet the real thing.

The two languages at a glance

N N++
Role The metal: kernel modules, drivers, small userland tools The ergonomics: applications, GUI programs, larger systems
File extension .n .npp
Compiler ncc (exists — bootstrap) n++ (planned, builds on ncc)
Memory model Manual, raw pointers Ownership/borrowing opt-in, #[user] checked pointers
Error handling Return codes Result<T, E> + ? propagation
Data types Primitives, pointers, str + struct methods, enum sum types, match, generics, traits
Status v0.22 — working P1–P5#[user] pointers, pageflags W^X, #[caps], and own types (must-consume, branch-aware moves, #[drop] destructors) + the GUI binding (nwin)

What makes it "native"

  • Syscalls are part of the language. An extern syscall block binds kernel entry points by number, and the compiler emits the raw x86-64 syscall instruction inline — no libc in between:

    extern syscall {
        fn write(fd: i32, buf: *u8, len: isize) -> i64 = 1
        fn getpid() -> i64                             = 6
    }
    
    fn main() -> i64 {
        pid := getpid();
        msg := "hello from N! pid={pid}\n";
        write(1, msg.ptr as *u8, msg.len as isize);
        0
    }
  • The compiler knows NyxOS. Types like addr, the canonical user-space boundary, the register ABI, the W^X page-flag rules — these are compiler knowledge, not header files.

  • Readable surface, systems semantics. := inference, {...} string interpolation, expression blocks — but everything lowers to straightforward, dependency-free C (and to native code eventually) with zero hidden runtime.

The compiler — ncc

ncc (lang/ncc/ncc.c) is a single-file, dependency-free C99 program (~2570 lines) that transpiles N to freestanding C targeting the NyxOS runtime. "Bootstrap" means it exists to get N off the ground and to be simple enough to port into NyxOS.

ncc input.n -o output.c    # transpile
ncc input.n                # ... or write the C to stdout

On success it prints a one-line summary to stderr and exits 0; on the first error it prints file:line: message and exits 1. Since v0.2 the emitted C is strict C99 with no GNU extensions (checked with -std=c99 -pedantic-errors) — which matters because TinyCC is the in-OS compiler that builds N programs inside NyxOS, and tcc rejects extensions like __auto_type.

The runtime N links against lives with the rest of user space: user/nyxrt.h / nyxrt.c — freestanding string/format helpers plus the syscall primitive. (This is the same nyxrt the wiki previously called "Nyx C"; N is its matured, named, versioned form — see Userspace.)

Language features by version

Each ncc release adds one capability, versioned in lockstep with the spec. The N++ safety work (P1–P4) landed as part of this progression.

Version Feature N++ phase
v0.2 Type inference — typed := bindings (i64 default), typed interpolation, enforced mut; strict-C99 output
v0.3v0.4 The expression-level static checker — undeclared names, unknown callees, arity, argument/operand/return/assignment types, all compile errors with file:line diagnostics P1 complete
v0.5 struct declarations — checked literals, typed field access, mut-through-field P2 starts
v0.6 defer — function-scoped LIFO cleanup on every exit path (Go semantics, static lowering)
v0.7 enum + match — tagged-union sum types with exhaustive dispatch (the Result foundation)
v0.8 impl methods — static dispatch on structs and enums, chained calls P2 complete
v0.9 match as an expression — bind/assign/return positions, one result type P3 starts
v0.10 ? error propagation over Ok/Err result enums
fs standard-bindings example — syscall→Result boundary, ? chains, deferred close P3 complete
v0.11 Counted for loops over half-open ranges; reject C keywords as N names
v0.12 #[user] checked pointers — a distinct pointer flavor, explicit as crossings, syscall params markable P4 starts
v0.13 pageflags — page permissions with a total compile-time W^X proof, PROT constants, a live mmap demo P4 2/3
v0.14 Capabilities#[caps(syscall)] gates extern blocks; wrappers are the audited boundary P4 complete
v0.15 Indexings[i]/p[i] byte and element reads (read-only); str.ptr is now truly *u8 (the self-hosting enabler)
v0.16 Index writesp[i] = x through pointers (a VM written in N now runs emitted code)
v0.17 own structs — move-not-copy, must-consume; leaks and double-use are compile errors P5 starts
v0.18 Branch-aware own moves — if/else arms consume only if both exits agree; loops/conditions stay move-free
v0.19 #[drop(fn)] destructors — live own values auto-close at scope end (defers first, drops LIFO, no drop flags)
v0.20v0.21 Format specs in interpolation — hex ({x:x}/{x:X}), width and zero-pad ({n:w8}/{n:z8}), composable
v0.22 Missing-return flow analysis — every path through a typed function must yield a value; tcc is no longer the backstop
(P5) nwin — a real desktop window drawn from N: an own+#[drop] handle over the window syscalls 57–60 P5 complete

Living inside the OS — the milestones

N rides the same self-hosting ladder the C toolchain climbed (see Toolchain).

Milestone Description Status
M0 Bootstrap ncc compiles N v0.1 on the dev machine ✅ done
M1 Language home in-repo: compiler, spec, examples, docs ✅ done
M2 ncc compiles inside NyxOS with the in-OS cc (tcc) ✅ done
M3 ncc hello.n → running binary, entirely in-OS — the HolyC moment ✅ done
M4 N++ front-end: type checker, structs/enums/match, Result/? done (P1–P5 landed)
M5 Self-hostingncc rewritten in N in progress — a growing multi-pass toy compiler in N

M2 and M3 were reached with zero changes to the compiler's designncc.c is plain C99 in one file, so the in-OS tcc builds it directly, and the same transpile-to-C pipeline works in-OS. The verified full loop inside a booted NyxOS:

cc /mnt/ncc.c -I/usr/src/nyx -o /mnt/bin/ncc     # tcc compiles the N compiler
ncc /mnt/hello.n -o /mnt/hello_gen.c             # ncc transpiles N source
cc /mnt/hello_gen.c /mnt/nyxrt.c -I/mnt -o /mnt/bin/nhello
nhello                                           # → hello from N! pid=8

On NyxOS itself the compiler is one command away — xbm install ncc builds it from source with the in-OS toolchain and installs it to /mnt/bin.

M5 — rewriting ncc in N

Self-hosting began as the classic "toy compiler triangle" — a tokenizer (ntokens.n), a precedence parser + evaluator (ncalc.n), and a stack-code emitter (nemit.n), each written in N and verified in-OS. It has since grown into a real multi-pass toy compiler (nparse.n, nstack.n): a token-buffer parser with line-numbered errors, statements and := bindings, if/while with branch-patched JZ/JMP, functions (CALL/RET, recursive factorial/gcd on the toy VM), interned identifiers, an AST with a check pass, constant folding and dead-arm elimination, and string literals with print. It now lexes N source from a disk file it did not embed — the first self-hosting rungs, each verified running inside NyxOS.

Next for M5: closing the parity gap with ncc's own front-end, rung by rung.

How it is verified

Three independent ways, so a regression shows up somewhere:

  1. Real programs run on NyxOS. The in-OS TinyCC builds the current ncc from source, and that compiler transpiles, compiles and runs the entire 22-program example suite in a single boot, output identical to the host runs — the fs bindings exercise real kernel open/read/close, the pageflags demo does a live anonymous mmap through the W^X-typed flags, the own-struct demo proves move semantics, nwin opens a real desktop window from N, and the toy compiler lexes/parses/checks/folds/emits a program in-OS.
  2. Generated C is clean. It compiles warning-free with the OS freestanding flags and links with the standard crt0 + nyxrt.
  3. Host behavioral tests. The x86-64 syscall instruction ABI is identical on Linux and NyxOS — only the numbers differ — so lang/ncc/host/nyxrt.h maps NyxOS syscall numbers to Linux ones, letting N programs run and be checked on the dev machine without booting.

Note

This workload doubles as a real OS stress test: running the whole suite in one boot uncovered a kernel VFS node-pool exhaustion (#66), which prompted the 512-node VFS pool and the vfsstat census (v6.4.197). See Filesystem.

The example suite

lang/examples/ — one program per feature, each verified in-OS:

hello · countdown · inference · structs · defer · enums · methods · matchexpr · results · fsio (fs bindings) · forloop · userptr (#[user] pointers) · pageflags (W^X + live mmap) · caps (#[caps]) · bytes (indexing, FNV-1a) · own (own structs + #[drop]) · nwin (a desktop window from N) · plus the M5 self-hosting programs ntokens · ncalc · nemit · nparse · nstack.

See also

  • Toolchain — the in-OS C toolchain N rides on (cc, xbm, the tcc self-host)
  • Userspace — the nyxrt runtime and the ELF a compiled N program becomes
  • Syscalls — the kernel entry points an extern syscall block binds
  • Version-History — the N v0.x releases in context

External resources

Clone this wiki locally