5ae1d3fd7b
switch would probably otherwise be called match, but has been renamed so it isn't confused with string.match and the enum matching capabilities yants has. It implements the closest to pattern matching nix can come which is still flexible enough to not be painful: Syntactically it works like cond, but is given a value. Instead of booleans it checks passed predicates or equality if simple values are passed. Both types of checks can be mixed. Change-Id: I40f000979cfd469316e15fd58d6c3a80312c1cc4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2589 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
82 lines
1.7 KiB
Nix
82 lines
1.7 KiB
Nix
{ depot, ... }:
|
|
|
|
let
|
|
|
|
inherit (depot.nix)
|
|
yants
|
|
;
|
|
|
|
inherit (depot.users.sterni.nix)
|
|
fun
|
|
;
|
|
|
|
# we must avoid evaluating any of the sublists
|
|
# as they may contain conditions that throw
|
|
condition = yants.restrict "condition"
|
|
(ls: builtins.length ls == 2)
|
|
(yants.list yants.any);
|
|
|
|
/* Like the common lisp macro: takes a list
|
|
of two elemented lists whose first element
|
|
is a boolean. The second element of the
|
|
first list that has true as its first
|
|
element is returned.
|
|
|
|
Type: [ [ bool a ] ] -> a
|
|
|
|
Example:
|
|
|
|
cond [
|
|
[ (builtins.isString true) 12 ]
|
|
[ (3 == 2) 13 ]
|
|
[ true 42 ]
|
|
]
|
|
|
|
=> 42
|
|
*/
|
|
cond = conds: switch true conds;
|
|
|
|
/* Generic pattern match-ish construct for nix.
|
|
Takes a bunch of lists which are of length
|
|
two and checks the first element for either
|
|
a predicate or a value. The second value of
|
|
the first list which either has a value equal
|
|
to or a function that evaluates to true for
|
|
the given value.
|
|
|
|
Type: a -> [ [ (function | a) b ] ] -> b
|
|
|
|
Example:
|
|
|
|
switch "foo" [
|
|
[ "smol" "SMOL!!!" ]
|
|
[ (x: builtins.stringLength x <= 3) "smol-ish" ]
|
|
[ (fun.const true) "not smol" ]
|
|
]
|
|
|
|
=> "smol-ish"
|
|
*/
|
|
switch = x: conds:
|
|
if builtins.length conds == 0
|
|
then builtins.throw "exhausted all conditions"
|
|
else
|
|
let
|
|
c = condition (builtins.head conds);
|
|
s = builtins.head c;
|
|
b =
|
|
if builtins.isFunction s
|
|
then s x
|
|
else x == s;
|
|
in
|
|
if b
|
|
then builtins.elemAt c 1
|
|
else switch x (builtins.tail conds);
|
|
|
|
|
|
|
|
in {
|
|
inherit
|
|
cond
|
|
switch
|
|
;
|
|
}
|