Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Language overview

A .prim file is a sequence of top-level items, separated by newlines. There are six kinds of item:

ItemSpellingNotes
Constant<type> <NAME> = <value>One per line
Enumenum Name { Variant, … }Optionally integer-backed
Type aliastype Name = <type>Reusable type expression
use importuse ns::Name / use ns::{A, B}Cross-namespace ergonomic
namespace overridenamespace foo::barEscape hatch (see below)
Comments//, ///, //!Line, doc, file-doc

A real-world snippet:

/// Maximum upload size, enforced by the gateway.
u64 MAX_UPLOAD = 100MiB

/// Severity of a log line, integer-backed for fast filtering.
enum LogLevel: u8 {
    Debug = 0,
    Info  = 1,
    Warn  = 2,
    Error = 3,
}

type Port = u32

Port HTTP_PORT  = 8080
Port HTTPS_PORT = 8443

Identifiers and naming

primate enforces case conventions. The formatter doesn’t fix violations — the parser surfaces a naming-convention diagnostic.

ItemConventionExample
ConstantsSCREAMING_SNAKE_CASEMAX_UPLOAD
EnumsPascalCaseLogLevel
Enum variantsPascalCaseWarn
Type aliasesPascalCasePort
Namespaceslower_snake_casecore::time

Namespaces

Each .prim file belongs to exactly one namespace. By default the namespace comes from the file’s path relative to the project’s input directory:

constants/                ← input
├── limits.prim           → namespace `limits`
├── time.prim             → namespace `time`
└── net/
    └── ports.prim        → namespace `net::ports`

This is the recommended way to organize. Don’t write namespace foo at the top of every file — let the directory layout do it. The explicit form is an escape hatch when you want a file’s contents to live somewhere other than the path implies.

// constants/legacy/old_metrics.prim
namespace metrics::v1
// — overrides the path-derived `legacy::old_metrics`.

Files sharing a namespace share a flat scope: enums and aliases declared in one are visible in all, by bare name. Cross-namespace references go through fully qualified paths or use statements.

Resolution rules

When you write a bare type name like LogLevel, primate looks for it in:

  1. The current file.
  2. Sibling files in the same namespace.
  3. Names brought into scope by use statements.
  4. (Otherwise: unknown-type error. Use a fully qualified path.)

A few syntactic rules

  • No expressions in values. Every constant is a literal of its declared type. No 60 * 60, no BASE * 2.
  • No statement-terminating semicolons. Newlines terminate.
  • Inside (), [], {}, <> newlines are insignificant — handy for wrapping long type expressions or value literals.
  • One comment style per role. // line, /// doc, //! file doc. No block comments.

Some features you might expect (expressions, newtype nominal types, string interpolation) aren’t in the language. See the roadmap for what’s under consideration.