Last active
December 13, 2018 00:37
-
-
Save Shados/a51ab65b276310af22a29f461f255d46 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
# 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