Nitpick Module & FFI System Specification
This specification documents the current behavior, syntax, and semantics of the Nitpick module system, visibility rules, function declarations, and the C Foreign Function Interface (FFI). It addresses historical syntax discrepancies and establishes the canonical usage for the compiler version >= 0.8.4.
1. Modules (mod)
Modules allow organization of code into hierarchical namespaces.
1.1 Defining Modules
Modules can be defined inline or exist in external files.
Inline Modules:
nitpick mod network { pub func:connect = int32() { pass 0i32; }; func:internal = int32() { pass 1i32; }; // Private }External File Modules:
nitpick mod network;The compiler searches fornetwork.npkornetwork/mod.npkrelative to the declaring file.Nested Modules: Modules can be arbitrarily nested (e.g.,
mod core { mod math { ... } }).Visibility: Modules are private by default. Use
pub modto expose them to outer scopes.
2. Imports (use)
The use keyword brings symbols from other
modules into the current scope. Nitpick guarantees type
identity across multiple paths without duplicate type
definition errors (Diamond Import Behavior).
2.1 File-Based Imports (Canonical)
The canonical syntax imports directly from an
.npk file path:
- Wildcard (All
pubsymbols):use "path/module.npk".*; - Single-Name:
use "path/module.npk".square; - Selective:
use "path/module.npk".{square, pi}; - Namespace (Alias):
use "path/module.npk" as math;
2.2 Logical Path Imports (Legacy/Alternative)
The legacy logical path syntax is still supported by the compiler:
use std.math.*;
use std.collections.{HashMap, HashSet};
2.3 Search Paths & Transitivity
- Search Order: Current directory ->
-I <dir>->stdlib/->/usr/lib/aria->NITPICK_PATH. - Transitivity:
useimports are strictly not transitive. Symbols imported into a module are not automatically re-exported. You must explicitly wrap or usepub useto expose them.
3. Visibility
(pub)
Nitpick uses a strict binary visibility model: Public or Private.
- Private (Default): Symbols are accessible only within the same module/file. Intra-module access to private symbols is always permitted.
- Public (
pub): Prefix declarations withpubto export them.nitpick pub func:compute = int32() { ... }; pub struct Point { ... }; pub const int32:MAX = 100i32; pub mod utils { ... }
4. Functions (func
/ func:)
4.1 Syntax
- Canonical Syntax
(
func:name):nitpick func:add = int32(int32:a, int32:b) { pass (a + b); };NILis the return type for void-like functions. Must end withpass NIL;.
- Alternative Legacy Syntax
(
func name/fn name):nitpick func add(a: int32, b: int32) -> int32 { pass (a + b); }Note: The legacy syntax is fully supported for standard functions, but fails parsing withinexternblocks.
4.2 Calling Nitpick Functions
All native user-defined functions return a
Result<T> wrapper (the only exception is
extern functions). * Safe
Unwrap: int32:res = add(1, 2) ? 0; *
Raw Unwrap:
int32:res = raw add(1, 2); (Asserts success) *
Drop: drop side_effect_fn();
(Discards the Result)
5. Foreign
Function Interface (extern)
extern blocks are used for C FFI bindings.
Crucially, extern functions return bare
values, not Result<T>.
5.1 Extern Syntax
Extern Block:
nitpick extern "libc" { func:printf = int32(string:fmt); func:malloc = wild ?*(int64:size); }Restriction:extern "lib"blocks have a hard limit of ≤ 7 declarations per block.Flat Declaration:
nitpick extern func:custom_exit = void(int32:code);Note: Flat declarations have no limits per file.voidis used instead ofNILfor no-return C functions.Syntax Constraint: Inside
externblocks, you must use the canonicalfunc:name = type(args);syntax. The legacyfunc name() -> type;syntax is invalid here and will emit parse errors.
5.2 ABI & Pointers
- Strings:
stringis passed asconst char*. Functions returningstringmust return a C struct:struct {char* data; int64_t length;}. - Floats:
flt32is passed asdoubleat the C ABI level. - Pointers:
int32->: Scalar pointer (int32_t*).MyStruct->: Struct pointer (struct MyStruct*).?*/?->: Erased/Opaque pointer (void*).int64: Recommended stable choice for opaque handles and C callbacks.
5.3 Calling Extern Functions
Because they do not return Result<T>,
you do not use raw.
int32:n = printf("Hello\0"); // Direct assignment