Terse lookup companion for the Nore language. For the full narrative (philosophy, type model, memory model, safety), see nore.md.
// single-line comment
val x: i64 = 42 // inline comment
/* multi-line
comment */
//to end of line/*to*/(do not nest)
import math "std/math.nore"
import file "std/file.nore"
import utils "../shared/utils.nore"
import alias "path"at top levelstd/paths resolve relative to compiler binary; others relative to importing file- Each file imported at most once
- No transitive visibility
val x: i64 = math.min_i64(3, 7) // function
val r: file.ReadResult = file.read_file(mut ref m, ref p) // type
val fd: i32 = fd_open(ref path, file.O_RDONLY) // constant
val err: file.WriteResult = file.WriteResult.Err(-1) // enum variant
val p: types.Vec2 = types.Vec2 { x: 1.0, y: 2.0 } // value constructor
- Functions:
alias.func_name(args) - Types:
alias.TypeName - Value constructors:
alias.TypeName { fields } - Enum variants:
alias.EnumName.Variantoralias.EnumName.Variant(payload) - Constants:
alias.CONSTANT_NAME - Table row types:
alias.TableName.Row - Match arms use unqualified variant names
- Built-ins and compiler-injected names remain unqualified
pub func add(a: i64, b: i64): i64 = { a + b }
pub val MAX_SIZE: i64 = 1024
pub value Point { x: i64, y: i64 }
pub enum Color { Red, Green, Blue }
pub table Particles { x: f64, y: f64 }
- Prefixes:
func,value,struct,table,enum,val,mut pub importnot allowed- Only
pubdeclarations accessible from other modules (S083, S084, S085) - Same-file: all declarations visible regardless of
pub
| Type | Description |
|---|---|
i64 |
64-bit signed integer |
i32 |
32-bit signed integer |
u8 |
8-bit unsigned integer |
u32 |
32-bit unsigned integer |
f64 |
64-bit floating-point |
bool |
Boolean (true / false) |
void |
No return value (functions only) |
str |
String (byte slice [u8]) |
Arena |
Heap memory arena |
[T; N] |
Fixed-size array |
[T] |
Slice |
value Name { ... } |
User-defined value type |
struct Name { ... } |
User-defined struct type |
enum Name { ... } |
User-defined enum / tagged union |
table Name { ... } |
Columnar storage (generates struct + value) |
Internal compile-time types: comptime_int (coerces to any integer or f64), comptime_float (coerces to f64 only).
42 // comptime_int, coerces to any integer type or f64
-17 // negative integer
3.14 // comptime_float, coerces to f64 only
"hello\n" // string literal (type: str / [u8])
'A' // character literal (comptime_int, value 65)
'\n' // escape character (value 10)
true / false // boolean
String escapes: \n \t \r \\ \" \0
Character escapes: \n \t \r \\ \' \0
val x: i64 = 42 // comptime_int -> i64
val y: f64 = 42 // comptime_int -> f64
val z: f64 = 3.14 // comptime_float -> f64
val a: u8 = 255 // comptime_int -> u8 (range-checked)
val b: u8 = 256 // ERROR: out of range
comptime_intcoerces to any integer type (i64,i32,u8,u32) orf64comptime_floatcoerces tof64only- No implicit coercion between concrete types
- Compile-time range checking for smaller types
- Negation of unsigned types is an error
val x: i64 = 42
val y: u8 = u8(x) // narrowing: runtime bounds check (R003)
val z: f64 = f64(x) // widening: always safe
val w: i64 = i64(3.14) // truncation toward zero
val c: i64 = i64(Color.Red) // enum to integer
Supported: u8(), i32(), u32(), i64(), f64()
- Narrowing / sign change: runtime bounds check, panics R003
- Widening: always safe
- Float to integer: runtime check for NaN/Inf/range, truncates toward zero
- Comptime values: range-checked at compile time (S050)
- Non-numeric: error S063
val x: i64 = 3 + 5 * 2 // folded to 13
val y: bool = 10 > 5 // folded to true
val z: i64 = 5 / 0 // ERROR: division by zero
val a = 42 // comptime_int
val b = a + 1 // folded to 43
val O_CREAT: i32 = if (TARGET_OS == OS.MacOS) { 512 } else { 64 } // comptime if/else
Immutable (val):
val x: i64 = 42 // explicit type, concrete
val y = 42 // comptime: type inferred as comptime_int
val z = y + 1 // comptime: propagates through expressions
Comptime constants (untyped val): stay flexible until consumed. Each use site decides the concrete type.
val width = 800
val a: i64 = width // comptime_int -> i64
val b: i32 = width // comptime_int -> i32
val c: f64 = width // comptime_int -> f64
val d: u8 = width // ERROR: 800 out of range for u8
Mutable (mut):
mut counter: i64 = 0 // explicit type required
counter = counter + 1
val PI = 3.14159 // comptime constant (inlined)
val MAX_SIZE: i64 = 1024 // typed constant
val GREETING: str = "hello" // string constant
mut counter: i64 = 0 // mutable global
val origin: Vec2 = Vec2 { x: 0.0, y: 0.0 } // value type
val data: [i64; 3] = [10, 20, 30] // array
mut mem: Arena = arena(4096) // global arena (auto-init/free in main)
- Global initializers must be constant expressions
arena()is the only non-constant initializer allowed- Function calls and
arena_alloc()not allowed as global initializers (S057) - Slice globals not allowed (except string literals via
val)
func name(param1: type1, param2: type2): returnType = {
body
}
- Return type required (use
voidfor no return) =precedes body- Last expression in block is the block's value (implicit return)
func add(a: i64, b: i64): i64 = { a + b }
func min(a: i64, b: i64): i64 = { if (a < b) { a } else { b } }
val sum: i64 = add(10, 20)
val nested: i64 = add(mul(2, 3), 4)
process() // bare call statement
Read-only (ref):
func length_sq(ref v: Vec2): f64 = { v.x * v.x + v.y * v.y }
val lsq: f64 = length_sq(ref p)
Mutable (mut ref):
func scale(mut ref v: Vec2, factor: f64): void = { v.x = v.x * factor }
scale(mut ref q, 2.0)
- Call site must match:
refforrefparams,mut refformut refparams - Argument must be addressable (variable or field-access chain)
mut refrequires root variable to bemut- Cannot take ref of scalar fields or array elements
- Refs are calling convention only: cannot be stored, returned, or used as locals
value Vec2 { x: f64, y: f64 }
value Color { r: u8, g: u8, b: u8, a: u8 }
val p: Vec2 = Vec2 { x: 1.0, y: 2.0 } // constructor (all fields, any order)
val x: f64 = p.x // field access
mut q: Vec2 = Vec2 { x: 0.0, y: 0.0 }
q.x = 3.0 // field assignment (mut only)
mut b: Vec2 = p // copy semantics
- Fields: scalars, fixed arrays, other value types
- No slices, no indirection
- Copy semantics, pass by value or
ref
struct Entity { x: f64, y: f64, health: i64 }
val e: Entity = Entity { x: 1.0, y: 2.0, health: 100 }
val hp: i64 = e.health
- Fields: scalars, fixed arrays, value types, slices
- Cannot embed other structs or Arena
- Cannot copy (S043), cannot pass by value (S044)
reformut refonly for parameters- Can be returned from functions (direct init)
enum Color { Red, Green, Blue }
val c: Color = Color.Red
assert c == Color.Red // == and != only
assert i64(Color.Blue) == 2 // cast to integer
- Variants auto-numbered from 0
- Type annotation required
- No ordering (
<>) or arithmetic - Both sides must be same enum type
Built-in: enum OS { Linux, MacOS } and TARGET_OS: OS (compiler-injected).
enum Option { Some(i64), None }
enum ReadResult { Ok([u8]), Err(i32) }
Construction:
val x: Option = Option.Some(42)
val y: Option = Option.None
Match (statement and expression):
match (opt) {
Some(n) = { result = n }
None = { result = 0 }
}
val x: i64 = match (opt) {
Some(n) = { n }
None = { 0 }
}
match (scrutinee) { arms }with parentheses- Each arm:
VariantName(binding) = { body }orVariantName = { body } _wildcard:Some(_) = { ... }- Exhaustiveness required
- Match expression arms must produce compatible types (S076)
- Slice-payload tagged unions are non-copyable (S043, S044, S045)
- Payload types: scalars, fixed arrays, value types, slices, plain enums. No structs/Arena (S082)
- No
==/!=on tagged unions (usematch)
val arr: [i64; 3] = [1, 2, 3]
val grid: [[i64; 2]; 3] = [[1, 2], [3, 4], [5, 6]]
- Size must be a positive integer literal
- Indexing:
arr[i], bounds-checked (R002) - Element assignment:
arr[0] = 99(mut only) - Value semantics: copy on assignment
- Sub-slicing:
arr[1..4]produces a slice
mut mem: Arena = arena(4096)
val data: [i64] = arena_alloc(mut ref mem, 10)
val result: [i64] = get_data(mut ref mem, 5)
val sub: [i64] = data[2..5]
- Fat pointer:
{data, length} .lenreturns element count asi64- Indexing:
data[i], bounds-checked (R002) - Parameters must use
reformut ref - Locals initialized via
arena_alloc(), function call, or sub-slice only (S046)
Sub-slicing (expr[start..end]):
val sub: [i64] = data[2..5] // elements 2, 3, 4
val head: [i64] = data[..3] // same as data[0..3]
val tail: [i64] = data[2..] // same as data[2..data.len]
val all: [i64] = data[..] // full slice
- Half-open range
[start..end) - Bounds-checked (R004)
- Works on slices and arrays, always produces a slice
- Can be chained:
data[1..4][0] - Can be passed to
refparams:sum(ref arr[1..4])
val greeting: str = "hello" // static memory, zero cost
val h: u8 = greeting[0] // 104 (ASCII 'h')
assert greeting.len == 5
stris[u8](interchangeable)- String literals:
valonly (S054 formut) - Parameters:
reformut ref(same as slices) - Escapes:
\n\t\r\\\"\0
mut mem: Arena = arena(4096)
val data: [i64] = arena_alloc(mut ref mem, 10)
arena_reset(mut ref mem) // invalidates all slices from mem (S056)
arena(capacity)creates with byte capacityarena_alloc(mut ref arena, count)allocates zero-initialized elementsarena_reset(mut ref arena)reclaims all memory- Arena params:
reformut refonly - Auto-freed on scope exit,
return,break/continue - Ref-param arenas not freed by callee
- Slice lifetime: cannot outlive arena (S053)
- Escape analysis: tracks direct, indirect, and transitive escape
Global arenas: mut at top level, auto-init at start of main, auto-free at end.
value Vec2 { x: f64, y: f64 }
table Particles { pos: Vec2, life: i64 }
Generates: struct Particles (pos: [Vec2], life: [i64], _len: i64) + value Particles.Row (pos: Vec2, life: i64).
mut mem: Arena = arena(65536)
mut p: Particles = table_alloc(mut ref mem, 100)
table_insert(mut ref p, Particles.Row { pos: Vec2 { x: 1.0, y: 2.0 }, life: 100 })
val row: Particles.Row = table_get(ref p, 0)
val n: i64 = table_len(ref p)
p.life[0] = 50 // direct column access
- Fields must be value-compatible (S059)
- Table is a struct: no copy,
refonly, no nesting - Row is a value: copyable, embeddable
If/else:
if (condition) { ... }
if (condition) { ... } else { ... }
val x: i64 = if (a < b) { a } else { b } // expression
return if (x < 0) { 0 - x } else { x } // after return
- Condition must be
bool - Expression form: both branches must have compatible types
- Comptime conditions folded at compile time
While:
while (condition) { ... }
breakexits,continueskips to next iteration
For (range-based):
for i in 0..n { ... }
- Exclusive upper bound (
0..5= 0,1,2,3,4) - Loop variable is
val i64(immutable) - End expression evaluated once
- Empty ranges skip the body
breakandcontinuework
Expression blocks:
val y: i64 = {
val a: i64 = 10
a + 5 // last expression is the block's value
}
Arithmetic (numeric): + - * / % (modulo: integers only)
Bitwise (integers): & | ^ ~ << >>
Comparison (numeric, produces bool): == != < <= > >=
Logical (bool): && || !
Assignment: = (mutable only)
Precedence (highest to lowest):
| Level | Operators | Category |
|---|---|---|
| 8 | * / % |
Multiplicative |
| 7 | + - |
Additive |
| 6 | << >> |
Shift |
| 5 | & |
Bitwise AND |
| 4 | ^ |
Bitwise XOR |
| 3 | | |
Bitwise OR |
| 2 | == != < > <= >= |
Comparison |
| 1 | && |
Logical AND |
| 0 | || |
Logical OR |
- Bitwise binds tighter than comparison:
a & mask == 0means(a & mask) == 0 - Both operands must be same concrete type (after coercion)
- Modulo follows C truncation semantics
- No comparison of
boolvalues
val name: type = expr/mut name: type = exprname = expr(assignment, mutable only)expr.field = expr/expr[index] = exprname(args...)(bare function call)return exprassert expr(R001, exits with code 2)break/continue
native func fd_write(fd: i32, ref data: [u8]): i64
native func exit(code: i32): void
- Top level, no body (P060 if
=follows) - Name must match known built-in (S086)
- Always module-private (
pub nativeis an error) - Wrapper pattern:
native func exit(...)+pub func exit(...)(native takes precedence inside module) - Required before using the built-in (S087)
| Native | Signature | Used by |
|---|---|---|
fd_write |
(fd: i32, ref data: [u8]): i64 |
std/io.nore, std/file.nore |
fd_read |
(fd: i32, mut ref buf: [u8]): i64 |
std/io.nore, std/file.nore |
fd_open |
(ref path: str, flags: i32): i32 |
std/file.nore |
fd_close |
(fd: i32): void |
std/file.nore |
fd_seek |
(fd: i32, offset: i64, whence: i32): i64 |
std/file.nore |
mem_copy |
(mut ref dst: [u8], ref src: [u8]): i64 |
std/string.nore |
exit |
(code: i32): void |
std/sys.nore |
args |
(mut ref mem: Arena): [str] |
std/sys.nore |
fd_write(fd, ref data): write bytes to fd. Returns i64 bytes written (negative on error).
val n: i64 = fd_write(io.STDOUT, ref "Hello\n")
fd_read(fd, mut ref buf): read bytes from fd. Returns i64 bytes read (0 = EOF).
mut buf: [u8; 256] = [0, 0, ...]
val n: i64 = fd_read(io.STDIN, mut ref buf)
fd_open(ref path, flags): open file. Returns i32 fd (negative on error). Null-terminated, max 4095 bytes, perms 0644.
val fd: i32 = fd_open(ref "file.txt", file.O_RDONLY)
fd_close(fd): close fd. Returns void.
fd_seek(fd, offset, whence): seek. Returns i64 new position.
val size: i64 = fd_seek(fd, 0, file.SEEK_END)
exit(code): terminate process. Returns void (never returns).
mem_copy(mut ref dst, ref src): copy min(dst.len, src.len) bytes. Returns i64 bytes copied. Uses memmove.
Type errors: S064 (fd not integer), S065 (data/buf not byte buffer), S066 (buf immutable).
arena(capacity)- Create Arena with byte capacityarena_alloc(mut ref arena, count)- Allocatecountzero-initialized elementsarena_reset(mut ref arena)- Reclaim all arena memory (invalidates slices, S056)table_alloc(mut ref arena, count)- Allocate columnar storage forcountrowstable_len(ref table)- Get current row counttable_get(ref table, index)- Get row value at index (R002)table_insert(mut ref table, row)- Insert a row
TARGET_OS-OS.LinuxorOS.MacOS(compiler-injected, no import)io.STDIN(0),io.STDOUT(1),io.STDERR(2) - fromstd/io.norefile.O_RDONLY(0),file.O_WRONLY(1),file.O_RDWR(2) - fromstd/file.norefile.O_CREAT,file.O_TRUNC,file.O_APPEND- platform-specific, fromstd/file.norefile.SEEK_SET(0),file.SEEK_CUR(1),file.SEEK_END(2) - fromstd/file.nore- Flags combine with
|:file.O_WRONLY | file.O_CREAT | file.O_TRUNC
std/io.nore (import as io):
io.print(ref s),io.println(ref s)- stdoutio.eprint(ref s),io.eprintln(ref s)- stderrio.print_i64(n)- integer to stdoutio.Writerstruct,io.writer_new(mut ref mem, capacity)- buffered writerio.write_str(mut ref w, ref s),io.write_byte(mut ref w, b),io.write_i64(mut ref w, n)io.write_i64_padded(mut ref w, n, width)- right-aligned with leading spacesio.flush(ref w, fd),io.writer_reset(mut ref w)
std/math.nore (import as math):
math.min_i64,math.max_i64,math.abs_i64,math.clamp_i64math.min_f64,math.max_f64,math.abs_f64,math.clamp_f64
std/string.nore (import as string):
string.is_digit(c),string.is_alpha(c),string.is_space(c)- char classificationstring.str_eq(ref a, ref b),string.str_starts_with(...),string.str_ends_with(...)- comparisonstring.str_find(ref s, ref needle),string.str_contains(...)- searchingstring.str_concat(mut ref mem, ref a, ref b)- concatenationstring.fmt_i64(mut ref buf, n),string.i64_to_str(mut ref mem, n),string.str_to_i64(ref s),string.str_to_f64(ref s)string.ParseResult-Ok(i64)orNonestring.ParseFloatResult-Ok(f64)orNone
std/file.nore (import as file):
file.read_file(mut ref mem, ref path)- returnsfile.ReadResult(Ok([u8])/Err(i32))file.write_file(ref path, ref data)- returnsfile.WriteResult(Ok(i64)/Err(i32))
std/sys.nore (import as sys):
sys.exit(code)- terminate processsys.get_args(mut ref mem)- command-line args as[str](argv[0]is program name,--runforwards args after--)
std/json.nore (import as json):
json.json_parse(mut ref nodes, ref src)- parse JSON, returnsjson.JsonResult(Ok(i64)root index /Err(JsonError))json.json_kind(ref nodes, node)- node kind (json.JsonKind: Null, Bool, Number, Str, Array, Object)json.json_child(ref nodes, parent)/json.json_next(ref nodes, node)- tree traversaljson.json_str(ref src, ref nodes, node)/json.json_key(ref src, ref nodes, node)- string/key accessjson.json_num(ref nodes, node)/json.json_bool(ref nodes, node)- value accessjson.json_len(ref nodes, node)/json.json_count(ref nodes)- child count / total nodesjson.json_find(ref src, ref nodes, parent, ref key)- find child by key
func value struct enum table match import pub native str Arena ref val mut return assert if else while for in break continue true false i64 i32 u8 u32 f64 bool void
+ - * / % & | ^ ~ << >> == != < <= > >= && || ! =
| Token | Usage |
|---|---|
( ) |
Parameters, grouping, conditions |
{ } |
Blocks, bodies, declarations, constructors |
[ ] |
Array types, literals, indexing, sub-slicing |
: |
Type annotation separator |
; |
Array type size separator ([T; N]) |
, |
Parameter/field/element separator |
. |
Field access, module access, enum variant access |
.. |
Range operator (for loops, sub-slicing) |
" delimits string literals (consumed by lexer, not a standalone token).
- Compound assignment operators (
+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=) else ifsyntax (currently requireselse { if (...) { } })- Multiline strings
- Additional types (
f32) - While as expressions
- Early exit from expression blocks (
yield)