Skip to content

Instantly share code, notes, and snippets.

@Shados
Last active December 13, 2018 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shados/a51ab65b276310af22a29f461f255d46 to your computer and use it in GitHub Desktop.
Save Shados/a51ab65b276310af22a29f461f255d46 to your computer and use it in GitHub Desktop.
{
# The type checking function.
# Example:
# > checkType (list string) [ "foo" "bar" ]
# { }
# > checkType (list string) [ "foo" 42 ]
# { "1" = { should = "string"; val = 42; }; }
#
# Where { } means no error (given value is of given type) and
# { should : String, val : Value} denotes a type mismatch
checkType = let
# Succcess value
ok = {};
# Filters out non-error values
mapAndFilter = f: vals:
lib.filterAttrs (_: v: v != ok) (lib.mapAttrs f vals);
in type: val:
# This first case handles the type-specific check for the given type; the
# subsequent cases handle recursively performing checks for each compound
# type variant
if !(type.check val) then
{ should = type.description; inherit val; }
# Scalar types don't have any other types associated with them, so if the
# previous type-specific check passed, we're done
else if type.variant == variants.scalar then
ok
# For recursive types, check each child value against the nested type
else if type.variant == variants.recursive then
mapAndFilter (_: child: checkType type.nested child) (type.each val)
# For sum types, check the tagged value against its associated type
else if type.variant == variants.sum then
let alt = builtins.head (builtins.attrNames val);
in checkType type.alts.${alt} val.${alt}
# For product types, check each field against its associated type
else if type.variant == variants.product then
mapAndFilter (name: memberType:
if val ? ${name} then checkType memberType val.${name} else ok
) (type.req // type.opt)
# For union types, check that the value is any of the associated types
else if type.variant == variants.union then
let
altChecks = map (checkType) val.altList;
anyOk = value: fnList: lib.any
(res: res == ok)
(map (fn: fn value) fnList);
in if ! anyOk val altChecks
then { should = type.description; inherit val; }
else ok
else abort "Given type is invalid!";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment