diff options
author | Vincent Ambo <mail@tazj.in> | 2022-01-30T16·06+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-01-31T16·11+0000 |
commit | aa122cbae78ce97d60c0c98ba14df753d97e40b1 (patch) | |
tree | 12b98d85c4b18fe870feb26de70db9ba61837bd7 /nix/yants/default.nix | |
parent | 2d10d60fac0fd00a71b65cfdcb9fba0477b2086c (diff) |
style: format entire depot with nixpkgs-fmt r/3723
This CL can be used to compare the style of nixpkgs-fmt against other formatters (nixpkgs, alejandra). Change-Id: I87c6abff6bcb546b02ead15ad0405f81e01b6d9e Reviewed-on: https://cl.tvl.fyi/c/depot/+/4397 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org> Reviewed-by: lukegb <lukegb@tvl.fyi> Reviewed-by: wpcarro <wpcarro@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: tazjin <tazjin@tvl.su> Reviewed-by: cynthia <cynthia@tvl.fyi> Reviewed-by: edef <edef@edef.eu> Reviewed-by: eta <tvl@eta.st> Reviewed-by: grfn <grfn@gws.fyi>
Diffstat (limited to 'nix/yants/default.nix')
-rw-r--r-- | nix/yants/default.nix | 301 |
1 files changed, 169 insertions, 132 deletions
diff --git a/nix/yants/default.nix b/nix/yants/default.nix index 2bbf4dd15a9e..cb9fc08287fb 100644 --- a/nix/yants/default.nix +++ b/nix/yants/default.nix @@ -6,10 +6,10 @@ # # All types (should) compose as expected. -{ lib ? (import <nixpkgs> {}).lib, ... }: +{ lib ? (import <nixpkgs> { }).lib, ... }: with builtins; let - prettyPrint = lib.generators.toPretty {}; + prettyPrint = lib.generators.toPretty { }; # typedef' :: struct { # name = string; @@ -34,41 +34,44 @@ with builtins; let # # This function is the low-level primitive used to create types. For # many cases the higher-level 'typedef' function is more appropriate. - typedef' = { name, checkType - , checkToBool ? (result: result.ok) - , toError ? (_: result: result.err) - , def ? null - , match ? null }: { - inherit name checkToBool toError; - - # check :: a -> bool - # - # This function is used to determine whether a given type is - # conformant. - check = value: checkToBool (checkType value); - - # checkType :: a -> struct { ok = bool; err = option string; } - # - # This function checks whether the passed value is type conformant - # and returns an optional type error string otherwise. - inherit checkType; - - # __functor :: a -> a - # - # This function checks whether the passed value is type conformant - # and throws an error if it is not. - # - # The name of this function is a special attribute in Nix that - # makes it possible to execute a type attribute set like a normal - # function. - __functor = self: value: - let result = self.checkType value; - in if checkToBool result then value - else throw (toError value result); - }; + typedef' = + { name + , checkType + , checkToBool ? (result: result.ok) + , toError ? (_: result: result.err) + , def ? null + , match ? null + }: { + inherit name checkToBool toError; + + # check :: a -> bool + # + # This function is used to determine whether a given type is + # conformant. + check = value: checkToBool (checkType value); + + # checkType :: a -> struct { ok = bool; err = option string; } + # + # This function checks whether the passed value is type conformant + # and returns an optional type error string otherwise. + inherit checkType; + + # __functor :: a -> a + # + # This function checks whether the passed value is type conformant + # and throws an error if it is not. + # + # The name of this function is a special attribute in Nix that + # makes it possible to execute a type attribute set like a normal + # function. + __functor = self: value: + let result = self.checkType value; + in if checkToBool result then value + else throw (toError value result); + }; typeError = type: val: - "expected type '${type}', but value '${prettyPrint val}' is of type '${typeOf val}'"; + "expected type '${type}', but value '${prettyPrint val}' is of type '${typeOf val}'"; # typedef :: string -> (a -> bool) -> type # @@ -85,27 +88,34 @@ with builtins; let }); }; - checkEach = name: t: l: foldl' (acc: e: - let res = t.checkType e; + checkEach = name: t: l: foldl' + (acc: e: + let + res = t.checkType e; isT = t.checkToBool res; - in { - ok = acc.ok && isT; - err = if isT - then acc.err - else acc.err + "${prettyPrint e}: ${t.toError e res}\n"; - }) { ok = true; err = "expected type ${name}, but found:\n"; } l; -in lib.fix (self: { + in + { + ok = acc.ok && isT; + err = + if isT + then acc.err + else acc.err + "${prettyPrint e}: ${t.toError e res}\n"; + }) + { ok = true; err = "expected type ${name}, but found:\n"; } + l; +in +lib.fix (self: { # Primitive types - any = typedef "any" (_: true); - unit = typedef "unit" (v: v == {}); - int = typedef "int" isInt; - bool = typedef "bool" isBool; - float = typedef "float" isFloat; - string = typedef "string" isString; - path = typedef "path" (x: typeOf x == "path"); - drv = typedef "derivation" (x: isAttrs x && x ? "type" && x.type == "derivation"); + any = typedef "any" (_: true); + unit = typedef "unit" (v: v == { }); + int = typedef "int" isInt; + bool = typedef "bool" isBool; + float = typedef "float" isFloat; + string = typedef "string" isString; + path = typedef "path" (x: typeOf x == "path"); + drv = typedef "derivation" (x: isAttrs x && x ? "type" && x.type == "derivation"); function = typedef "function" (x: isFunction x || (isAttrs x && x ? "__functor" - && isFunction x.__functor)); + && isFunction x.__functor)); # Type for types themselves. Useful when defining polymorphic types. type = typedef "type" (x: @@ -124,7 +134,7 @@ in lib.fix (self: { in { ok = isNull v || (self.type t).checkToBool res; err = "expected type ${name}, but value does not conform to '${t.name}': " - + t.toError v res; + + t.toError v res; }; }; @@ -136,7 +146,8 @@ in lib.fix (self: { list = t: typedef' rec { name = "list<${t.name}>"; - checkType = v: if isList v + checkType = v: + if isList v then checkEach name (self.type t) v else { ok = false; @@ -147,7 +158,8 @@ in lib.fix (self: { attrs = t: typedef' rec { name = "attrs<${t.name}>"; - checkType = v: if isAttrs v + checkType = v: + if isAttrs v then checkEach name (self.type t) (attrValues v) else { ok = false; @@ -172,20 +184,23 @@ in lib.fix (self: { # checkField checks an individual field of the struct against # its definition and creates a typecheck result. These results # are aggregated during the actual checking. - checkField = def: name: value: let result = def.checkType value; in rec { - ok = def.checkToBool result; - err = if !ok && isNull value - then "missing required ${def.name} field '${name}'\n" - else "field '${name}': ${def.toError value result}\n"; - }; + checkField = def: name: value: + let result = def.checkType value; in rec { + ok = def.checkToBool result; + err = + if !ok && isNull value + then "missing required ${def.name} field '${name}'\n" + else "field '${name}': ${def.toError value result}\n"; + }; # checkExtraneous determines whether a (closed) struct contains # any fields that are not part of the definition. checkExtraneous = def: has: acc: if (length has) == 0 then acc else if (hasAttr (head has) def) - then checkExtraneous def (tail has) acc - else checkExtraneous def (tail has) { + then checkExtraneous def (tail has) acc + else + checkExtraneous def (tail has) { ok = false; err = acc.err + "unexpected struct field '${head has}'\n"; }; @@ -197,85 +212,102 @@ in lib.fix (self: { init = { ok = true; err = ""; }; extraneous = checkExtraneous def (attrNames value) init; - checkedFields = map (n: - let v = if hasAttr n value then value."${n}" else null; - in checkField def."${n}" n v) (attrNames def); - - combined = foldl' (acc: res: { - ok = acc.ok && res.ok; - err = if !res.ok then acc.err + res.err else acc.err; - }) init checkedFields; - in { + checkedFields = map + (n: + let v = if hasAttr n value then value."${n}" else null; + in checkField def."${n}" n v) + (attrNames def); + + combined = foldl' + (acc: res: { + ok = acc.ok && res.ok; + err = if !res.ok then acc.err + res.err else acc.err; + }) + init + checkedFields; + in + { ok = combined.ok && extraneous.ok; err = combined.err + extraneous.err; }; struct' = name: def: typedef' { inherit name def; - checkType = value: if isAttrs value + checkType = value: + if isAttrs value then (checkStruct (self.attrs self.type def) value) else { ok = false; err = typeError name value; }; - toError = _: result: "expected '${name}'-struct, but found:\n" + result.err; + toError = _: result: "expected '${name}'-struct, but found:\n" + result.err; }; - in arg: if isString arg then (struct' arg) else (struct' "anon" arg); + in + arg: if isString arg then (struct' arg) else (struct' "anon" arg); # Enums & pattern matching enum = - let - plain = name: def: typedef' { - inherit name def; + let + plain = name: def: typedef' { + inherit name def; - checkType = (x: isString x && elem x def); - checkToBool = x: x; - toError = value: _: "'${prettyPrint value} is not a member of enum ${name}"; - }; - enum' = name: def: lib.fix (e: (plain name def) // { - match = x: actions: deepSeq (map e (attrNames actions)) ( - let - actionKeys = attrNames actions; - missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [] def; - in if (length missing) > 0 - then throw "Missing match action for members: ${prettyPrint missing}" - else actions."${e x}"); - }); - in arg: if isString arg then (enum' arg) else (enum' "anon" arg); + checkType = (x: isString x && elem x def); + checkToBool = x: x; + toError = value: _: "'${prettyPrint value} is not a member of enum ${name}"; + }; + enum' = name: def: lib.fix (e: (plain name def) // { + match = x: actions: deepSeq (map e (attrNames actions)) ( + let + actionKeys = attrNames actions; + missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [ ] def; + in + if (length missing) > 0 + then throw "Missing match action for members: ${prettyPrint missing}" + else actions."${e x}" + ); + }); + in + arg: if isString arg then (enum' arg) else (enum' "anon" arg); # Sum types # # The representation of a sum type is an attribute set with only one # value, where the key of the value denotes the variant of the type. sum = - let - plain = name: def: typedef' { - inherit name def; - checkType = (x: - let variant = elemAt (attrNames x) 0; - in if isAttrs x && length (attrNames x) == 1 && hasAttr variant def - then let t = def."${variant}"; - v = x."${variant}"; - res = t.checkType v; - in if t.checkToBool res - then { ok = true; } - else { - ok = false; - err = "while checking '${name}' variant '${variant}': " - + t.toError v res; - } + let + plain = name: def: typedef' { + inherit name def; + checkType = (x: + let variant = elemAt (attrNames x) 0; + in if isAttrs x && length (attrNames x) == 1 && hasAttr variant def + then + let + t = def."${variant}"; + v = x."${variant}"; + res = t.checkType v; + in + if t.checkToBool res + then { ok = true; } + else { + ok = false; + err = "while checking '${name}' variant '${variant}': " + + t.toError v res; + } else { ok = false; err = typeError name x; } - ); - }; - sum' = name: def: lib.fix (s: (plain name def) // { - match = x: actions: - let variant = deepSeq (s x) (elemAt (attrNames x) 0); - actionKeys = attrNames actions; - defKeys = attrNames def; - missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [] defKeys; - in if (length missing) > 0 - then throw "Missing match action for variants: ${prettyPrint missing}" - else actions."${variant}" x."${variant}"; - }); - in arg: if isString arg then (sum' arg) else (sum' "anon" arg); + ); + }; + sum' = name: def: lib.fix (s: (plain name def) // { + match = x: actions: + let + variant = deepSeq (s x) (elemAt (attrNames x) 0); + actionKeys = attrNames actions; + defKeys = attrNames def; + missing = foldl' (m: k: if (elem k actionKeys) then m else m ++ [ k ]) [ ] defKeys; + in + if (length missing) > 0 + then throw "Missing match action for variants: ${prettyPrint missing}" + else actions."${variant}" x."${variant}"; + }); + in + arg: if isString arg then (sum' arg) else (sum' "anon" arg); # Typed function definitions # @@ -289,15 +321,19 @@ in lib.fix (self: { mkFunc = sig: f: { inherit sig; __toString = self: foldl' (s: t: "${s} -> ${t.name}") - "λ :: ${(head self.sig).name}" (tail self.sig); + "λ :: ${(head self.sig).name}" + (tail self.sig); __functor = _: f; }; - defun' = sig: func: if length sig > 2 + defun' = sig: func: + if length sig > 2 then mkFunc sig (x: defun' (tail sig) (func ((head sig) x))) else mkFunc sig (x: ((head (tail sig)) (func ((head sig) x)))); - in sig: func: if length sig < 2 + in + sig: func: + if length sig < 2 then (throw "Signature must at least have two types (a -> b)") else defun' sig func; @@ -311,21 +347,22 @@ in lib.fix (self: { # depend on the value being of the wrapped type. restrict = name: pred: t: let restriction = "${t.name}[${name}]"; in typedef' { - name = restriction; - checkType = v: - let res = t.checkType v; - in + name = restriction; + checkType = v: + let res = t.checkType v; + in if !(t.checkToBool res) then res else let iok = pred v; - in if isBool iok then { + in + if isBool iok then { ok = iok; err = "${prettyPrint v} does not conform to restriction '${restriction}'"; } else - # use throw here to avoid spamming the build log + # use throw here to avoid spamming the build log throw "restriction '${restriction}' predicate returned unexpected value '${prettyPrint iok}' instead of boolean"; - }; + }; }) |