Improve lib.generators.toPreserves

- Generate dictionaries with symbol keys. This breaks lossless
  JSON conversion but is consistent with Preserves in the wild.
- New record pattern: ``[ 1 2 3 { record = "foo"; } ]``.
This commit is contained in:
Emery Hemingway 2022-03-16 21:48:08 -05:00
parent 9c0ef4db5d
commit 98e81b98e9
1 changed files with 31 additions and 12 deletions

43
lib.nix
View File

@ -5,31 +5,50 @@ in with lib; {
generators = with final.generators;
prev.generators // {
# Generates Preserves from an arbitrary value.
# Records are generated for functions that take
# a single formal argument `toRecord` and return
# a list of values.
/* Generates text-encoded Preserves from an arbitrary value.
Records are generated for lists with a final element in
the form of `{ record = «label»; }`.
Type: toPreserves :: a -> string
Example:
toPreserves { } [{ a = 0; b = 1; } "c" [ true false ] { record = "foo"; }]
=> "<foo { a: 0 b: 1 } \"c\" [ #t #f ]>"
*/
toPreserves = { }@args:
let
toPreserves' = toPreserves args;
concatItems = toString;
recordLabel = list:
with builtins;
let len = length list;
in if len == 0 then
null
else
let end = elemAt list (len - 1);
in if (isAttrs end) && (attrNames end) == [ "record" ] then
end
else
null;
in v:
if isAttrs v then
"{ ${
concatItems (lib.attrsets.mapAttrsToList
(key: val: "${builtins.toJSON key}: ${toPreserves' val}") v)
(key: val: "${key}: ${toPreserves' val}") v)
} }"
else if isList v then
"[ ${concatItems (map toPreserves' v)} ]"
let label = recordLabel v;
in if label == null then
"[ ${concatItems (map toPreserves' v)} ]"
else
"<${label.record} ${
concatItems (map toPreserves' (lib.lists.init v))
}>"
else if isBool v then
(if v then "#t" else "#f")
else if isFunction v then
(if (lib.functionArgs v) == { toRecord = false; } then
let items = v { toRecord = null; };
in "<${head items} ${toString (map toPreserves' (tail items))}>"
else
abort
"generators.toPreserves: cannot convert a function to Preserves")
abort "generators.toPreserves: cannot convert a function to Preserves"
else if isNull v then
"null"
else