add mix as a primitive (for nt bootstrap)

This commit is contained in:
Emile Clark-Boman 2026-01-24 23:19:07 +10:00
parent 6e8eaa982c
commit 498412e050
2 changed files with 172 additions and 0 deletions

View file

@ -0,0 +1,154 @@
{this, ...}: let
inherit
(builtins)
attrNames
attrValues
hasAttr
listToAttrs
removeAttrs
;
inherit
(this.util)
filterAttrs
hasInfix
mergeAttrsList
nameValuePair
projectOnto
removeSuffix
Wrap
;
modNameFromPath = path: let
name = baseNameOf path |> removeSuffix ".nix";
in
assert (! hasInfix "." name)
|| throw ''
Mix module ${path} has invalid name \"${name}\".
Module names must not contain the . (period) character.
''; name;
in rec {
# by default the imported module is given the basename of its path
# but you can set it manually by using the `mix.mod` function.
importMods = list: inputs:
list
|> map (path: nameValuePair (modNameFromPath path) (import path inputs))
|> listToAttrs;
importMergeMods = list: inputs:
list
|> map (path: (import path inputs))
|> mergeAttrsList;
# create a new and empty mixture
newMixture' = let
self = {
# trapdoor attribute
_' = {
path = [];
modName = null;
};
};
in
self;
# a splash of this, a splash of that ^_^
add = ingredients: mixture: let
sidedish = mergeAttrsList ingredients;
in
# bone apple tea ;-;
mixture // filterAttrs (x: _: ! hasAttr x mixture) sidedish;
newMixture = inputs: modBuilder: let
inputs' = removeAttrs inputs ["this"];
inputsWithThis = inputs' // {this = mixture;};
# mixture components are ordered based on shadowing
mixture =
inputs'
// importMods meta.submods.public inputsWithThis
// importMergeMods meta.includes.public inputsWithThis
// content;
# this = {
# # trapdoor attribute
# _' = {
# path = [];
# };
# parent' = throw "Mix: The mixture's root module has no parent by definition.";
# };
# partition modAttrs' into metadata and content
modAttrs' = modBuilder mixture;
content = removeAttrs modAttrs' (attrNames meta);
# attributes expected by and that directly modify mix's behaviour
meta =
modAttrs'
|> projectOnto
{
includes = {
public = [];
private = [];
protected = [];
};
submods = {
public = [];
private = [];
protected = [];
};
options = Wrap {};
config = Wrap {};
};
in
mixture;
mkMod = mixture: modBuilder: let
# XXX: TODO
# modAttrs = modBuilder privateMixture;
modAttrs = modBuilder mixture;
# attributes expected by and that directly modify mix's behaviour
meta =
modAttrs
|> projectOnto
{
includes = {
public = [];
private = [];
protected = [];
};
submods = {
public = [];
private = [];
protected = [];
};
options = Wrap {};
config = Wrap {};
};
# XXX: TODO
# protectedMixture = add [public protected] mixture;
# privateMixture = add [private] protectedMixture;
mkInterface = name: mixture: base:
mergeAttrsList
(attrValues <| importMods meta.includes.${name} mixture)
++ [
base
(importMods meta.submods.${name} mixture)
];
# XXX: TODO
# NOTE: public submodules are still DESCENDENTS
# NOTE: and should be able to access protected values :)
# public = mkInterface "public" protectedMixture content;
# protected = mkInterface "protected" protectedMixture public;
# private = mkInterface "private" privateMixture protected;
content = throw "TODO";
public = mkInterface "public" mixture content;
protected = mkInterface "protected" mixture public;
private = mkInterface "private" mixture protected;
in
# XXX: TODO
# public;
modAttrs;
}

View file

@ -2,6 +2,7 @@
{...}: let
inherit
(builtins)
attrNames
elem
elemAt
filter
@ -10,8 +11,10 @@
genList
length
mapAttrs
match
partition
removeAttrs
replaceStrings
stringLength
substring
tail
@ -97,6 +100,14 @@ in rec {
stringInit = x: x |> stringTake 1;
stringLast = x: stringElem (stringLength x - 1);
stringToCharacters = s: genList (p: substring p 1 s) (stringLength s);
escape = list: replaceStrings list (map (c: "\\${c}") list);
escapeRegex = escape (stringToCharacters "\\[{()^$?*+|.");
hasInfix = infix: content:
match ".*${escapeRegex infix}.*" "${content}" != null;
countEvensLeq = n: n / 2;
countOddsLeq = n: (n + 1) / 2;
@ -151,4 +162,11 @@ in rec {
|> filter (x: head x == name)
|> map tail
|> removeAttrsRec);
filterAttrs = pred: xs:
attrNames xs
|> filter (name: ! pred name xs.${name})
|> removeAttrs xs;
nameValuePair = name: value: {inherit name value;};
}