Skip to main content

Module module_system

Module module_system 

Source
Expand description

The Nix module system — typed border for the option-merge lattice.

This module names the load-bearing gap that blocks sui from evaluating NixOS, nix-darwin, and home-manager configurations. cppnix’s lib.evalModules runs a fixed-point over a set of modules, each declaring options (typed slots) and config (definitions for those slots) plus optional imports (recursive module inclusion). The result is a merged config attrset that system.build.toplevel (and its kin) consume.

Per the constructive-substrate-engineering pattern, the algorithm lives here as a typed Rust border + a Lisp spec — both engines will eventually drive the same (defmodule-eval-algorithm …), so they cannot drift. The implementation in sui-eval is M2 work; today this module pins down the typed contract every M2 implementation must satisfy.

§Authoring surface

Three keyword forms compose into the full algorithm:

  • (defoption-type :name "..." :merge-strategy ... :check-kind ...) declares a type in the option-type registry (bool, int, str, path, listOf<T>, attrsOf<T>, submodule, oneOf [...], nullOr T, attrs, any). The merge-strategy determines how multiple definitions of the same option combine; the check-kind determines acceptance.

  • (defpriority :name "..." :level N :origin ...) declares one priority rank in the priority lattice (mkDefault 1000, mkOverride 0, mkForce 50, normal=100 by default). Higher level = lower priority (matches cppnix).

  • (defmodule-eval-algorithm cppnix-module-eval :name ... :phases (...)) declares the fixed-point pipeline: collect-modules, resolve-imports, evaluate-options, group-definitions, resolve-priorities, merge-per-type, type-check, emit-config.

Future M2 implementation: replace the apply() stub with a real interpreter that walks the phases against an evalModulesArgs. Both sui-eval and sui-bytecode will call exactly that function, with exactly the same spec.

Structs§

CanonicalSpecs
The three typed surfaces, loaded from one Lisp file.
Definition
One config definition — a value assigned to an option path, with a priority rank. Wrappers like mkDefault / mkForce / mkOverride N produce these directly with adjusted priority.
EvalModulesArgs
Legacy EvalModulesArgs — kept for backwards compatibility with the apply() surface. New code uses the Module + eval_modules API directly.
Module
A single module — the cppnix { options, config, imports } authoring shape, typed.
ModuleEvalAlgorithm
The module-evaluation algorithm authored as (defmodule-eval-algorithm …). Phases compose left-to-right over an EvalModulesArgs scratchpad; later phases consume earlier-bound slots.
ModulePhase
One phase of the module-evaluation pipeline. Mirrors the shape of crate::derivation::Phase for visual + cognitive consistency across spec domains.
OptionDecl
One option declaration — what cppnix’s mkOption returns.
OptionTypeSpec
One entry in the option-type registry. Each cppnix type (lib.types.<X>) becomes one (defoption-type …) form.
PriorityRank
One rank in the priority lattice. cppnix uses mkDefault 1000 (lowest), default 100, mkOverride 50, mkForce 50 — lower level value = higher priority. This typed border lets the authored spec declare the canonical ranks once.

Enums§

MergeStrategy
How multiple definitions of one option fold into one value.
ModulePhaseKind
The closed set of operations any module-eval algorithm composes. Adding a new variant IS adding a new primitive to the spec language.
PriorityOrigin
Where a definition’s priority comes from.
TypeCheckKind
Per-definition acceptance check. Run before merging.

Constants§

CANONICAL_MODULE_SYSTEM_LISP

Functions§

apply
Legacy apply() — kept for backwards compatibility with the previous typed-NotYet API surface. Returns a typed not-yet error since the typed pipeline driven by algo.phases requires the sui-eval Value type that lands at M2.1. New code should use eval_modules directly.
eval_modules
Evaluate a list of modules + their option-type registry, and return the merged config. M2.0 implementation: covers LastWins (bool, int, str, path, package, null), Concatenate (listOf), AttrsetMerge (attrsOf, attrs), and priority resolution (mkForce < normal < mkDefault). Submodules + recursion + transitive imports are M2.1 work.
flatten_imports
Flatten a tree of modules by resolving imports transitively. The resolver closure receives an import name and must return the corresponding Module; returning None errors. Imports are deduplicated by name — the same name imported from multiple modules contributes its options + config exactly once.
load_canonical
Compile the canonical module-system specs. Returns (algorithms, option_types, priorities).

Type Aliases§

Config
The output of eval_modules — a path-keyed config attrset.
NixValue
The substrate’s value type for module-system computation. M2.0 uses serde_json::Value because it covers Nix’s literal types (bool, int/float, string, list, attrset, null) with no extra machinery. When sui-eval consumes this layer (M2.1), it’ll swap to its lazy Value type via an adapter trait.