dhall 1.24.0 → 1.42.3
raw patch · 3837 files changed
Files
- CHANGELOG.md +1518/−501
- LICENSE +1/−1
- benchmark/deep-nested-large-record/Main.hs +44/−24
- benchmark/deep-nested-large-record/prelude.dhall +2/−2
- benchmark/dhall-command/Main.hs +0/−20
- benchmark/examples/issue108.dhall +0/−61
- benchmark/examples/normalize/ChurchEval.dhall +0/−22
- benchmark/examples/normalize/FunCompose.dhall +0/−18
- benchmark/examples/normalize/ListBench.dhall +0/−75
- benchmark/examples/normalize/ListBenchAlt.dhall +0/−45
- benchmark/map/Main.hs +0/−44
- benchmark/parser/Main.hs +57/−64
- benchmark/parser/examples/cpkg.dhall too large to diff
- benchmark/parser/examples/issue108.dhall +63/−0
- benchmark/parser/examples/issue108.dhallb binary
- benchmark/parser/examples/kubernetes.dhallb too large to diff
- benchmark/parser/examples/normalize/ChurchEval.dhall +22/−0
- benchmark/parser/examples/normalize/FunCompose.dhall +18/−0
- benchmark/parser/examples/normalize/ListBench.dhall +75/−0
- benchmark/parser/examples/normalize/ListBenchAlt.dhall +45/−0
- dhall-lang/Prelude/Bool/and +3/−18
- dhall-lang/Prelude/Bool/and.dhall +14/−0
- dhall-lang/Prelude/Bool/build +3/−17
- dhall-lang/Prelude/Bool/build.dhall +16/−0
- dhall-lang/Prelude/Bool/equal.dhall +6/−0
- dhall-lang/Prelude/Bool/even +3/−22
- dhall-lang/Prelude/Bool/even.dhall +20/−0
- dhall-lang/Prelude/Bool/fold +3/−20
- dhall-lang/Prelude/Bool/fold.dhall +14/−0
- dhall-lang/Prelude/Bool/not +3/−12
- dhall-lang/Prelude/Bool/not.dhall +10/−0
- dhall-lang/Prelude/Bool/odd +3/−22
- dhall-lang/Prelude/Bool/odd.dhall +20/−0
- dhall-lang/Prelude/Bool/or +3/−18
- dhall-lang/Prelude/Bool/or.dhall +14/−0
- dhall-lang/Prelude/Bool/package.dhall +28/−16
- dhall-lang/Prelude/Bool/show +3/−13
- dhall-lang/Prelude/Bool/show.dhall +13/−0
- dhall-lang/Prelude/Date/package.dhall +5/−0
- dhall-lang/Prelude/Date/show.dhall +15/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/Type.dhall +5/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/intersect.dhall +69/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/invert.dhall +48/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/none.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/package.dhall +53/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/r.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/rw.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/rwx.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/rx.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/toAccess.dhall +20/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/toAccessWith.dhall +42/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/union.dhall +64/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/w.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Mask/x.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/Type.dhall +5/−0
- dhall-lang/Prelude/DirectoryTree/Access/equal.dhall +29/−0
- dhall-lang/Prelude/DirectoryTree/Access/none.dhall +4/−0
- dhall-lang/Prelude/DirectoryTree/Access/package.dhall +17/−0
- dhall-lang/Prelude/DirectoryTree/Access/schema.dhall +12/−0
- dhall-lang/Prelude/DirectoryTree/Entry/BinaryFileEntry.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/DirectoryEntry.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/Metadata.dhall +24/−0
- dhall-lang/Prelude/DirectoryTree/Entry/TextFileEntry.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/Type.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/binary-file.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/directory.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Entry/entry.dhall +24/−0
- dhall-lang/Prelude/DirectoryTree/Entry/package.dhall +37/−0
- dhall-lang/Prelude/DirectoryTree/Entry/text-file.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Group/Type.dhall +1/−0
- dhall-lang/Prelude/DirectoryTree/Group/id.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Group/name.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Group/package.dhall +13/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/Type.dhall +10/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/all.dhall +9/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/directory.dhall +17/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/executable.dhall +17/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/file.dhall +17/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/group.dhall +14/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/intersect.dhall +24/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/invert.dhall +22/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/none.dhall +12/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/other.dhall +14/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/package.dhall +41/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/toMode.dhall +28/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/toModeWith.dhall +149/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/union.dhall +24/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Mask/user.dhall +14/−0
- dhall-lang/Prelude/DirectoryTree/Mode/Type.dhall +10/−0
- dhall-lang/Prelude/DirectoryTree/Mode/equal.dhall +34/−0
- dhall-lang/Prelude/DirectoryTree/Mode/none.dhall +9/−0
- dhall-lang/Prelude/DirectoryTree/Mode/package.dhall +17/−0
- dhall-lang/Prelude/DirectoryTree/Mode/schema.dhall +12/−0
- dhall-lang/Prelude/DirectoryTree/Tree/Make.dhall +20/−0
- dhall-lang/Prelude/DirectoryTree/Tree/Type.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/Tree/makeTree.dhall +32/−0
- dhall-lang/Prelude/DirectoryTree/Tree/makeTreeFromList.dhall +42/−0
- dhall-lang/Prelude/DirectoryTree/Tree/makeTreesFromList.dhall +36/−0
- dhall-lang/Prelude/DirectoryTree/Tree/package.dhall +21/−0
- dhall-lang/Prelude/DirectoryTree/User/Type.dhall +1/−0
- dhall-lang/Prelude/DirectoryTree/User/id.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/User/name.dhall +6/−0
- dhall-lang/Prelude/DirectoryTree/User/package.dhall +13/−0
- dhall-lang/Prelude/DirectoryTree/package.dhall +25/−0
- dhall-lang/Prelude/Double/package.dhall +3/−2
- dhall-lang/Prelude/Double/show +3/−13
- dhall-lang/Prelude/Double/show.dhall +13/−0
- dhall-lang/Prelude/Function/compose +3/−21
- dhall-lang/Prelude/Function/compose.dhall +17/−0
- dhall-lang/Prelude/Function/composeList.dhall +35/−0
- dhall-lang/Prelude/Function/identity +3/−0
- dhall-lang/Prelude/Function/identity.dhall +10/−0
- dhall-lang/Prelude/Function/package.dhall +11/−2
- dhall-lang/Prelude/Integer/abs +3/−0
- dhall-lang/Prelude/Integer/abs.dhall +15/−0
- dhall-lang/Prelude/Integer/add +3/−0
- dhall-lang/Prelude/Integer/add.dhall +25/−0
- dhall-lang/Prelude/Integer/clamp +3/−0
- dhall-lang/Prelude/Integer/clamp.dhall +14/−0
- dhall-lang/Prelude/Integer/equal +3/−0
- dhall-lang/Prelude/Integer/equal.dhall +24/−0
- dhall-lang/Prelude/Integer/greaterThan +3/−0
- dhall-lang/Prelude/Integer/greaterThan.dhall +30/−0
- dhall-lang/Prelude/Integer/greaterThanEqual +3/−0
- dhall-lang/Prelude/Integer/greaterThanEqual.dhall +27/−0
- dhall-lang/Prelude/Integer/lessThan +3/−0
- dhall-lang/Prelude/Integer/lessThan.dhall +25/−0
- dhall-lang/Prelude/Integer/lessThanEqual +3/−0
- dhall-lang/Prelude/Integer/lessThanEqual.dhall +47/−0
- dhall-lang/Prelude/Integer/multiply +3/−0
- dhall-lang/Prelude/Integer/multiply.dhall +40/−0
- dhall-lang/Prelude/Integer/negate +3/−0
- dhall-lang/Prelude/Integer/negate.dhall +12/−0
- dhall-lang/Prelude/Integer/negative +3/−0
- dhall-lang/Prelude/Integer/negative.dhall +21/−0
- dhall-lang/Prelude/Integer/nonNegative +3/−0
- dhall-lang/Prelude/Integer/nonNegative.dhall +21/−0
- dhall-lang/Prelude/Integer/nonPositive +3/−0
- dhall-lang/Prelude/Integer/nonPositive.dhall +16/−0
- dhall-lang/Prelude/Integer/package.dhall +71/−5
- dhall-lang/Prelude/Integer/positive +3/−0
- dhall-lang/Prelude/Integer/positive.dhall +26/−0
- dhall-lang/Prelude/Integer/show +3/−14
- dhall-lang/Prelude/Integer/show.dhall +14/−0
- dhall-lang/Prelude/Integer/subtract +3/−0
- dhall-lang/Prelude/Integer/subtract.dhall +54/−0
- dhall-lang/Prelude/Integer/toDouble +3/−12
- dhall-lang/Prelude/Integer/toDouble.dhall +10/−0
- dhall-lang/Prelude/Integer/toNatural +3/−0
- dhall-lang/Prelude/Integer/toNatural.dhall +20/−0
- dhall-lang/Prelude/JSON/Format +3/−0
- dhall-lang/Prelude/JSON/Format.dhall +7/−0
- dhall-lang/Prelude/JSON/Nesting +3/−31
- dhall-lang/Prelude/JSON/Nesting.dhall +35/−0
- dhall-lang/Prelude/JSON/Tagged +3/−67
- dhall-lang/Prelude/JSON/Tagged.dhall +74/−0
- dhall-lang/Prelude/JSON/Type +3/−0
- dhall-lang/Prelude/JSON/Type.dhall +63/−0
- dhall-lang/Prelude/JSON/array +3/−0
- dhall-lang/Prelude/JSON/array.dhall +41/−0
- dhall-lang/Prelude/JSON/bool +3/−0
- dhall-lang/Prelude/JSON/bool.dhall +35/−0
- dhall-lang/Prelude/JSON/core.dhall +70/−0
- dhall-lang/Prelude/JSON/double +3/−0
- dhall-lang/Prelude/JSON/double.dhall +35/−0
- dhall-lang/Prelude/JSON/integer +3/−0
- dhall-lang/Prelude/JSON/integer.dhall +35/−0
- dhall-lang/Prelude/JSON/keyText +3/−17
- dhall-lang/Prelude/JSON/keyText.dhall +3/−0
- dhall-lang/Prelude/JSON/keyValue +3/−20
- dhall-lang/Prelude/JSON/keyValue.dhall +3/−0
- dhall-lang/Prelude/JSON/natural +3/−0
- dhall-lang/Prelude/JSON/natural.dhall +31/−0
- dhall-lang/Prelude/JSON/null +3/−0
- dhall-lang/Prelude/JSON/null.dhall +30/−0
- dhall-lang/Prelude/JSON/number +3/−0
- dhall-lang/Prelude/JSON/number.dhall +28/−0
- dhall-lang/Prelude/JSON/object +3/−0
- dhall-lang/Prelude/JSON/object.dhall +55/−0
- dhall-lang/Prelude/JSON/omitNullFields +3/−0
- dhall-lang/Prelude/JSON/omitNullFields.dhall +145/−0
- dhall-lang/Prelude/JSON/package.dhall +29/−7
- dhall-lang/Prelude/JSON/render +3/−0
- dhall-lang/Prelude/JSON/render.dhall +52/−0
- dhall-lang/Prelude/JSON/renderAs +3/−0
- dhall-lang/Prelude/JSON/renderAs.dhall +458/−0
- dhall-lang/Prelude/JSON/renderCompact.dhall +61/−0
- dhall-lang/Prelude/JSON/renderInteger.dhall +23/−0
- dhall-lang/Prelude/JSON/renderYAML +3/−0
- dhall-lang/Prelude/JSON/renderYAML.dhall +49/−0
- dhall-lang/Prelude/JSON/string +3/−0
- dhall-lang/Prelude/JSON/string.dhall +35/−0
- dhall-lang/Prelude/JSON/tagInline +3/−0
- dhall-lang/Prelude/JSON/tagInline.dhall +29/−0
- dhall-lang/Prelude/JSON/tagNested +3/−0
- dhall-lang/Prelude/JSON/tagNested.dhall +33/−0
- dhall-lang/Prelude/List/all +3/−20
- dhall-lang/Prelude/List/all.dhall +16/−0
- dhall-lang/Prelude/List/any +3/−20
- dhall-lang/Prelude/List/any.dhall +16/−0
- dhall-lang/Prelude/List/build +3/−32
- dhall-lang/Prelude/List/build.dhall +30/−0
- dhall-lang/Prelude/List/concat +3/−42
- dhall-lang/Prelude/List/concat.dhall +34/−0
- dhall-lang/Prelude/List/concatMap +3/−28
- dhall-lang/Prelude/List/concatMap.dhall +32/−0
- dhall-lang/Prelude/List/default +3/−0
- dhall-lang/Prelude/List/default.dhall +15/−0
- dhall-lang/Prelude/List/drop +3/−0
- dhall-lang/Prelude/List/drop.dhall +28/−0
- dhall-lang/Prelude/List/empty +3/−0
- dhall-lang/Prelude/List/empty.dhall +8/−0
- dhall-lang/Prelude/List/filter +3/−30
- dhall-lang/Prelude/List/filter.dhall +22/−0
- dhall-lang/Prelude/List/filterMap.dhall +45/−0
- dhall-lang/Prelude/List/fold +3/−46
- dhall-lang/Prelude/List/fold.dhall +43/−0
- dhall-lang/Prelude/List/foldLeft.dhall +60/−0
- dhall-lang/Prelude/List/generate +3/−38
- dhall-lang/Prelude/List/generate.dhall +35/−0
- dhall-lang/Prelude/List/head +3/−12
- dhall-lang/Prelude/List/head.dhall +10/−0
- dhall-lang/Prelude/List/index +3/−0
- dhall-lang/Prelude/List/index.dhall +18/−0
- dhall-lang/Prelude/List/indexed +3/−21
- dhall-lang/Prelude/List/indexed.dhall +19/−0
- dhall-lang/Prelude/List/iterate +3/−43
- dhall-lang/Prelude/List/iterate.dhall +42/−0
- dhall-lang/Prelude/List/last +3/−12
- dhall-lang/Prelude/List/last.dhall +10/−0
- dhall-lang/Prelude/List/length +3/−12
- dhall-lang/Prelude/List/length.dhall +10/−0
- dhall-lang/Prelude/List/map +3/−27
- dhall-lang/Prelude/List/map.dhall +23/−0
- dhall-lang/Prelude/List/mapMaybe.dhall +37/−0
- dhall-lang/Prelude/List/mapWithIndex.dhall +41/−0
- dhall-lang/Prelude/List/null +3/−16
- dhall-lang/Prelude/List/null.dhall +10/−0
- dhall-lang/Prelude/List/package.dhall +105/−38
- dhall-lang/Prelude/List/partition +3/−0
- dhall-lang/Prelude/List/partition.dhall +31/−0
- dhall-lang/Prelude/List/replicate +3/−24
- dhall-lang/Prelude/List/replicate.dhall +18/−0
- dhall-lang/Prelude/List/reverse +3/−12
- dhall-lang/Prelude/List/reverse.dhall +11/−0
- dhall-lang/Prelude/List/shifted +3/−86
- dhall-lang/Prelude/List/shifted.dhall +83/−0
- dhall-lang/Prelude/List/take +3/−0
- dhall-lang/Prelude/List/take.dhall +26/−0
- dhall-lang/Prelude/List/unpackOptionals +3/−0
- dhall-lang/Prelude/List/unpackOptionals.dhall +31/−0
- dhall-lang/Prelude/List/unzip +3/−55
- dhall-lang/Prelude/List/unzip.dhall +50/−0
- dhall-lang/Prelude/List/zip +3/−0
- dhall-lang/Prelude/List/zip.dhall +58/−0
- dhall-lang/Prelude/Location/Type +3/−0
- dhall-lang/Prelude/Location/Type.dhall +15/−0
- dhall-lang/Prelude/Location/package.dhall +5/−0
- dhall-lang/Prelude/Map/Entry +3/−0
- dhall-lang/Prelude/Map/Entry.dhall +6/−0
- dhall-lang/Prelude/Map/Type +3/−0
- dhall-lang/Prelude/Map/Type.dhall +25/−0
- dhall-lang/Prelude/Map/empty +3/−0
- dhall-lang/Prelude/Map/empty.dhall +14/−0
- dhall-lang/Prelude/Map/keyText +3/−0
- dhall-lang/Prelude/Map/keyText.dhall +15/−0
- dhall-lang/Prelude/Map/keyValue +3/−0
- dhall-lang/Prelude/Map/keyValue.dhall +17/−0
- dhall-lang/Prelude/Map/keys +3/−0
- dhall-lang/Prelude/Map/keys.dhall +39/−0
- dhall-lang/Prelude/Map/map +3/−0
- dhall-lang/Prelude/Map/map.dhall +58/−0
- dhall-lang/Prelude/Map/mapMaybe.dhall +56/−0
- dhall-lang/Prelude/Map/package.dhall +41/−0
- dhall-lang/Prelude/Map/unpackOptionals.dhall +41/−0
- dhall-lang/Prelude/Map/values +3/−0
- dhall-lang/Prelude/Map/values.dhall +39/−0
- dhall-lang/Prelude/Monoid +3/−39
- dhall-lang/Prelude/Monoid.dhall +43/−0
- dhall-lang/Prelude/Natural/build +3/−33
- dhall-lang/Prelude/Natural/build.dhall +31/−0
- dhall-lang/Prelude/Natural/enumerate +3/−36
- dhall-lang/Prelude/Natural/enumerate.dhall +32/−0
- dhall-lang/Prelude/Natural/equal +3/−0
- dhall-lang/Prelude/Natural/equal.dhall +17/−0
- dhall-lang/Prelude/Natural/even +3/−12
- dhall-lang/Prelude/Natural/even.dhall +10/−0
- dhall-lang/Prelude/Natural/fold +3/−33
- dhall-lang/Prelude/Natural/fold.dhall +28/−0
- dhall-lang/Prelude/Natural/greaterThan +3/−0
- dhall-lang/Prelude/Natural/greaterThan.dhall +21/−0
- dhall-lang/Prelude/Natural/greaterThanEqual +3/−0
- dhall-lang/Prelude/Natural/greaterThanEqual.dhall +23/−0
- dhall-lang/Prelude/Natural/isZero +3/−12
- dhall-lang/Prelude/Natural/isZero.dhall +10/−0
- dhall-lang/Prelude/Natural/lessThan +3/−0
- dhall-lang/Prelude/Natural/lessThan.dhall +26/−0
- dhall-lang/Prelude/Natural/lessThanEqual +3/−0
- dhall-lang/Prelude/Natural/lessThanEqual.dhall +16/−0
- dhall-lang/Prelude/Natural/listMax +3/−0
- dhall-lang/Prelude/Natural/listMax.dhall +30/−0
- dhall-lang/Prelude/Natural/listMin +3/−0
- dhall-lang/Prelude/Natural/listMin.dhall +34/−0
- dhall-lang/Prelude/Natural/max +3/−0
- dhall-lang/Prelude/Natural/max.dhall +19/−0
- dhall-lang/Prelude/Natural/min +3/−0
- dhall-lang/Prelude/Natural/min.dhall +17/−0
- dhall-lang/Prelude/Natural/odd +3/−12
- dhall-lang/Prelude/Natural/odd.dhall +10/−0
- dhall-lang/Prelude/Natural/package.dhall +77/−22
- dhall-lang/Prelude/Natural/product +3/−17
- dhall-lang/Prelude/Natural/product.dhall +11/−0
- dhall-lang/Prelude/Natural/show +3/−13
- dhall-lang/Prelude/Natural/show.dhall +13/−0
- dhall-lang/Prelude/Natural/sort +3/−0
- dhall-lang/Prelude/Natural/sort.dhall +61/−0
- dhall-lang/Prelude/Natural/subtract +3/−0
- dhall-lang/Prelude/Natural/subtract.dhall +18/−0
- dhall-lang/Prelude/Natural/sum +3/−17
- dhall-lang/Prelude/Natural/sum.dhall +11/−0
- dhall-lang/Prelude/Natural/toDouble +3/−16
- dhall-lang/Prelude/Natural/toDouble.dhall +10/−0
- dhall-lang/Prelude/Natural/toInteger +3/−12
- dhall-lang/Prelude/Natural/toInteger.dhall +10/−0
- dhall-lang/Prelude/NonEmpty/Type.dhall +9/−0
- dhall-lang/Prelude/NonEmpty/all.dhall +34/−0
- dhall-lang/Prelude/NonEmpty/any.dhall +34/−0
- dhall-lang/Prelude/NonEmpty/concat.dhall +61/−0
- dhall-lang/Prelude/NonEmpty/concatMap.dhall +56/−0
- dhall-lang/Prelude/NonEmpty/head.dhall +13/−0
- dhall-lang/Prelude/NonEmpty/index.dhall +33/−0
- dhall-lang/Prelude/NonEmpty/indexed.dhall +41/−0
- dhall-lang/Prelude/NonEmpty/last.dhall +17/−0
- dhall-lang/Prelude/NonEmpty/length.dhall +16/−0
- dhall-lang/Prelude/NonEmpty/make.dhall +18/−0
- dhall-lang/Prelude/NonEmpty/map.dhall +30/−0
- dhall-lang/Prelude/NonEmpty/package.dhall +73/−0
- dhall-lang/Prelude/NonEmpty/reverse.dhall +35/−0
- dhall-lang/Prelude/NonEmpty/shifted.dhall +101/−0
- dhall-lang/Prelude/NonEmpty/singleton.dhall +14/−0
- dhall-lang/Prelude/NonEmpty/toList.dhall +17/−0
- dhall-lang/Prelude/NonEmpty/unzip.dhall +58/−0
- dhall-lang/Prelude/NonEmpty/zip.dhall +63/−0
- dhall-lang/Prelude/Operator/package.dhall +85/−0
- dhall-lang/Prelude/Optional/all +3/−20
- dhall-lang/Prelude/Optional/all.dhall +16/−0
- dhall-lang/Prelude/Optional/any +3/−20
- dhall-lang/Prelude/Optional/any.dhall +16/−0
- dhall-lang/Prelude/Optional/build +3/−36
- dhall-lang/Prelude/Optional/build.dhall +41/−0
- dhall-lang/Prelude/Optional/concat +3/−28
- dhall-lang/Prelude/Optional/concat.dhall +14/−0
- dhall-lang/Prelude/Optional/concatMap.dhall +23/−0
- dhall-lang/Prelude/Optional/default +3/−0
- dhall-lang/Prelude/Optional/default.dhall +13/−0
- dhall-lang/Prelude/Optional/equal.dhall +24/−0
- dhall-lang/Prelude/Optional/filter +3/−32
- dhall-lang/Prelude/Optional/filter.dhall +29/−0
- dhall-lang/Prelude/Optional/fold +3/−21
- dhall-lang/Prelude/Optional/fold.dhall +20/−0
- dhall-lang/Prelude/Optional/head +3/−28
- dhall-lang/Prelude/Optional/head.dhall +24/−0
- dhall-lang/Prelude/Optional/last +3/−28
- dhall-lang/Prelude/Optional/last.dhall +24/−0
- dhall-lang/Prelude/Optional/length +3/−18
- dhall-lang/Prelude/Optional/length.dhall +14/−0
- dhall-lang/Prelude/Optional/map +3/−20
- dhall-lang/Prelude/Optional/map.dhall +14/−0
- dhall-lang/Prelude/Optional/null +3/−18
- dhall-lang/Prelude/Optional/null.dhall +12/−0
- dhall-lang/Prelude/Optional/package.dhall +51/−26
- dhall-lang/Prelude/Optional/toList +3/−18
- dhall-lang/Prelude/Optional/toList.dhall +12/−0
- dhall-lang/Prelude/Optional/unzip +3/−38
- dhall-lang/Prelude/Optional/unzip.dhall +30/−0
- dhall-lang/Prelude/Text/concat +3/−17
- dhall-lang/Prelude/Text/concat.dhall +11/−0
- dhall-lang/Prelude/Text/concatMap +3/−21
- dhall-lang/Prelude/Text/concatMap.dhall +22/−0
- dhall-lang/Prelude/Text/concatMapSep +3/−41
- dhall-lang/Prelude/Text/concatMapSep.dhall +38/−0
- dhall-lang/Prelude/Text/concatSep +3/−38
- dhall-lang/Prelude/Text/concatSep.dhall +31/−0
- dhall-lang/Prelude/Text/default +3/−0
- dhall-lang/Prelude/Text/default.dhall +10/−0
- dhall-lang/Prelude/Text/defaultMap +3/−0
- dhall-lang/Prelude/Text/defaultMap.dhall +13/−0
- dhall-lang/Prelude/Text/lowerASCII.dhall +56/−0
- dhall-lang/Prelude/Text/package.dhall +47/−10
- dhall-lang/Prelude/Text/replace.dhall +14/−0
- dhall-lang/Prelude/Text/replicate +3/−0
- dhall-lang/Prelude/Text/replicate.dhall +20/−0
- dhall-lang/Prelude/Text/shell-escape.dhall +16/−0
- dhall-lang/Prelude/Text/show +3/−13
- dhall-lang/Prelude/Text/show.dhall +19/−0
- dhall-lang/Prelude/Text/spaces +3/−0
- dhall-lang/Prelude/Text/spaces.dhall +20/−0
- dhall-lang/Prelude/Text/upperASCII.dhall +56/−0
- dhall-lang/Prelude/Time/package.dhall +5/−0
- dhall-lang/Prelude/Time/show.dhall +15/−0
- dhall-lang/Prelude/TimeZone/package.dhall +5/−0
- dhall-lang/Prelude/TimeZone/show.dhall +15/−0
- dhall-lang/Prelude/XML/Type +3/−0
- dhall-lang/Prelude/XML/Type.dhall +65/−0
- dhall-lang/Prelude/XML/attribute +3/−0
- dhall-lang/Prelude/XML/attribute.dhall +6/−0
- dhall-lang/Prelude/XML/element +3/−0
- dhall-lang/Prelude/XML/element.dhall +59/−0
- dhall-lang/Prelude/XML/emptyAttributes +3/−0
- dhall-lang/Prelude/XML/emptyAttributes.dhall +2/−0
- dhall-lang/Prelude/XML/leaf +3/−0
- dhall-lang/Prelude/XML/leaf.dhall +30/−0
- dhall-lang/Prelude/XML/package.dhall +33/−0
- dhall-lang/Prelude/XML/rawText.dhall +40/−0
- dhall-lang/Prelude/XML/render +3/−0
- dhall-lang/Prelude/XML/render.dhall +140/−0
- dhall-lang/Prelude/XML/text +3/−0
- dhall-lang/Prelude/XML/text.dhall +39/−0
- dhall-lang/Prelude/package.dhall +56/−11
- dhall-lang/tests/alpha-normalization/success/regression/preludeBoolFoldA.dhall +6/−0
- dhall-lang/tests/alpha-normalization/success/regression/preludeBoolFoldB.dhall +1/−0
- dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingUnderscoreB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionBindingXB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXXFreeA.dhall +3/−0
- dhall-lang/tests/alpha-normalization/success/unit/FunctionNestedBindingXYB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingUnderscoreB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeBindingXB.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXA.dhall +1/−1
- dhall-lang/tests/alpha-normalization/success/unit/FunctionTypeNestedBindingXB.dhall +1/−1
- dhall-lang/tests/binary-decode/failure/unit/ApplyNoArgs.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/LambdaExplicitlyNamedUnderscore.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/ListOneWithAnnotation.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/NaturalNegativeOne.dhallb +1/−0
- dhall-lang/tests/binary-decode/failure/unit/OperatorOrTooFewArgs.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/OperatorOrTooManyArgs.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/OperatorUnknownOpcode.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/PiExplicitlyNamedUnderscore.dhallb binary
- dhall-lang/tests/binary-decode/failure/unit/VariableExplicitlyNamedUnderscore.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/AnnotationA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/AnnotationB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ApplicationA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ApplicationB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ApplicationMultipleA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ApplicationMultipleB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/AssertA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/AssertB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BoolFalseA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/BoolFalseB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BoolIfA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/BoolIfB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BoolTrueA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/BoolTrueB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalShowA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalShowB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/BuiltinNaturalSubtractB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/BytesA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/BytesB.dhall +23/−0
- dhall-lang/tests/binary-decode/success/unit/CompletionA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/CompletionB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/DateA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/DateB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/DoubleDoubleA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/DoubleDoubleB.dhall +6/−0
- dhall-lang/tests/binary-decode/success/unit/DoubleHalfA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/DoubleHalfB.dhall +7/−0
- dhall-lang/tests/binary-decode/success/unit/DoubleInfinityA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/DoubleInfinityB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/DoubleNegativeInfinityA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/DoubleNegativeInfinityB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/DoubleSingleA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/DoubleSingleB.dhall +4/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerBigNegativeA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerBigNegativeB.dhall +2/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerBigPositiveA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/IntegerBigPositiveB.dhall +2/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerNegativeOneA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerNegativeOneB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/IntegerZeroA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/IntegerZeroB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/LambdaNamedXA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/LambdaNamedXB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/LambdaUnderscoreA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/LambdaUnderscoreB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/LetMultipleA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/LetMultipleB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/LetOneTypedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/LetOneTypedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/LetOneUntypedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/LetOneUntypedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ListEmpty0A.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/ListEmpty0B.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ListEmpty1A.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ListEmpty1B.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ListOneA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ListOneB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/MergeAnnotatedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/MergeAnnotatedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/MergeUnannotatedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/MergeUnannotatedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/NaturalBigA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/NaturalBigB.dhall +2/−0
- dhall-lang/tests/binary-decode/success/unit/NaturalTwentyFourA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/NaturalTwentyFourB.dhall +5/−0
- dhall-lang/tests/binary-decode/success/unit/NaturalZeroA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/NaturalZeroB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorAndA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorAndB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorCombineA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorCombineB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorCombineTypesA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorCombineTypesB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorEqA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorEqB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorEquivA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorEquivB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorImportAltA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorImportAltB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorListAppendA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorListAppendB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorNeqA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorNeqB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorOrA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorOrB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorPlusA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorPlusB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorPreferA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorPreferB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorTextAppendA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorTextAppendB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/OperatorTimesA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/OperatorTimesB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/PiNamedXA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/PiNamedXB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/PiUnderscoreA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/PiUnderscoreB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordFieldAccessA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/RecordFieldAccessB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordLiteralA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordLiteralB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordProjectFieldsA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/RecordProjectFieldsB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordTypeA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/RecordTypeB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/SomeA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/SomeB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/TextInterpolatedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/TextInterpolatedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/TextSimpleA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/TextSimpleB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/TimeA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/TimeB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/TimeZoneA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/TimeZoneB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ToMapA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/ToMapAnnotatedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/ToMapB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/UnionTypeA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/UnionTypeB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/VariableNamedA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/VariableNamedB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/VariableNamedOversizedIntA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/VariableNamedOversizedIntB.dhall +16/−0
- dhall-lang/tests/binary-decode/success/unit/VariableUnderscoreA.dhallb +1/−0
- dhall-lang/tests/binary-decode/success/unit/VariableUnderscoreB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/VariableUnderscoreOversizedIntA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/VariableUnderscoreOversizedIntB.dhall +13/−0
- dhall-lang/tests/binary-decode/success/unit/imports/EnvironmentVariableA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/EnvironmentVariableB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpImportWithQueryA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpImportWithQueryB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpImportWithoutQueryA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpImportWithoutQueryB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithEmptyQueryA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithEmptyQueryB.dhall +2/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithQueryA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithQueryB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithTrickyPathCharsA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithTrickyPathCharsB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithTrickyQueryCharsA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithTrickyQueryCharsB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithoutQueryA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/HttpsImportWithoutQueryB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/LocalHereImportA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/LocalHereImportB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/LocalHomeImportA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/LocalHomeImportB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/LocalParentImportA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/LocalParentImportB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/LocalRootImportA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/LocalRootImportB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/imports/MissingA.dhallb binary
- dhall-lang/tests/binary-decode/success/unit/imports/MissingB.dhall +1/−0
- dhall-lang/tests/binary-decode/success/unit/recordProjectionByExpressionA.dhallb +2/−0
- dhall-lang/tests/binary-decode/success/unit/recordProjectionByExpressionB.dhall +1/−0
- dhall-lang/tests/import/cache/dhall/12203871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc binary
- dhall-lang/tests/import/cache/dhall/1220618f785ce8f3930a9144398f576f0a992544b51212bc9108c31b4e670dc6ed21 +1/−0
- dhall-lang/tests/import/data/cors/AllowedAll.dhall +1/−0
- dhall-lang/tests/import/data/cors/Empty.dhall +1/−0
- dhall-lang/tests/import/data/cors/NoCORS.dhall +1/−0
- dhall-lang/tests/import/data/cors/Null.dhall +1/−0
- dhall-lang/tests/import/data/cors/OnlyGithub.dhall +1/−0
- dhall-lang/tests/import/data/cors/OnlyOther.dhall +1/−0
- dhall-lang/tests/import/data/cors/OnlySelf.dhall +1/−0
- dhall-lang/tests/import/data/cors/Prelude.dhall +1/−0
- dhall-lang/tests/import/data/cors/SelfImportAbsolute.dhall +1/−0
- dhall-lang/tests/import/data/cors/SelfImportRelative.dhall +1/−0
- dhall-lang/tests/import/data/cycle.dhall +1/−1
- dhall-lang/tests/import/data/doesNotParse.dhall +1/−0
- dhall-lang/tests/import/data/doesNotTypecheck.dhall +1/−0
- dhall-lang/tests/import/data/example.bin +1/−0
- dhall-lang/tests/import/data/fieldOrder/1.dhall +0/−1
- dhall-lang/tests/import/data/fieldOrder/2.dhall +0/−1
- dhall-lang/tests/import/data/file with spaces.txt +1/−0
- dhall-lang/tests/import/data/importBoundary.dhall +3/−0
- dhall-lang/tests/import/data/nested.dhall +1/−0
- dhall-lang/tests/import/data/poisonedCache.dhall +4/−0
- dhall-lang/tests/import/data/referentiallyOpaque.dhall +6/−8
- dhall-lang/tests/import/data/simpleLocation.dhall +1/−0
- dhall-lang/tests/import/data/userAgent.dhall +1/−0
- dhall-lang/tests/import/failure/customHeadersUsingBoundVariable.dhall +15/−0
- dhall-lang/tests/import/failure/cycle.dhall +0/−1
- dhall-lang/tests/import/failure/hashMismatch.dhall +0/−1
- dhall-lang/tests/import/failure/missing.dhall +0/−1
- dhall-lang/tests/import/failure/originHeadersFromRemote.dhall +1/−0
- dhall-lang/tests/import/failure/originHeadersFromRemoteENV.dhall +11/−0
- dhall-lang/tests/import/failure/referentiallyInsane.dhall +0/−13
- dhall-lang/tests/import/failure/unit/404.dhall +1/−0
- dhall-lang/tests/import/failure/unit/Cycle.dhall +1/−0
- dhall-lang/tests/import/failure/unit/DontRecoverCycle.dhall +1/−0
- dhall-lang/tests/import/failure/unit/DontRecoverHashMismatch.dhall +3/−0
- dhall-lang/tests/import/failure/unit/DontRecoverParseError.dhall +1/−0
- dhall-lang/tests/import/failure/unit/DontRecoverTypeError.dhall +1/−0
- dhall-lang/tests/import/failure/unit/EnvFromRemote.dhall +13/−0
- dhall-lang/tests/import/failure/unit/EnvUnset.dhall +1/−0
- dhall-lang/tests/import/failure/unit/EnvUnsetAsText.dhall +1/−0
- dhall-lang/tests/import/failure/unit/FileMissing.dhall +1/−0
- dhall-lang/tests/import/failure/unit/HashMismatch.dhall +1/−0
- dhall-lang/tests/import/failure/unit/HashMismatch2.dhall +2/−0
- dhall-lang/tests/import/failure/unit/Missing.dhall +1/−0
- dhall-lang/tests/import/failure/unit/VarAcrossImportBoundary.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/Empty.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/NoCORS.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/Null.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/OnlyOther.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/OnlySelf.dhall +1/−0
- dhall-lang/tests/import/failure/unit/cors/TwoHops.dhall +1/−0
- dhall-lang/tests/import/home/hello.dhall +1/−0
- dhall-lang/tests/import/success/alternativeEnvNaturalA.dhall +0/−1
- dhall-lang/tests/import/success/alternativeEnvNaturalB.dhall +0/−1
- dhall-lang/tests/import/success/alternativeEnvSimpleA.dhall +0/−1
- dhall-lang/tests/import/success/alternativeEnvSimpleB.dhall +0/−1
- dhall-lang/tests/import/success/alternativeHashMismatchA.dhall +0/−2
- dhall-lang/tests/import/success/alternativeHashMismatchB.dhall +0/−1
- dhall-lang/tests/import/success/alternativeNaturalA.dhall +0/−1
- dhall-lang/tests/import/success/alternativeNaturalB.dhall +0/−1
- dhall-lang/tests/import/success/alternativeParseErrorA.dhall +0/−1
- dhall-lang/tests/import/success/alternativeParseErrorB.dhall +0/−1
- dhall-lang/tests/import/success/asTextA.dhall +0/−1
- dhall-lang/tests/import/success/asTextB.dhall +0/−3
- dhall-lang/tests/import/success/customHeadersA.dhall +1/−1
- dhall-lang/tests/import/success/fieldOrderA.dhall +0/−5
- dhall-lang/tests/import/success/fieldOrderB.dhall +0/−1
- dhall-lang/tests/import/success/hashFromCacheA.dhall +11/−0
- dhall-lang/tests/import/success/hashFromCacheB.dhall +3/−0
- dhall-lang/tests/import/success/headerForwardingA.dhall +5/−9
- dhall-lang/tests/import/success/headerForwardingB.dhall +1/−26
- dhall-lang/tests/import/success/nestedHashA.dhall +1/−0
- dhall-lang/tests/import/success/nestedHashB.dhall +1/−0
- dhall-lang/tests/import/success/noHeaderForwardingA.dhall +1/−1
- dhall-lang/tests/import/success/originHeadersA.dhall +1/−0
- dhall-lang/tests/import/success/originHeadersB.dhall +5/−0
- dhall-lang/tests/import/success/originHeadersENV.dhall +10/−0
- dhall-lang/tests/import/success/originHeadersImportA.dhall +1/−0
- dhall-lang/tests/import/success/originHeadersImportB.dhall +5/−0
- dhall-lang/tests/import/success/originHeadersImportENV.dhall +10/−0
- dhall-lang/tests/import/success/originHeadersImportFromEnvA.dhall +1/−0
- dhall-lang/tests/import/success/originHeadersImportFromEnvB.dhall +5/−0
- dhall-lang/tests/import/success/originHeadersImportFromEnvENV.dhall +11/−0
- dhall-lang/tests/import/success/originHeadersOverrideA.dhall +3/−0
- dhall-lang/tests/import/success/originHeadersOverrideB.dhall +5/−0
- dhall-lang/tests/import/success/originHeadersOverrideENV.dhall +10/−0
- dhall-lang/tests/import/success/unit/AlternativeChain1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeChain1B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeChain2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeChain2B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeEnvA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeEnvB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeImportErrorA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeImportErrorB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNestedImportErrorA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNestedImportErrorB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError1B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError2B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError3A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeNoError3B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeSubExprA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeSubExprB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithVariableA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithVariableB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithWrongVariable1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithWrongVariable1B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithWrongVariable2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/AlternativeWithWrongVariable2B.dhall +1/−0
- dhall-lang/tests/import/success/unit/AsBytesA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AsBytesB.dhall +1/−0
- dhall-lang/tests/import/success/unit/AsTextA.dhall +1/−0
- dhall-lang/tests/import/success/unit/AsTextB.dhall +3/−0
- dhall-lang/tests/import/success/unit/DontCacheIfHashA.dhall +5/−0
- dhall-lang/tests/import/success/unit/DontCacheIfHashB.dhall +1/−0
- dhall-lang/tests/import/success/unit/EnvSetA.dhall +1/−0
- dhall-lang/tests/import/success/unit/EnvSetAsTextA.dhall +1/−0
- dhall-lang/tests/import/success/unit/EnvSetAsTextB.dhall +1/−0
- dhall-lang/tests/import/success/unit/EnvSetB.dhall +1/−0
- dhall-lang/tests/import/success/unit/FilenameWithSpacesA.dhall +1/−0
- dhall-lang/tests/import/success/unit/FilenameWithSpacesB.dhall +1/−0
- dhall-lang/tests/import/success/unit/IgnorePoisonedCacheA.dhall +1/−0
- dhall-lang/tests/import/success/unit/IgnorePoisonedCacheB.dhall +1/−0
- dhall-lang/tests/import/success/unit/ImportRelativeToHomeA.dhall +1/−0
- dhall-lang/tests/import/success/unit/ImportRelativeToHomeB.dhall +1/−0
- dhall-lang/tests/import/success/unit/MixImportModesA.dhall +2/−0
- dhall-lang/tests/import/success/unit/MixImportModesB.dhall +1/−0
- dhall-lang/tests/import/success/unit/NormalizeA.dhall +1/−0
- dhall-lang/tests/import/success/unit/NormalizeB.dhall +1/−0
- dhall-lang/tests/import/success/unit/QuotedPathA.dhall +1/−0
- dhall-lang/tests/import/success/unit/QuotedPathB.dhall +3/−0
- dhall-lang/tests/import/success/unit/RecoverTransitiveFailureA.dhall +1/−0
- dhall-lang/tests/import/success/unit/RecoverTransitiveFailureB.dhall +1/−0
- dhall-lang/tests/import/success/unit/RemoteAsTextA.dhall +1/−0
- dhall-lang/tests/import/success/unit/RemoteAsTextB.dhall +3/−0
- dhall-lang/tests/import/success/unit/SimpleA.dhall +1/−0
- dhall-lang/tests/import/success/unit/SimpleB.dhall +1/−0
- dhall-lang/tests/import/success/unit/SimpleHashA.dhall +1/−0
- dhall-lang/tests/import/success/unit/SimpleHashB.dhall +1/−0
- dhall-lang/tests/import/success/unit/SimpleRemoteA.dhall +1/−0
- dhall-lang/tests/import/success/unit/SimpleRemoteB.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/AbsoluteA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/AbsoluteB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize1B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize2B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize3A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize3B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize4A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize4B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize5A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Canonicalize5B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain1B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain2B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain3A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Chain3B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/DontTryResolvingA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/DontTryResolvingB.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/EnvA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/EnvB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/HashA.dhall +6/−0
- dhall-lang/tests/import/success/unit/asLocation/HashB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/HomeA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/HomeB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/MissingA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/MissingB.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Relative1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Relative1B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/Relative2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/Relative2B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteA.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize1B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize2B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize3A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize3B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize4A.dhall +4/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteCanonicalize4B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain1A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain1B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain2B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain3A.dhall +1/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChain3B.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChainEnvA.dhall +5/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChainEnvB.dhall +2/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChainMissingA.dhall +6/−0
- dhall-lang/tests/import/success/unit/asLocation/RemoteChainMissingB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/AllowedAllA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/AllowedAllB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/NoCORSFromLocalA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/NoCORSFromLocalB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/OnlyGithubA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/OnlyGithubB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/PreludeA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/PreludeB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportAbsolute2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportAbsolute2B.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportAbsoluteA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportAbsoluteB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportRelative2A.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportRelative2B.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportRelativeA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/SelfImportRelativeB.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/TwoHopsA.dhall +1/−0
- dhall-lang/tests/import/success/unit/cors/TwoHopsB.dhall +1/−0
- dhall-lang/tests/normalization/success/WithRecordValueA.dhall +12/−0
- dhall-lang/tests/normalization/success/WithRecordValueB.dhall +1/−0
- dhall-lang/tests/normalization/success/prelude/Bool/and/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/and/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/and/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/and/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/build/0A.dhall +0/−2
- dhall-lang/tests/normalization/success/prelude/Bool/build/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/build/1A.dhall +0/−2
- dhall-lang/tests/normalization/success/prelude/Bool/build/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/2A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/2B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/3A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/even/3B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/fold/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/fold/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/fold/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/fold/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/not/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/not/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/not/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/not/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/2A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/2B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/3A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/odd/3B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/or/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/or/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/or/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/or/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/show/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/show/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/show/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Bool/show/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Double/show/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Double/show/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Double/show/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Double/show/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/show/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/show/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/show/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/show/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/all/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/all/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/all/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/all/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/any/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/any/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/any/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/any/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/build/0A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/List/build/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/build/1A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/List/build/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concat/0A.dhall +0/−5
- dhall-lang/tests/normalization/success/prelude/List/concat/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concat/1A.dhall +0/−5
- dhall-lang/tests/normalization/success/prelude/List/concat/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concatMap/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concatMap/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concatMap/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/concatMap/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/filter/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/filter/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/filter/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/filter/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/fold/0A.dhall +0/−6
- dhall-lang/tests/normalization/success/prelude/List/fold/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/fold/1A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/List/fold/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/fold/2A.dhall +0/−4
- dhall-lang/tests/normalization/success/prelude/List/fold/2B.dhall +0/−4
- dhall-lang/tests/normalization/success/prelude/List/generate/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/generate/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/generate/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/generate/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/head/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/head/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/head/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/head/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/indexed/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/indexed/0B.dhall +0/−4
- dhall-lang/tests/normalization/success/prelude/List/indexed/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/indexed/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/iterate/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/iterate/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/iterate/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/iterate/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/last/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/last/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/last/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/last/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/length/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/length/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/length/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/length/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/map/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/map/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/map/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/map/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/null/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/null/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/null/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/null/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/replicate/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/replicate/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/replicate/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/replicate/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/reverse/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/reverse/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/reverse/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/reverse/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/shifted/0A.dhall +0/−15
- dhall-lang/tests/normalization/success/prelude/List/shifted/0B.dhall +0/−10
- dhall-lang/tests/normalization/success/prelude/List/shifted/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/shifted/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/unzip/0A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/List/unzip/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/unzip/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/List/unzip/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/build/0A.dhall +0/−6
- dhall-lang/tests/normalization/success/prelude/Natural/build/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/build/1A.dhall +0/−6
- dhall-lang/tests/normalization/success/prelude/Natural/build/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/even/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/even/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/even/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/even/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/fold/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/fold/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/fold/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/fold/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/fold/2A.dhall +0/−4
- dhall-lang/tests/normalization/success/prelude/Natural/fold/2B.dhall +0/−4
- dhall-lang/tests/normalization/success/prelude/Natural/isZero/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/isZero/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/isZero/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/isZero/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/odd/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/odd/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/odd/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/odd/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/product/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/product/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/product/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/product/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/show/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/show/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/show/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/show/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/sum/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/sum/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/sum/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/sum/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/all/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/all/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/all/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/all/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/any/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/any/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/any/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/any/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/build/0A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/Optional/build/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/build/1A.dhall +0/−7
- dhall-lang/tests/normalization/success/prelude/Optional/build/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/2A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/concat/2B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/filter/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/filter/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/filter/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/filter/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/fold/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/fold/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/fold/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/fold/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/2A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/head/2B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/2A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/last/2B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/length/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/length/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/length/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/length/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/map/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/map/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/map/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/map/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/null/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/null/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/null/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/null/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/toList/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/toList/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/toList/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/toList/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/unzip/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/unzip/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/unzip/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Optional/unzip/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concat/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concat/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concat/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concat/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMap/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMap/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMap/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMap/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatSep/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatSep/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatSep/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/concatSep/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/show/0A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/show/0B.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/show/1A.dhall +0/−1
- dhall-lang/tests/normalization/success/prelude/Text/show/1B.dhall +0/−1
- dhall-lang/tests/normalization/success/regression/ComplexRecordSimplificationA.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/ComplexRecordSimplificationB.dhall +3/−0
- dhall-lang/tests/normalization/success/regression/NaturalFoldExtraArgA.dhall +2/−0
- dhall-lang/tests/normalization/success/regression/NaturalFoldExtraArgB.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/ToMapQuotedFieldsA.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/ToMapQuotedFieldsB.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/TrickyBinderIdentityA.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/TrickyBinderIdentityB.dhall +1/−0
- dhall-lang/tests/normalization/success/regression/UnsaturatedBuiltinsA.dhall +16/−0
- dhall-lang/tests/normalization/success/regression/UnsaturatedBuiltinsB.dhall +3/−0
- dhall-lang/tests/normalization/success/remoteSystemsA.dhall +7/−8
- dhall-lang/tests/normalization/success/remoteSystemsB.dhall +3/−6
- dhall-lang/tests/normalization/success/simple/completionA.dhall +10/−0
- dhall-lang/tests/normalization/success/simple/completionB.dhall +5/−0
- dhall-lang/tests/normalization/success/simple/equalNoCommuteA.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/equalNoCommuteB.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/notEqualNoCommuteA.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/notEqualNoCommuteB.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/optionalBuildA.dhall +0/−32
- dhall-lang/tests/normalization/success/simple/optionalBuildB.dhall +0/−9
- dhall-lang/tests/normalization/success/simple/optionalBuildFoldA.dhall +0/−1
- dhall-lang/tests/normalization/success/simple/optionalBuildFoldB.dhall +0/−1
- dhall-lang/tests/normalization/success/simple/optionalFoldA.dhall +0/−7
- dhall-lang/tests/normalization/success/simple/optionalFoldB.dhall +0/−1
- dhall-lang/tests/normalization/success/simple/plusNoCommuteA.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/plusNoCommuteB.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/timesNoCommuteA.dhall +1/−0
- dhall-lang/tests/normalization/success/simple/timesNoCommuteB.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/issue661A.dhall +17/−0
- dhall-lang/tests/normalization/success/simplifications/issue661B.dhall +2/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0A.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0B.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1A.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1B.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/AssertNormalizeArgumentB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/BareInterpolationA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/BareInterpolationB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/BytesA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/BytesB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/BytesLiteralA.dhall +23/−0
- dhall-lang/tests/normalization/success/unit/BytesLiteralB.dhall +23/−0
- dhall-lang/tests/normalization/success/unit/CompletionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/CompletionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/EmptyToMapA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/EmptyToMapB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/EquivalenceNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationCaptureB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationNoSubstituteB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsA.dhall +3/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionApplicationSubstituteB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/FunctionTypeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IfAlternativesIdenticalB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesA.dhall +4/−1
- dhall-lang/tests/normalization/success/unit/IfNormalizePredicateAndBranchesB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IfTrivialA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IfTrivialB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/IntegerClampA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampNegativeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampNegativeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampPositiveA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampPositiveB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampZeroA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerClampZeroB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateNegativeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateNegativeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegatePositiveA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegatePositiveB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateZeroA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/IntegerNegateZeroB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/LetA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/LetB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/LetWithTypeA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/LetWithTypeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListBuildFoldFusionB.dhall +8/−1
- dhall-lang/tests/normalization/success/unit/ListBuildImplementationA.dhall +3/−1
- dhall-lang/tests/normalization/success/unit/ListBuildImplementationB.dhall +3/−1
- dhall-lang/tests/normalization/success/unit/ListFoldEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListFoldEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListFoldOneA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListFoldOneB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListHeadEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListHeadEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListIndexedEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListIndexedEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListLastEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListLastEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListLengthEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListLengthEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListNormalizeElementsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListNormalizeElementsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListNormalizeTypeAnnotationA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListNormalizeTypeAnnotationB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListReverseEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/ListReverseEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeEmptyAlternativeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeNoneA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/MergeNoneB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsA.dhall +3/−1
- dhall-lang/tests/normalization/success/unit/MergeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeSomeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/MergeSomeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/MergeWithTypeA.dhall +4/−1
- dhall-lang/tests/normalization/success/unit/MergeWithTypeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsA.dhall +5/−1
- dhall-lang/tests/normalization/success/unit/MergeWithTypeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalBuildFoldFusionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationA.dhall +2/−2
- dhall-lang/tests/normalization/success/unit/NaturalBuildImplementationB.dhall +2/−1
- dhall-lang/tests/normalization/success/unit/NaturalFoldOneA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalFoldOneB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalFoldZeroA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalFoldZeroB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractEquivalentB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractFromZeroB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractGreaterB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractLessA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractLessB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractNormalizeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractZero0B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NaturalSubtractZero1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NestedRecordProjectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NestedRecordProjectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NestedRecordProjectionByTypeA.dhall +2/−0
- dhall-lang/tests/normalization/success/unit/NestedRecordProjectionByTypeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/NoneNaturalA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/NoneNaturalB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndEquivalentArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndLhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndLhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndRhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorAndRhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualEquivalentArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualLhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorEqualRhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateLhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateListListB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall +4/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorListConcatenateRhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualEquivalentArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualLhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorNotEqualRhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrEquivalentArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrLhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrLhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrRhsFalseB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorOrRhsTrueB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusLhsZeroB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorPlusRhsZeroB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsEmptyB.dhall +1/−5
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateLhsNonEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsEmptyB.dhall +1/−5
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTextConcatenateRhsNonEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesLhsOneB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesLhsZeroB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesRhsOneB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OperatorTimesRhsZeroB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/OptionalBuildA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalBuildB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalBuildFoldFusionB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationA.dhall +0/−3
- dhall-lang/tests/normalization/success/unit/OptionalBuildImplementationB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldNoneA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldNoneB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldSomeA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/OptionalFoldSomeB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/RecordA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordLitAllSugarsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitAllSugarsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitDottedFieldsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitDottedFieldsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitDuplicateFieldsNoCollisionsA.dhall +9/−0
- dhall-lang/tests/normalization/success/unit/RecordLitDuplicateFieldsNoCollisionsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitNixLikeA.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/RecordLitNixLikeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitPun1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitPun1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitPun2A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitPun2B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordLitTriplicateFieldsA.dhall +7/−0
- dhall-lang/tests/normalization/success/unit/RecordLitTriplicateFieldsB.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeEmptyA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeEmptyB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNonEmptyA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNonEmptyB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeNormalizeProjectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionByTypeWithinFieldSelectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeFieldsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionNormalizeFieldsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionTypeEmptyB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionTypeNonEmptyB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordProjectionWithinFieldSelectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordSelectionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordSelectionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordSelectionNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordSortFieldsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordSortFieldsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordTypeA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordTypeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecordTypeSortFieldsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecordTypeSortFieldsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeLhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNoCollisionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeRhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection0B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection2B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordMergeWithinFieldSelection3B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeCollisionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeDeepA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeDeepB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeLhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNoCollisionB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeEquivalentArgumentsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection0B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection2B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedMergeWithinFieldSelection3B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeLhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeWithinRecordProjectionA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/RightBiasedRecordMergeWithinRecordProjectionB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ShowConstructorEmptyA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ShowConstructorEmptyB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ShowConstructorNonEmptyA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ShowConstructorNonEmptyB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/SomeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextInterpolateA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextInterpolateB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextLitNested1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextLitNested1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextLitNested2A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextLitNested2B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextLitNested3A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextLitNested3B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextNormalizeInterpolationsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextReplaceAbstractA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceAbstractB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceAbstractHaystackA.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceAbstractHaystackB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty1A.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty1B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty2A.dhall +2/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty2B.dhall +2/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty3A.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceEmpty3B.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceMultipleA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceMultipleB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceNFCUnicodeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceNFCUnicodeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceNormalizationA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceNormalizationB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceOverlappingA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceOverlappingB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceSimpleA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceSimpleB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceUnicodeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceUnicodeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceVarA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/TextReplaceVarB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextShowEmptyA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextShowEmptyB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/TextShowInterpolatedA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TextShowInterpolatedB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TimeAsRecordA.dhall +2/−0
- dhall-lang/tests/normalization/success/unit/TimeAsRecordB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ToMapA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/ToMapB.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/ToMapWithTypeA.dhall +16/−0
- dhall-lang/tests/normalization/success/unit/ToMapWithTypeB.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/TypeAnnotationA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/TypeAnnotationB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeAlternativesB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralNormalizeArgumentsB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesA.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionLiteralSortAlternativesB.dhall +0/−1
- dhall-lang/tests/normalization/success/unit/UnionProjectConstructorA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionProjectConstructorB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionTypeA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionTypeB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/UnionTypeNormalizeArgumentsB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/VariableA.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/VariableB.dhall +1/−1
- dhall-lang/tests/normalization/success/unit/WithA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithChainedA.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/WithChainedB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithCreateIntermediateRecordsA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/WithCreateIntermediateRecordsB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithDesugarA.dhall +3/−0
- dhall-lang/tests/normalization/success/unit/WithDesugarB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithNestedA.dhall +12/−0
- dhall-lang/tests/normalization/success/unit/WithNestedB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOnOptionalNoneA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOnOptionalNoneB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOnOptionalSomeA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOnOptionalSomeB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOptionalDeeplyNestedA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOptionalDeeplyNestedB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOptionalNestedA.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithOptionalNestedB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithPartiallyAbstractA.dhall +4/−0
- dhall-lang/tests/normalization/success/unit/WithPartiallyAbstractB.dhall +1/−0
- dhall-lang/tests/normalization/success/unit/WithPriorityA.dhall +6/−0
- dhall-lang/tests/normalization/success/unit/WithPriorityB.dhall +1/−0
- dhall-lang/tests/parser/failure/ImportHeadersExteriorHash.dhall +1/−0
- dhall-lang/tests/parser/failure/ProjectionByTypeNeedsParens.dhall +1/−0
- dhall-lang/tests/parser/failure/assertBinding.dhall +1/−0
- dhall-lang/tests/parser/failure/boundBuiltins.dhall +1/−1
- dhall-lang/tests/parser/failure/bytesInvalid.dhall +1/−0
- dhall-lang/tests/parser/failure/bytesOddLength.dhall +1/−0
- dhall-lang/tests/parser/failure/missingSpace.dhall +0/−2
- dhall-lang/tests/parser/failure/nonBase16Hash.dhall +1/−0
- dhall-lang/tests/parser/failure/nonCharacter.dhall +1/−0
- dhall-lang/tests/parser/failure/nonCharacterUnbraced.dhall +6/−0
- dhall-lang/tests/parser/failure/nonUtf8.dhall +4/−0
- dhall-lang/tests/parser/failure/spacing/AnnotationNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ApplicationNoSpace1.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ApplicationNoSpace2.dhall +2/−0
- dhall-lang/tests/parser/failure/spacing/AssertNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ForallNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/HeadersNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/IfNoSpace1.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/IfNoSpace2.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/IfNoSpace3.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ImportAltNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ImportHashedNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LambdaNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LetAnnotNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LetNoSpace1.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LetNoSpace2.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LetNoSpace3.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/LetNoSpace4.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ListLitEmptyNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/MergeAnnotationNoSpace3.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/MergeNoSpace1.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/MergeNoSpace2.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/NaturalPlusNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/RecordTypeNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/SomeNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ToMapAnnotNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/ToMapNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/spacing/UnionTypeNoSpace.dhall +1/−0
- dhall-lang/tests/parser/failure/surrogatePairUnbraced.dhall +5/−0
- dhall-lang/tests/parser/failure/time/DateTimeZone.dhall +2/−0
- dhall-lang/tests/parser/failure/time/InvalidDayOfMonth.dhall +2/−0
- dhall-lang/tests/parser/failure/time/InvalidHour.dhall +2/−0
- dhall-lang/tests/parser/failure/time/InvalidLeapSecond.dhall +3/−0
- dhall-lang/tests/parser/failure/time/InvalidMinute.dhall +2/−0
- dhall-lang/tests/parser/failure/time/InvalidMonth.dhall +2/−0
- dhall-lang/tests/parser/failure/time/InvalidSecond.dhall +2/−0
- dhall-lang/tests/parser/failure/time/NegativeYear.dhall +2/−0
- dhall-lang/tests/parser/failure/time/YearTooLarge.dhall +2/−0
- dhall-lang/tests/parser/failure/unit/AssertNoAnnotation.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/BoolLitTrueWithIndex.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/BuiltinBoolWithIndex.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/BuiltinTypeWithIndex.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/ImportEnvWrongEscape.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/ListLitEmptyAnnotation.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/ListLitEmptyMissingAnnotation.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/ListLitTwoCommas.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/MergeAlone.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/MergeOneArgument.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/NaturalLitLeadingZero.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/OldUnionLitSyntax.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/ProjectionTwoCommas.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword00.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword01.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword02.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword03.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword04.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword05.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword06.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword07.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword08.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword09.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword10.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword11.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword12.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword13.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordFieldMustNotBeKeyword14.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordLitPunDotted.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/RecordTwoCommas.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/SomeAlone.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/UnionTypeTwoDelims.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/UrlWithQuotedPath.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/UsingToMap.dhall +8/−0
- dhall-lang/tests/parser/failure/unit/WithPrecedence1.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/WithPrecedence2.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/WithPrecedence3.dhall +1/−0
- dhall-lang/tests/parser/failure/unit/WithWhitespace.dhall +2/−0
- dhall-lang/tests/parser/failure/unit/showConstructorAlone.dhall +1/−0
- dhall-lang/tests/parser/failure/urlWithoutPath.dhall +0/−2
- dhall-lang/tests/parser/success/RecordProjectionByType.dhall +0/−15
- dhall-lang/tests/parser/success/annotationsA.dhall +1/−4
- dhall-lang/tests/parser/success/annotationsB.dhallb binary
- dhall-lang/tests/parser/success/binaryA.dhall +8/−0
- dhall-lang/tests/parser/success/binaryB.dhallb binary
- dhall-lang/tests/parser/success/builtinsA.dhall +40/−32
- dhall-lang/tests/parser/success/builtinsB.dhallb binary
- dhall-lang/tests/parser/success/bytesA.dhall +25/−0
- dhall-lang/tests/parser/success/bytesB.dhallb binary
- dhall-lang/tests/parser/success/doubleA.dhall +0/−1
- dhall-lang/tests/parser/success/doubleB.dhallb binary
- dhall-lang/tests/parser/success/hexadecimalA.dhall +6/−0
- dhall-lang/tests/parser/success/hexadecimalB.dhallb +1/−0
- dhall-lang/tests/parser/success/ifThenElseA.dhall +0/−1
- dhall-lang/tests/parser/success/ifThenElseB.dhallb +0/−1
- dhall-lang/tests/parser/success/largeExpressionA.dhall +5/−6
- dhall-lang/tests/parser/success/largeExpressionB.dhallb binary
- dhall-lang/tests/parser/success/leadingSeparatorsA.dhall +10/−0
- dhall-lang/tests/parser/success/leadingSeparatorsB.dhallb +1/−0
- dhall-lang/tests/parser/success/letA.dhall +0/−3
- dhall-lang/tests/parser/success/letB.dhallb binary
- dhall-lang/tests/parser/success/lineCommentCRLFA.dhall +3/−0
- dhall-lang/tests/parser/success/lineCommentCRLFB.dhallb +1/−0
- dhall-lang/tests/parser/success/listWithCommentA.dhall +3/−0
- dhall-lang/tests/parser/success/listWithCommentB.dhallb +1/−0
- dhall-lang/tests/parser/success/missingFooA.dhall +1/−0
- dhall-lang/tests/parser/success/missingFooB.dhallb binary
- dhall-lang/tests/parser/success/missingInParenthesesA.dhall +1/−0
- dhall-lang/tests/parser/success/missingInParenthesesB.dhallb binary
- dhall-lang/tests/parser/success/missingSlashA.dhall +1/−0
- dhall-lang/tests/parser/success/missingSlashB.dhallb binary
- dhall-lang/tests/parser/success/mixedBlockLineCommentA.dhall +6/−0
- dhall-lang/tests/parser/success/mixedBlockLineCommentB.dhallb +1/−0
- dhall-lang/tests/parser/success/multiletA.dhall +0/−3
- dhall-lang/tests/parser/success/multiletB.dhallb binary
- dhall-lang/tests/parser/success/naturalA.dhall +1/−1
- dhall-lang/tests/parser/success/naturalB.dhallb binary
- dhall-lang/tests/parser/success/preferMissingNoSpacesA.dhall +1/−0
- dhall-lang/tests/parser/success/preferMissingNoSpacesB.dhallb binary
- dhall-lang/tests/parser/success/quotedLabelA.dhall +1/−0
- dhall-lang/tests/parser/success/quotedLabelB.dhallb binary
- dhall-lang/tests/parser/success/quotedRecordLabelA.dhall +1/−0
- dhall-lang/tests/parser/success/quotedRecordLabelB.dhallb +1/−0
- dhall-lang/tests/parser/success/quotedUnionLabelA.dhall +1/−0
- dhall-lang/tests/parser/success/quotedUnionLabelB.dhallb +1/−0
- dhall-lang/tests/parser/success/recordProjectionByExpressionA.dhall +15/−0
- dhall-lang/tests/parser/success/recordProjectionByExpressionB.dhallb binary
- dhall-lang/tests/parser/success/text/dollarSignA.dhall +1/−0
- dhall-lang/tests/parser/success/text/dollarSignB.dhallb +1/−0
- dhall-lang/tests/parser/success/text/escapedDoubleQuotedStringA.dhall +1/−1
- dhall-lang/tests/parser/success/text/escapedDoubleQuotedStringB.dhallb +2/−2
- dhall-lang/tests/parser/success/text/multilinePreserveCommentA.dhall +8/−0
- dhall-lang/tests/parser/success/text/multilinePreserveCommentB.dhallb +2/−0
- dhall-lang/tests/parser/success/text/nonAssignedUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/text/nonAssignedUnicodeB.dhallb +1/−0
- dhall-lang/tests/parser/success/text/preserveCommentA.dhall +1/−8
- dhall-lang/tests/parser/success/text/preserveCommentB.dhallb +1/−2
- dhall-lang/tests/parser/success/text/singleQuoteConcatA.dhall +5/−0
- dhall-lang/tests/parser/success/text/singleQuoteConcatB.dhallb +1/−0
- dhall-lang/tests/parser/success/text/unicodeBracedA.dhall +1/−0
- dhall-lang/tests/parser/success/text/unicodeBracedB.dhallb +1/−0
- dhall-lang/tests/parser/success/text/unicodeEscapedA.dhall +1/−0
- dhall-lang/tests/parser/success/text/unicodeEscapedB.dhallb +1/−0
- dhall-lang/tests/parser/success/text/unicodePlane16A.dhall +1/−0
- dhall-lang/tests/parser/success/text/unicodePlane16B.dhallb +1/−0
- dhall-lang/tests/parser/success/time/DateTimeA.dhall +1/−0
- dhall-lang/tests/parser/success/time/DateTimeB.dhallb binary
- dhall-lang/tests/parser/success/time/DateTimeTimeZoneA.dhall +1/−0
- dhall-lang/tests/parser/success/time/DateTimeTimeZoneB.dhallb binary
- dhall-lang/tests/parser/success/time/LowercaseTA.dhall +2/−0
- dhall-lang/tests/parser/success/time/LowercaseTB.dhallb binary
- dhall-lang/tests/parser/success/time/TimeTimeZoneA.dhall +1/−0
- dhall-lang/tests/parser/success/time/TimeTimeZoneB.dhallb binary
- dhall-lang/tests/parser/success/time/TimeTimeZoneZA.dhall +5/−0
- dhall-lang/tests/parser/success/time/TimeTimeZoneZB.dhallb binary
- dhall-lang/tests/parser/success/toMapA.dhall +1/−0
- dhall-lang/tests/parser/success/toMapB.dhallb +1/−0
- dhall-lang/tests/parser/success/unionA.dhall +0/−4
- dhall-lang/tests/parser/success/unionB.dhallb +0/−1
- dhall-lang/tests/parser/success/unit/AnnotationA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/AnnotationB.dhallb binary
- dhall-lang/tests/parser/success/unit/AssertA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/AssertB.dhallb binary
- dhall-lang/tests/parser/success/unit/AssertEquivalenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/AssertEquivalenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/AssertEquivalenceUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/AssertPrecedenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/AssertPrecedenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/BuiltinListBuildA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/BuiltinListBuildB.dhallb binary
- dhall-lang/tests/parser/success/unit/CompletionA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/CompletionB.dhallb binary
- dhall-lang/tests/parser/success/unit/DateA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DateB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DateLiteralA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DateLiteralB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DeBruijnIndexA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DeBruijnIndexB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLit16bitA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLit16bitB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLit32bitA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLit32bitB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLit64bitA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLit64bitB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitExponentA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitExponentB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitExponentNegativeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitExponentNoDotB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitInfinityA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitInfinityB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitNaNA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitNaNB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitNegInfinityB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitNegZeroA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitNegZeroB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitNegativeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitNegativeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitPositiveA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitPositiveB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitSecretlyIntA.dhall +5/−0
- dhall-lang/tests/parser/success/unit/DoubleLitSecretlyIntB.dhallb binary
- dhall-lang/tests/parser/success/unit/DoubleLitZeroA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/DoubleLitZeroB.dhallb binary
- dhall-lang/tests/parser/success/unit/EmptyRecordLiteralA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/EmptyRecordLiteralB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/FieldA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FieldB.dhallb binary
- dhall-lang/tests/parser/success/unit/FieldBuiltinNameA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FieldBuiltinNameB.dhallb binary
- dhall-lang/tests/parser/success/unit/FieldQuotedA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FieldQuotedB.dhallb binary
- dhall-lang/tests/parser/success/unit/ForallUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ForallUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionApplicationMultipleArgsB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionApplicationOneArgB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionTypeArrowA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionTypeArrowB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionTypePiA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionTypePiB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionTypePiNestedA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionTypePiNestedB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionTypePiUnderscoreB.dhallb binary
- dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/FunctionTypePiUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/LambdaUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LambdaUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/LetA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LetAnnotA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LetAnnotB.dhallb binary
- dhall-lang/tests/parser/success/unit/LetB.dhallb binary
- dhall-lang/tests/parser/success/unit/LetMultiA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LetMultiB.dhallb binary
- dhall-lang/tests/parser/success/unit/LetNestedA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LetNestedB.dhallb binary
- dhall-lang/tests/parser/success/unit/LetNoAnnotA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/LetNoAnnotB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitEmpty1A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitEmpty1B.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitEmpty2A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitEmpty2B.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitEmptyA.dhall +0/−1
- dhall-lang/tests/parser/success/unit/ListLitEmptyB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitEmptyCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitEmptyCommaB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/ListLitEmptyPrecedenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitEmptyPrecedenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitLeadingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitLeadingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitNonEmptyA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitNonEmptyAnnotatedB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitNonEmptyB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitTrailingAndLeadingCommasA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitTrailingAndLeadingCommasB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListLitTrailingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ListLitTrailingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/ListWithNewlineA.dhall +11/−0
- dhall-lang/tests/parser/success/unit/ListWithNewlineB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/ProjectionA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ProjectionB.dhallb binary
- dhall-lang/tests/parser/success/unit/ProjectionLeadingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ProjectionLeadingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/ProjectionTrailingAndLeadingCommasA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ProjectionTrailingAndLeadingCommasB.dhallb binary
- dhall-lang/tests/parser/success/unit/ProjectionTrailingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ProjectionTrailingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitDottedA.dhall +7/−0
- dhall-lang/tests/parser/success/unit/RecordLitDottedB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitDottedEscapeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitDottedEscapeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitDuplicatesA.dhall +7/−0
- dhall-lang/tests/parser/success/unit/RecordLitDuplicatesB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyBothCommasA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyBothCommasB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyLeadingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyLeadingCommaB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyTrailingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitEmptyTrailingCommaB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitLeadingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitLeadingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitNixLikeA.dhall +5/−0
- dhall-lang/tests/parser/success/unit/RecordLitNixLikeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitPunA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitPunB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitPunDuplicateA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitPunDuplicateB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitPunMixedA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitPunMixedB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitPunSomeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitPunSomeB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitSomeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitSomeB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitTrailingAndLeadingCommasA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitTrailingAndLeadingCommasB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordLitTrailingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordLitTrailingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordProjectionByTypeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordProjectionByTypeB.dhallb +2/−0
- dhall-lang/tests/parser/success/unit/RecordProjectionByTypeEmptyA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordProjectionByTypeEmptyB.dhallb +2/−0
- dhall-lang/tests/parser/success/unit/RecordTypeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordTypeEmptyA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeEmptyB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeEmptyCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeEmptyCommaB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeLeadingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeLeadingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordTypeTrailingAndLeadingCommasA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeTrailingAndLeadingCommasB.dhallb binary
- dhall-lang/tests/parser/success/unit/RecordTypeTrailingCommaA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/RecordTypeTrailingCommaB.dhallb binary
- dhall-lang/tests/parser/success/unit/SelectionSomeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/SelectionSomeB.dhallb binary
- dhall-lang/tests/parser/success/unit/ShebangA.dhall +2/−0
- dhall-lang/tests/parser/success/unit/ShebangB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/ShebangNixA.dhall +3/−0
- dhall-lang/tests/parser/success/unit/ShebangNixB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/ShowConstructorA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ShowConstructorB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/ShowConstructorWithValueA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ShowConstructorWithValueB.dhallb binary
- dhall-lang/tests/parser/success/unit/TimeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/TimeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/TimeLiteralA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/TimeLiteralB.dhallb binary
- dhall-lang/tests/parser/success/unit/TimeZoneA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/TimeZoneB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/TimeZoneLiteralA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/TimeZoneLiteralB.dhallb binary
- dhall-lang/tests/parser/success/unit/ToMapA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ToMapAnnotA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ToMapAnnotB.dhallb binary
- dhall-lang/tests/parser/success/unit/ToMapB.dhallb binary
- dhall-lang/tests/parser/success/unit/TrailingLineCommentWithoutNewlineA.dhall +2/−0
- dhall-lang/tests/parser/success/unit/TrailingLineCommentWithoutNewlineB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/UnionLit1A.dhall +0/−1
- dhall-lang/tests/parser/success/unit/UnionLit1B.dhallb binary
- dhall-lang/tests/parser/success/unit/UnionLit2A.dhall +0/−1
- dhall-lang/tests/parser/success/unit/UnionLit2B.dhallb binary
- dhall-lang/tests/parser/success/unit/UnionTypeEmptyDelimA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeEmptyDelimB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeLeadingDelimA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeLeadingDelimB.dhallb binary
- dhall-lang/tests/parser/success/unit/UnionTypeSomeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeSomeB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeTrailingAndLeadingDelimsA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeTrailingAndLeadingDelimsB.dhallb binary
- dhall-lang/tests/parser/success/unit/UnionTypeTrailingDelimA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/UnionTypeTrailingDelimB.dhallb binary
- dhall-lang/tests/parser/success/unit/VariableQuotedWithSpaceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/VariableQuotedWithSpaceB.dhallb binary
- dhall-lang/tests/parser/success/unit/WithA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/WithB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/WithMultipleA.dhall +4/−0
- dhall-lang/tests/parser/success/unit/WithMultipleB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/WithPrecedence1A.dhall +13/−0
- dhall-lang/tests/parser/success/unit/WithPrecedence1B.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/WithPrecedence2A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/WithPrecedence2B.dhallb binary
- dhall-lang/tests/parser/success/unit/WithPrecedence3A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/WithPrecedence3B.dhallb binary
- dhall-lang/tests/parser/success/unit/WithSomeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/WithSomeB.dhallb binary
- dhall-lang/tests/parser/success/unit/ifThenElseA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/ifThenElseB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationAbsoluteB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationEnvA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationEnvB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationHashA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationHashB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/AsLocationLocalA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationLocalB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationMissingA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationMissingB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationRemoteA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/AsLocationRemoteB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersDoubleHashPrecedenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersHashPrecedenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/HeadersInteriorHashB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/ImportAsNoSpaceB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/MissingA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/MissingB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/environmentVariablePosixA.dhall +1/−1
- dhall-lang/tests/parser/success/unit/import/environmentVariablePosixB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/inlineUsingA.dhall +2/−2
- dhall-lang/tests/parser/success/unit/import/inlineUsingB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/parenthesizeUsingA.dhall +0/−1
- dhall-lang/tests/parser/success/unit/import/parenthesizeUsingB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/pathTerminationUnionA.dhall +1/−1
- dhall-lang/tests/parser/success/unit/import/pathTerminationUnionB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/quotedPathsA.dhall +1/−3
- dhall-lang/tests/parser/success/unit/import/quotedPathsB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/basicHttpA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/basicHttpB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/basicHttpsA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/basicHttpsB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/emptyPath0A.dhall +3/−0
- dhall-lang/tests/parser/success/unit/import/urls/emptyPath0B.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/emptyPath1A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/emptyPath1B.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/emptyPathSegmentA.dhall +2/−0
- dhall-lang/tests/parser/success/unit/import/urls/emptyPathSegmentB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/emptyQueryA.dhall +3/−0
- dhall-lang/tests/parser/success/unit/import/urls/emptyQueryB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/escapedPathA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/escapedPathB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/escapedQueryA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/escapedQueryB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/fragmentParsesAsListAppendA.dhall +11/−0
- dhall-lang/tests/parser/success/unit/import/urls/fragmentParsesAsListAppendB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv4A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv4B.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv4upperoctetsA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv4upperoctetsB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv6longA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv6longB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv6mediumA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv6mediumB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv6shortA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv6shortB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv6verylongA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv6verylongB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/ipv6withipv4A.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/ipv6withipv4B.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/portA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/portB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/potPourriA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/potPourriB.dhallb binary
- dhall-lang/tests/parser/success/unit/import/urls/userinfoA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/import/urls/userinfoB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolAndA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolAndAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolAndAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolAndB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolEQA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolEQAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolEQAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolEQB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolNEA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolNEAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolNEAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolNEB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolOrA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolOrAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/BoolOrAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/BoolOrB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/EquivalenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/EquivalenceAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/EquivalenceAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/EquivalenceB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/ImportAltA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/ImportAltAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/ImportAltAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/ImportAltB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/ListAppendA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/ListAppendAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/ListAppendAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/ListAppendB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/NaturalPlusA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/NaturalPlusAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/NaturalPlusAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/NaturalPlusB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/NaturalTimesA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/NaturalTimesAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/NaturalTimesAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/NaturalTimesB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/PrecedenceBoolA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/PrecedenceBoolB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/PrecedenceEquivalenceA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/PrecedenceEquivalenceB.dhallb +1/−0
- dhall-lang/tests/parser/success/unit/operators/PrecedenceNatA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/PrecedenceNatB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/PrecedenceRecordA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/PrecedenceRecordB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeUnicodeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeUnicodeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordMergeUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeUnicodeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeUnicodeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RecursiveRecordTypeMergeUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeUnicodeA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeUnicodeAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeUnicodeAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/RightBiasedRecordMergeUnicodeB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/TextAppendA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/TextAppendAssocA.dhall +1/−0
- dhall-lang/tests/parser/success/unit/operators/TextAppendAssocB.dhallb binary
- dhall-lang/tests/parser/success/unit/operators/TextAppendB.dhallb binary
- dhall-lang/tests/parser/success/usingToMapA.dhall +1/−0
- dhall-lang/tests/parser/success/usingToMapB.dhallb binary
- dhall-lang/tests/parser/success/withQuestionMarkA.dhall +1/−0
- dhall-lang/tests/parser/success/withQuestionMarkB.dhallb binary
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/access/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/access/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/access/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/access/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/combineTypes/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/combineTypes/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/combineTypes/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/combineTypes/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/prefer/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/prefer/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/projection/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/haskell-tutorial/projection/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/and/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/and/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/and/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/and/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/build/0A.dhall +2/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/build/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/build/1A.dhall +2/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/build/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/2A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/3A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/even/3B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/fold/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/fold/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/fold/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/fold/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/not/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/not/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/not/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/not/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/2A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/3A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/odd/3B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/or/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/or/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/or/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/or/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/show/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/show/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/show/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Bool/show/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Double/show/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Double/show/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Double/show/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Double/show/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/show/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/show/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/show/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/show/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/toDouble/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/toDouble/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/toDouble/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Integer/toDouble/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/all/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/all/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/all/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/all/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/any/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/any/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/any/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/any/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/build/0A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/build/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/build/1A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/build/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concat/0A.dhall +5/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concat/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concat/1A.dhall +5/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concat/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concatMap/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concatMap/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concatMap/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/concatMap/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/filter/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/filter/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/filter/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/filter/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/0A.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/1A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/2A.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/fold/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/generate/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/generate/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/generate/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/generate/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/head/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/head/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/head/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/head/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/indexed/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/indexed/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/indexed/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/indexed/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/iterate/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/iterate/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/iterate/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/iterate/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/last/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/last/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/last/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/last/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/length/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/length/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/length/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/length/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/map/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/map/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/map/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/map/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/null/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/null/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/null/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/null/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/replicate/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/replicate/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/replicate/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/replicate/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/reverse/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/reverse/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/reverse/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/reverse/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/shifted/0A.dhall +15/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/shifted/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/shifted/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/shifted/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/unzip/0A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/unzip/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/unzip/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/List/unzip/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/build/0A.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/build/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/build/1A.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/build/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/enumerate/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/enumerate/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/enumerate/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/enumerate/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/even/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/even/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/even/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/even/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/2A.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/fold/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/isZero/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/isZero/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/isZero/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/isZero/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/odd/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/odd/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/odd/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/odd/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/product/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/product/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/product/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/product/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/show/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/show/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/show/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/show/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/sum/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/sum/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/sum/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/sum/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toDouble/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toDouble/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toDouble/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toDouble/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toInteger/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toInteger/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toInteger/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Natural/toInteger/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/all/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/all/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/all/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/all/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/any/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/any/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/any/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/any/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/build/0A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/build/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/build/1A.dhall +7/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/build/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/2A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/concat/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/filter/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/filter/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/filter/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/filter/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/fold/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/fold/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/fold/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/fold/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/2A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/head/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/2A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/last/2B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/length/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/length/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/length/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/length/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/map/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/map/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/map/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/map/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/null/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/null/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/null/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/null/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/toList/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/toList/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/toList/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/toList/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/unzip/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/unzip/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/unzip/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Optional/unzip/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concat/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concat/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concat/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concat/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMap/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMap/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMap/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMap/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMapSep/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMapSep/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMapSep/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatMapSep/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatSep/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatSep/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatSep/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/concatSep/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/show/0A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/show/0B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/show/1A.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/prelude/Text/show/1B.hash +1/−0
- dhall-lang/tests/semantic-hash/success/remoteSystemsA.dhall +51/−0
- dhall-lang/tests/semantic-hash/success/remoteSystemsB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/doubleShowA.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/simple/doubleShowB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/enumA.dhall +8/−0
- dhall-lang/tests/semantic-hash/success/simple/enumB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/integerShowA.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/simple/integerShowB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/integerToDoubleA.dhall +10/−0
- dhall-lang/tests/semantic-hash/success/simple/integerToDoubleB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/letletA.dhall +3/−0
- dhall-lang/tests/semantic-hash/success/simple/letletB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/listBuildA.dhall +22/−0
- dhall-lang/tests/semantic-hash/success/simple/listBuildB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/multiLineA.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/simple/multiLineB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalBuildA.dhall +18/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalBuildB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalPlusA.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalPlusB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalShowA.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalShowB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalToIntegerA.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/simple/naturalToIntegerB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simple/sortOperatorA.dhall +1/−0
- dhall-lang/tests/semantic-hash/success/simple/sortOperatorB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simplifications/andA.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/simplifications/andB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simplifications/eqA.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/simplifications/eqB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simplifications/ifThenElseA.dhall +3/−0
- dhall-lang/tests/semantic-hash/success/simplifications/ifThenElseB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simplifications/neA.dhall +4/−0
- dhall-lang/tests/semantic-hash/success/simplifications/neB.hash +1/−0
- dhall-lang/tests/semantic-hash/success/simplifications/orA.dhall +6/−0
- dhall-lang/tests/semantic-hash/success/simplifications/orB.hash +1/−0
- dhall-lang/tests/type-inference/failure/DateApplyTime.dhall +3/−0
- dhall-lang/tests/type-inference/failure/SortInLet.dhall +1/−0
- dhall-lang/tests/type-inference/failure/hurkensParadox.dhall +49/−0
- dhall-lang/tests/type-inference/failure/recordOfKind.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AnnotationRecordWrongFieldName.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AnnotationRecordWrongFieldType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AssertAlphaTrap.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AssertAlphaTrap2.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AssertDoubleZeros.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AssertNotEquivalence.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/AssertTriviallyFalse.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/CompletionMissingRequiredField.dhall +6/−0
- dhall-lang/tests/type-inference/failure/unit/CompletionWithWrongDefaultType.dhall +6/−0
- dhall-lang/tests/type-inference/failure/unit/CompletionWithWrongFieldName.dhall +6/−0
- dhall-lang/tests/type-inference/failure/unit/CompletionWithWrongOverridenType.dhall +6/−0
- dhall-lang/tests/type-inference/failure/unit/EmptyToMap.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/EquivalenceNotSameType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/EquivalenceNotTerms.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionApplicationArgumentNotMatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionApplicationIsNotFunction.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionArgumentTypeNotAType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionTypeArgumentTypeNotAType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionTypeKindSort.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionTypeOutputTypeNotAType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/FunctionTypeTypeSort.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/HeterogenousToMap.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/IfBranchesNotMatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/IfBranchesNotTermTypeOrKind.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/IfNotBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/LetInSort.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/LetWithNonterminatingAnnotation.dhall +14/−0
- dhall-lang/tests/type-inference/failure/unit/LetWithWrongAnnotation.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ListLiteralEmptyNotType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ListLiteralNotType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ListLiteralTypesNotMatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeAlternativeHasNoHandler.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeAnnotationMismatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeAnnotationNotType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeEmptyNeedsDirectAnnotation1.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeEmptyNeedsDirectAnnotation2.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeEmptyWithoutAnnotation.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeHandlerFreeVar.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeHandlerNotFunction.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeHandlerNotInUnion.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeHandlerNotMatchAlternativeType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeHandlersWithDifferentType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeLhsNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeMissingHandler1.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeMissingHandler2.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeRhsNotUnion.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MergeUnusedHandler.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MistypedToMap1.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MistypedToMap2.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MistypedToMap3.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/MistypedToMap4.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/NaturalSubtractNotNatural.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/NestedAnnotInnerWrong.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/NestedAnnotOuterWrong.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/NonRecordToMap.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorAndNotBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorEqualNotBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorListConcatenateLhsNotList.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorListConcatenateListsNotMatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorListConcatenateNotListsButMatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorListConcatenateRhsNotList.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorNotEqualNotBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorOrNotBool.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorPlusNotNatural.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorTextConcatenateLhsNotText.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorTextConcatenateRhsNotText.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OperatorTimesNotNatural.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OptionalDeprecatedSyntaxAbsent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/OptionalDeprecatedSyntaxPresent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordLitDuplicateFieldsAbstract.dhall +13/−0
- dhall-lang/tests/type-inference/failure/unit/RecordLitDuplicateFieldsCollidingRecords.dhall +8/−0
- dhall-lang/tests/type-inference/failure/unit/RecordLitDuplicateFieldsNotRecords.dhall +7/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionByTypeFieldTypeMismatch.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionByTypeNotPresent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionDuplicateFields.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionEmpty.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionNotPresent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordProjectionNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordSelectionEmpty.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordSelectionNotPresent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordSelectionNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordSelectionTypeNotUnionType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordTypeDuplicateFields.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecordTypeValueMember.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordMergeLhsNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordMergeOverlapping.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordMergeRhsNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordTypeMergeLhsNotRecordType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordTypeMergeOverlapping.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RecursiveRecordTypeMergeRhsNotRecordType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RemovedBuiltinOptionalBuild.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RemovedBuiltinOptionalFold.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RightBiasedRecordMergeLhsNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/RightBiasedRecordMergeRhsNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ShowConstructorNotFullyApplied.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ShowConstructorNotFullyAppliedOptional.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ShowConstructorWrongArgument.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/SomeNotType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/Sort.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/TextLiteralInterpolateNotText.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/ToMapEmptyInvalidAnnotation.dhall +2/−0
- dhall-lang/tests/type-inference/failure/unit/ToMapWrongKind.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/TypeAnnotationWrong.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/UnionConstructorFieldNotPresent.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/UnionDeprecatedConstructorsKeyword.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/UnionTypeDuplicateVariants1.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/UnionTypeDuplicateVariants2.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/UnionTypeNotType.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/VariableFree.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/WithInfersKind.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/WithInvalidOverrideA.dhall +6/−0
- dhall-lang/tests/type-inference/failure/unit/WithNotOptional.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/WithNotRecord.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/WithOptionalRecordTypeChanged.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/WithOptionalTypeChanged.dhall +1/−0
- dhall-lang/tests/type-inference/failure/unit/Z.dhall +4/−0
- dhall-lang/tests/type-inference/success/CacheImportsA.dhall +11/−0
- dhall-lang/tests/type-inference/success/CacheImportsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/CacheImportsCanonicalizeA.dhall +10/−0
- dhall-lang/tests/type-inference/success/CacheImportsCanonicalizeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/accessEncodedTypeA.dhall +4/−0
- dhall-lang/tests/type-inference/success/accessEncodedTypeB.dhall +4/−0
- dhall-lang/tests/type-inference/success/accessTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/accessTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/preferMixedRecordsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/preferMixedRecordsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/preferMixedRecordsSameFieldA.dhall +1/−0
- dhall-lang/tests/type-inference/success/preferMixedRecordsSameFieldB.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/and/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/and/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/and/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/and/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/build/0A.dhall +2/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/build/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/build/1A.dhall +2/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/build/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/3A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/even/3B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/fold/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/fold/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/fold/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/fold/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/not/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/not/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/not/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/not/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/3A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/odd/3B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/or/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/or/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/or/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/or/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/show/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/show/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/show/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Bool/show/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Double/show/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Double/show/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Double/show/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Double/show/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/show/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/show/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/show/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/show/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/toDouble/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/toDouble/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/toDouble/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Integer/toDouble/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/all/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/all/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/all/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/all/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/any/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/any/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/any/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/any/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/build/0A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/List/build/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/build/1A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/List/build/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concat/0A.dhall +5/−0
- dhall-lang/tests/type-inference/success/prelude/List/concat/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concat/1A.dhall +5/−0
- dhall-lang/tests/type-inference/success/prelude/List/concat/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concatMap/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concatMap/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concatMap/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/concatMap/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/filter/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/filter/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/filter/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/filter/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/0A.dhall +6/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/1A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/2A.dhall +4/−0
- dhall-lang/tests/type-inference/success/prelude/List/fold/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/generate/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/generate/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/generate/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/generate/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/head/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/head/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/head/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/head/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/indexed/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/indexed/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/indexed/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/indexed/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/iterate/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/iterate/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/iterate/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/iterate/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/last/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/last/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/last/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/last/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/length/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/length/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/length/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/length/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/map/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/map/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/map/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/map/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/null/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/null/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/null/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/null/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/replicate/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/replicate/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/replicate/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/replicate/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/reverse/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/reverse/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/reverse/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/reverse/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/shifted/0A.dhall +15/−0
- dhall-lang/tests/type-inference/success/prelude/List/shifted/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/shifted/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/shifted/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/unzip/0A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/List/unzip/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/unzip/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/List/unzip/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/00A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/00B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/01A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/01B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/02A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/02B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/03A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/03B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/04A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/04B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/05A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/05B.dhall +3/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/06A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/06B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/07A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/07B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/08A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/08B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/09A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/09B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/10A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Monoid/10B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/build/0A.dhall +6/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/build/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/build/1A.dhall +6/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/build/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/enumerate/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/enumerate/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/enumerate/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/enumerate/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/even/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/even/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/even/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/even/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/2A.dhall +4/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/fold/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/isZero/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/isZero/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/isZero/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/isZero/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/odd/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/odd/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/odd/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/odd/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/product/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/product/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/product/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/product/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/show/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/show/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/show/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/show/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/sum/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/sum/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/sum/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/sum/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toDouble/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toDouble/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toDouble/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toDouble/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toInteger/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toInteger/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toInteger/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Natural/toInteger/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/all/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/all/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/all/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/all/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/any/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/any/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/any/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/any/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/build/0A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/build/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/build/1A.dhall +7/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/build/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/concat/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/filter/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/filter/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/filter/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/filter/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/fold/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/fold/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/fold/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/fold/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/head/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/last/2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/length/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/length/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/length/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/length/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/map/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/map/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/map/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/map/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/null/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/null/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/null/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/null/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/toList/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/toList/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/toList/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/toList/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/unzip/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/unzip/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/unzip/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Optional/unzip/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concat/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concat/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concat/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concat/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMap/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMap/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMap/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMap/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMapSep/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMapSep/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMapSep/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatMapSep/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatSep/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatSep/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatSep/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/prelude/Text/concatSep/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/preludeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/preludeB.dhall +740/−0
- dhall-lang/tests/type-inference/success/recordOfRecordOfTypesA.dhall +5/−0
- dhall-lang/tests/type-inference/success/recordOfRecordOfTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/recordOfTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/recordOfTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/LambdaInLetScoping1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/LambdaInLetScoping1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/LambdaInLetScoping2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/LambdaInLetScoping2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/RecursiveRecordTypeMergeTripleCollisionA.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/RecursiveRecordTypeMergeTripleCollisionB.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/TodoA.dhall +1/−0
- dhall-lang/tests/type-inference/success/regression/TodoB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/access/0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/access/0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/access/1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/access/1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/anonymousFunctionsInTypesA.dhall +5/−0
- dhall-lang/tests/type-inference/success/simple/anonymousFunctionsInTypesB.dhall +3/−0
- dhall-lang/tests/type-inference/success/simple/combineMixedRecordsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/combineMixedRecordsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/completionA.dhall +25/−0
- dhall-lang/tests/type-inference/success/simple/completionB.dhall +8/−0
- dhall-lang/tests/type-inference/success/simple/complexShadowingA.dhall +6/−0
- dhall-lang/tests/type-inference/success/simple/complexShadowingB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/fieldsAreTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/fieldsAreTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/kindParameterA.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/kindParameterB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/mergeEquivalenceA.dhall +6/−0
- dhall-lang/tests/type-inference/success/simple/mergeEquivalenceB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/mixedFieldAccessA.dhall +9/−0
- dhall-lang/tests/type-inference/success/simple/mixedFieldAccessB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/orderInsensitivityA.dhall +15/−0
- dhall-lang/tests/type-inference/success/simple/orderInsensitivityB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/toMapEmptyNormalizeAnnotationA.dhall +3/−0
- dhall-lang/tests/type-inference/success/simple/toMapEmptyNormalizeAnnotationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/unionsOfTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/simple/unionsOfTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertAlphaA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertAlphaB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertNaNA.dhall +6/−0
- dhall-lang/tests/type-inference/success/unit/AssertNaNB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertSimpleA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertSimpleB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertTrivialA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/AssertTrivialB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/BoolA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/BoolB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/BytesLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/BytesLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/CompletionA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/CompletionB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ConstructorShiftA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ConstructorShiftB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleShowA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/DoubleShowB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/EquivalenceA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/EquivalenceB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FalseA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FalseB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationNormalizeArgumentA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationNormalizeArgumentB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationNormalizeResultA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionApplicationNormalizeResultB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionDependentType1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionDependentType1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionDependentType2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionDependentType2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionNamedArgA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionNamedArgB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionNormalizeTypeAnnotationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionNormalizeTypeAnnotationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindTermA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindTermB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeKindTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTermTermA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTermTermB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeTermA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeTermB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeTypeTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeUsingArgumentA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/FunctionTypeUsingArgumentB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfBranchesKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfBranchesKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfBranchesTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfBranchesTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IfNormalizeArgumentsA.dhall +9/−0
- dhall-lang/tests/type-inference/success/unit/IfNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerClampA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerClampB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerNegateA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerNegateB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerShowA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerShowB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerToDoubleA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/IntegerToDoubleB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/KindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/KindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetNestedTypeSynonymA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetNestedTypeSynonymB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetTypeSynonymA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetTypeSynonymB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetWithAnnotationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/LetWithAnnotationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListBuildA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListBuildB.dhall +3/−0
- dhall-lang/tests/type-inference/success/unit/ListFoldA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListFoldB.dhall +6/−0
- dhall-lang/tests/type-inference/success/unit/ListHeadA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListHeadB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListIndexedA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListIndexedB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLastA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLastB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLengthA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLengthB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralEmptyNormalizeAnnotationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralEmptyNormalizeAnnotationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralOneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListLiteralOneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListReverseA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ListReverseB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeEmptyAlternativeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeEmptyUnionA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeEmptyUnionB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeNoneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeNoneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneWithAnnotation0A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneWithAnnotation0B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneWithAnnotation1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOneWithAnnotation1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOptionalA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeOptionalB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeSomeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeSomeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/MergeTrickyShadowingB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalBuildA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalBuildB.dhall +6/−0
- dhall-lang/tests/type-inference/success/unit/NaturalEvenA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalEvenB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalFoldA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalFoldB.dhall +5/−0
- dhall-lang/tests/type-inference/success/unit/NaturalIsZeroA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalIsZeroB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalOddA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalOddB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalShowA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalShowB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalSubtractA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalSubtractB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalToIntegerA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NaturalToIntegerB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NoneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/NoneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorAndA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorAndB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorAndNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorAndNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorEqualA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorEqualB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorEqualNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorEqualNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorListConcatenateA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorListConcatenateB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorListConcatenateNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorListConcatenateNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorNotEqualA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorNotEqualB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorNotEqualNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorNotEqualNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorOrA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorOrB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorOrNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorOrNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorPlusA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorPlusB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorPlusNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorPlusNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTextConcatenateA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTextConcatenateB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTextConcatenateNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTextConcatenateNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTimesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTimesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTimesNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OperatorTimesNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OptionalA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/OptionalB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsMergeA.dhall +14/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsMergeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsAbstractA.dhall +12/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsAbstractB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsNoCollisionsA.dhall +12/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsNoCollisionsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitNormalizeFieldTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitNormalizeFieldTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunCaptureA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunCaptureB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunSomeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitPunSomeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitSortFieldsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordLitSortFieldsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordMixedKinds2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordMixedKinds2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordMixedKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordMixedKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedKindLikeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedKindLikeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedTypeLikeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordNestedTypeLikeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneValueA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordOneValueB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeJudgmentalEqualityA.dhall +5/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionByTypeJudgmentalEqualityB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionEmptyKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionEmptyKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionValueA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordProjectionValueB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionValueA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordSelectionValueB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeKindLikeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeKindLikeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKinds2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKinds2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKinds3A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKinds3B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeMixedKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeNestedKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeNestedKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeNestedKindLikeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeNestedKindLikeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecordTypeTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeBoolTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeLhsEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeLhsEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeMixedKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeMixedKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRecursivelyTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRhsEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeRhsEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordMergeTwoTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeDeepA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeDeepB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRecursivelyTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRhsEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeRhsEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RecursiveRecordTypeMergeTwoTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeMixedKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeMixedKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeRhsEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeRhsEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoDifferentA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoDifferentB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoKindsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoKindsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoTypesA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/RightBiasedRecordMergeTwoTypesB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorNonEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorNonEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorOptionalA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ShowConstructorOptionalB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/SomeTrueA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/SomeTrueB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralNormalizeArgumentsA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralNormalizeArgumentsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralWithInterpolationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextLiteralWithInterpolationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextReplaceA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextReplaceB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextShowA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TextShowB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapAnnotatedB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapInferTypeFromRecordA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/ToMapInferTypeFromRecordB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TrueA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TrueB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationFunctionA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationFunctionB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationNormalizeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationNormalizeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationSortA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeAnnotationSortB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/TypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionConstructorEmptyFieldA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionConstructorEmptyFieldB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionConstructorFieldA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionConstructorFieldB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeEmptyA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeEmptyB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds1A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds1B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds2A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds2B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds3A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds3B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds4A.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeMixedKinds4B.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeOneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeOneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeTypeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/UnionTypeTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithCreateIntermediateRecordsA.dhall +3/−0
- dhall-lang/tests/type-inference/success/unit/WithCreateIntermediateRecordsB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithInfersKindA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithInfersKindB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithNestedA.dhall +4/−0
- dhall-lang/tests/type-inference/success/unit/WithNestedB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithNewFieldA.dhall +4/−0
- dhall-lang/tests/type-inference/success/unit/WithNewFieldB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithNewTypeA.dhall +4/−0
- dhall-lang/tests/type-inference/success/unit/WithNewTypeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithOptionalTypeUnchangedA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/WithOptionalTypeUnchangedB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateTimeLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateTimeLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateTimeTimeZoneLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/DateTimeTimeZoneLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeTimeZoneLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeTimeZoneLiteralB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeZoneA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeZoneB.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeZoneLiteralA.dhall +1/−0
- dhall-lang/tests/type-inference/success/unit/time/TimeZoneLiteralB.dhall +1/−0
- dhall-lang/tests/typecheck/data/importBoundary.dhall +0/−3
- dhall-lang/tests/typecheck/failure/combineMixedRecords.dhall +0/−1
- dhall-lang/tests/typecheck/failure/customHeadersUsingBoundVariable.dhall +0/−15
- dhall-lang/tests/typecheck/failure/duplicateFields.dhall +0/−1
- dhall-lang/tests/typecheck/failure/hurkensParadox.dhall +0/−49
- dhall-lang/tests/typecheck/failure/importBoundary.dhall +0/−1
- dhall-lang/tests/typecheck/failure/mixedUnions.dhall +0/−1
- dhall-lang/tests/typecheck/failure/preferMixedRecords.dhall +0/−1
- dhall-lang/tests/typecheck/success/accessEncodedTypeA.dhall +0/−4
- dhall-lang/tests/typecheck/success/accessEncodedTypeB.dhall +0/−4
- dhall-lang/tests/typecheck/success/accessTypeA.dhall +0/−1
- dhall-lang/tests/typecheck/success/accessTypeB.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/and/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/and/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/and/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/and/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/build/0A.dhall +0/−2
- dhall-lang/tests/typecheck/success/prelude/Bool/build/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/build/1A.dhall +0/−2
- dhall-lang/tests/typecheck/success/prelude/Bool/build/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/2A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/3A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/even/3B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/fold/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/fold/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/fold/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/fold/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/not/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/not/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/not/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/not/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/2A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/3A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/odd/3B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/or/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/or/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/or/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/or/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/show/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/show/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/show/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Bool/show/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Double/show/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Double/show/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Double/show/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Double/show/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/show/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/show/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/show/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/show/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/all/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/all/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/all/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/all/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/any/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/any/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/any/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/any/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/build/0A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/List/build/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/build/1A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/List/build/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concat/0A.dhall +0/−5
- dhall-lang/tests/typecheck/success/prelude/List/concat/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concat/1A.dhall +0/−5
- dhall-lang/tests/typecheck/success/prelude/List/concat/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concatMap/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concatMap/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concatMap/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/concatMap/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/filter/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/filter/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/filter/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/filter/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/fold/0A.dhall +0/−6
- dhall-lang/tests/typecheck/success/prelude/List/fold/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/fold/1A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/List/fold/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/fold/2A.dhall +0/−4
- dhall-lang/tests/typecheck/success/prelude/List/fold/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/generate/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/generate/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/generate/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/generate/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/head/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/head/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/head/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/head/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/indexed/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/indexed/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/indexed/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/indexed/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/iterate/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/iterate/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/iterate/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/iterate/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/last/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/last/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/last/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/last/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/length/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/length/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/length/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/length/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/map/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/map/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/map/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/map/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/null/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/null/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/null/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/null/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/replicate/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/replicate/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/replicate/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/replicate/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/reverse/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/reverse/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/reverse/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/reverse/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/shifted/0A.dhall +0/−15
- dhall-lang/tests/typecheck/success/prelude/List/shifted/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/shifted/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/shifted/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/unzip/0A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/List/unzip/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/unzip/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/List/unzip/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/00A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/00B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/01A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/01B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/02A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/02B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/03A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/03B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/04A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/04B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/05A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/05B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/06A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/06B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/07A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/07B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/08A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/08B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/09A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/09B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/10A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Monoid/10B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/build/0A.dhall +0/−6
- dhall-lang/tests/typecheck/success/prelude/Natural/build/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/build/1A.dhall +0/−6
- dhall-lang/tests/typecheck/success/prelude/Natural/build/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/even/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/even/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/even/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/even/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/2A.dhall +0/−4
- dhall-lang/tests/typecheck/success/prelude/Natural/fold/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/odd/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/odd/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/odd/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/odd/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/product/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/product/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/product/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/product/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/show/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/show/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/show/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/show/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/sum/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/sum/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/sum/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/sum/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/all/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/all/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/all/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/all/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/any/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/any/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/any/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/any/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/build/0A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/Optional/build/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/build/1A.dhall +0/−7
- dhall-lang/tests/typecheck/success/prelude/Optional/build/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/2A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/concat/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/filter/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/filter/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/filter/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/filter/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/fold/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/fold/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/fold/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/fold/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/2A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/head/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/2A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/last/2B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/length/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/length/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/length/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/length/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/map/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/map/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/map/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/map/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/null/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/null/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/null/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/null/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/toList/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/toList/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/toList/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/toList/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concat/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concat/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concat/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concat/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/recordOfRecordOfTypesA.dhall +0/−5
- dhall-lang/tests/typecheck/success/recordOfRecordOfTypesB.dhall +0/−1
- dhall-lang/tests/typecheck/success/recordOfTypesA.dhall +0/−1
- dhall-lang/tests/typecheck/success/recordOfTypesB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/access/0A.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/access/0B.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/access/1A.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/access/1B.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/anonymousFunctionsInTypesA.dhall +0/−5
- dhall-lang/tests/typecheck/success/simple/anonymousFunctionsInTypesB.dhall +0/−4
- dhall-lang/tests/typecheck/success/simple/complexShadowingA.dhall +0/−6
- dhall-lang/tests/typecheck/success/simple/complexShadowingB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/fieldsAreTypesA.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/fieldsAreTypesB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/kindParameterA.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/kindParameterB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/mergeEquivalenceA.dhall +0/−6
- dhall-lang/tests/typecheck/success/simple/mergeEquivalenceB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/mixedFieldAccessA.dhall +0/−9
- dhall-lang/tests/typecheck/success/simple/mixedFieldAccessB.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/unionsOfTypesA.dhall +0/−1
- dhall-lang/tests/typecheck/success/simple/unionsOfTypesB.dhall +0/−1
- dhall.cabal +295/−420
- doctest/Main.hs +39/−13
- ghc-src/Dhall/Crypto.hs +47/−0
- ghc-src/Dhall/Import/HTTP.hs +320/−0
- ghc-src/Dhall/Import/Manager.hs +33/−0
- ghcjs-src/Dhall/Crypto.hs +75/−0
- ghcjs-src/Dhall/Import/HTTP.hs +52/−0
- ghcjs-src/Dhall/Import/Manager.hs +26/−0
- man/dhall.1 +100/−0
- src/Dhall.hs +579/−1811
- src/Dhall/Binary.hs +1437/−958
- src/Dhall/Binary.hs-boot +0/−10
- src/Dhall/Context.hs +4/−4
- src/Dhall/Core.hs +156/−2147
- src/Dhall/Core.hs-boot +0/−11
- src/Dhall/Deriving.hs +547/−0
- src/Dhall/Diff.hs +439/−260
- src/Dhall/DirectoryTree.hs +515/−0
- src/Dhall/DirectoryTree/Types.hs +267/−0
- src/Dhall/Eval.hs +1567/−946
- src/Dhall/Eval.hs-boot +0/−8
- src/Dhall/Format.hs +90/−78
- src/Dhall/Freeze.hs +352/−128
- src/Dhall/Hash.hs +0/−44
- src/Dhall/Import.hs +1401/−988
- src/Dhall/Import/HTTP.hs +0/−290
- src/Dhall/Import/Headers.hs +129/−0
- src/Dhall/Import/Types.hs +153/−115
- src/Dhall/Lint.hs +190/−41
- src/Dhall/Main.hs +722/−201
- src/Dhall/Map.hs +345/−110
- src/Dhall/Marshal/Decode.hs +1712/−0
- src/Dhall/Marshal/Encode.hs +1068/−0
- src/Dhall/Marshal/Internal.hs +193/−0
- src/Dhall/Normalize.hs +1037/−0
- src/Dhall/Optics.hs +51/−19
- src/Dhall/Package.hs +297/−0
- src/Dhall/Parser.hs +65/−33
- src/Dhall/Parser/Combinators.hs +83/−65
- src/Dhall/Parser/Expression.hs +1277/−838
- src/Dhall/Parser/Token.hs +1438/−790
- src/Dhall/Pretty.hs +10/−8
- src/Dhall/Pretty/Internal.hs +1991/−989
- src/Dhall/Pretty/Internal.hs-boot +22/−5
- src/Dhall/Repl.hs +283/−172
- src/Dhall/Schemas.hs +210/−0
- src/Dhall/Set.hs +97/−14
- src/Dhall/Src.hs +33/−10
- src/Dhall/Substitution.hs +34/−0
- src/Dhall/Syntax.hs +31/−0
- src/Dhall/Syntax/Binding.hs +57/−0
- src/Dhall/Syntax/Chunks.hs +141/−0
- src/Dhall/Syntax/Chunks.hs-boot +8/−0
- src/Dhall/Syntax/Const.hs +29/−0
- src/Dhall/Syntax/Expr.hs +267/−0
- src/Dhall/Syntax/Expr.hs-boot +8/−0
- src/Dhall/Syntax/FunctionBinding.hs +53/−0
- src/Dhall/Syntax/Import.hs +139/−0
- src/Dhall/Syntax/Instances/Applicative.hs +36/−0
- src/Dhall/Syntax/Instances/Bifunctor.hs +44/−0
- src/Dhall/Syntax/Instances/Data.hs +28/−0
- src/Dhall/Syntax/Instances/Eq.hs +67/−0
- src/Dhall/Syntax/Instances/Foldable.hs +20/−0
- src/Dhall/Syntax/Instances/Functor.hs +37/−0
- src/Dhall/Syntax/Instances/Lift.hs +42/−0
- src/Dhall/Syntax/Instances/Monad.hs +36/−0
- src/Dhall/Syntax/Instances/NFData.hs +35/−0
- src/Dhall/Syntax/Instances/Ord.hs +45/−0
- src/Dhall/Syntax/Instances/Pretty.hs +135/−0
- src/Dhall/Syntax/Instances/Pretty.hs-boot +8/−0
- src/Dhall/Syntax/Instances/Show.hs +36/−0
- src/Dhall/Syntax/Instances/Traversable.hs +22/−0
- src/Dhall/Syntax/MultiLet.hs +62/−0
- src/Dhall/Syntax/Operations.hs +394/−0
- src/Dhall/Syntax/Operations.hs-boot +5/−0
- src/Dhall/Syntax/RecordField.hs +93/−0
- src/Dhall/Syntax/Types.hs +55/−0
- src/Dhall/Syntax/Types.hs-boot +14/−0
- src/Dhall/Syntax/Var.hs +47/−0
- src/Dhall/TH.hs +612/−26
- src/Dhall/Tags.hs +269/−0
- src/Dhall/Tutorial.hs +2318/−2868
- src/Dhall/TypeCheck.hs +4851/−3926
- src/Dhall/URL.hs +37/−0
- src/Dhall/Util.hs +218/−10
- src/Dhall/Version.hs +17/−0
- tests/Dhall/Test/Dhall.hs +371/−74
- tests/Dhall/Test/Diff.hs +55/−0
- tests/Dhall/Test/DirectoryTree.hs +149/−0
- tests/Dhall/Test/Format.hs +33/−31
- tests/Dhall/Test/Freeze.hs +59/−0
- tests/Dhall/Test/Import.hs +191/−24
- tests/Dhall/Test/Lint.hs +31/−26
- tests/Dhall/Test/Main.hs +40/−3
- tests/Dhall/Test/Normalization.hs +40/−38
- tests/Dhall/Test/Package.hs +270/−0
- tests/Dhall/Test/Parser.hs +143/−69
- tests/Dhall/Test/QuickCheck.hs +592/−170
- tests/Dhall/Test/Regression.hs +135/−36
- tests/Dhall/Test/Schemas.hs +61/−0
- tests/Dhall/Test/SemanticHash.hs +45/−0
- tests/Dhall/Test/Substitution.hs +38/−0
- tests/Dhall/Test/TH.hs +219/−0
- tests/Dhall/Test/Tags.hs +63/−0
- tests/Dhall/Test/Tutorial.hs +19/−9
- tests/Dhall/Test/TypeCheck.hs +0/−88
- tests/Dhall/Test/TypeInference.hs +127/−0
- tests/Dhall/Test/Util.hs +245/−26
- tests/diff/appList.txt +4/−0
- tests/diff/appListA.dhall +1/−0
- tests/diff/appListB.dhall +1/−0
- tests/diff/emptyList.txt +2/−0
- tests/diff/emptyListA.dhall +1/−0
- tests/diff/emptyListB.dhall +1/−0
- tests/diff/function.txt +6/−0
- tests/diff/functionA.dhall +1/−0
- tests/diff/functionB.dhall +1/−0
- tests/diff/insideList.txt +7/−0
- tests/diff/insideListA.dhall +3/−0
- tests/diff/insideListB.dhall +3/−0
- tests/diff/nonEmptyList.txt +2/−0
- tests/diff/nonEmptyListA.dhall +1/−0
- tests/diff/nonEmptyListB.dhall +1/−0
- tests/diff/with.txt +5/−0
- tests/diff/withA.dhall +1/−0
- tests/diff/withB.dhall +1/−0
- tests/format/applicationMultilineA.dhall +33/−0
- tests/format/applicationMultilineB.dhall +34/−0
- tests/format/asciiB.dhall +0/−0
- tests/format/concatSepA.dhall +30/−0
- tests/format/concatSepB.dhall +33/−0
- tests/format/dottedFieldsA.dhall +1/−0
- tests/format/dottedFieldsB.dhall +1/−0
- tests/format/dottedFieldsCommentsA.dhall +17/−0
- tests/format/dottedFieldsCommentsB.dhall +17/−0
- tests/format/doubleRoundB.dhall +22/−22
- tests/format/duplicatesA.dhall +4/−0
- tests/format/duplicatesB.dhall +6/−0
- tests/format/emptyRecordB.dhall +0/−0
- tests/format/envVarsA.dhall +1/−0
- tests/format/envVarsB.dhall +1/−0
- tests/format/escapeNumericLabelB.dhall +0/−0
- tests/format/escapeSingleQuotedOpenInterpolationB.dhall +0/−0
- tests/format/fieldOrderB.dhall +0/−0
- tests/format/functionLikeA.dhall +6/−0
- tests/format/functionLikeB.dhall +6/−0
- tests/format/headerA.dhall +4/−0
- tests/format/headerB.dhall +2/−0
- tests/format/headerNoNewlineA.dhall +1/−0
- tests/format/headerNoNewlineB.dhall +2/−0
- tests/format/ifThenElseB.dhall +1/−7
- tests/format/importAccessB.dhall +0/−0
- tests/format/importAltPrecedenceA.dhall +1/−0
- tests/format/importAltPrecedenceB.dhall +1/−0
- tests/format/importLines2A.dhall +0/−0
- tests/format/importLines2B.dhall +0/−0
- tests/format/importLinesB.dhall +0/−0
- tests/format/importSuffixB.dhall +0/−0
- tests/format/innerMultilineA.dhall +11/−0
- tests/format/innerMultilineB.dhall +11/−0
- tests/format/interpolation0A.dhall +1/−0
- tests/format/interpolation0B.dhall +3/−0
- tests/format/ipfsA.dhall +163/−0
- tests/format/ipfsB.dhall +144/−0
- tests/format/issue1301A.dhall +5/−0
- tests/format/issue1301B.dhall +5/−0
- tests/format/issue1400-1A.dhall +14/−0
- tests/format/issue1400-1B.dhall +13/−0
- tests/format/issue1400-2A.dhall +14/−0
- tests/format/issue1400-2B.dhall +12/−0
- tests/format/issue1413A.dhall +6/−0
- tests/format/issue1413B.dhall +6/−0
- tests/format/issue1545-1A.dhall +1/−0
- tests/format/issue1545-1B.dhall +3/−0
- tests/format/issue1545-2A.dhall +1/−0
- tests/format/issue1545-2B.dhall +3/−0
- tests/format/issue1687A.dhall +7/−0
- tests/format/issue1687B.dhall +7/−0
- tests/format/issue1805KeywordRecordFieldShouldBeQuotedA.dhall +1/−0
- tests/format/issue1805KeywordRecordFieldShouldBeQuotedB.dhall +1/−0
- tests/format/issue1805SomeQuotedInLetButNotInRecordA.dhall +1/−0
- tests/format/issue1805SomeQuotedInLetButNotInRecordB.dhall +1/−0
- tests/format/issue183A.dhall +11/−0
- tests/format/issue183B.dhall +11/−0
- tests/format/issue2047A.dhall +4/−0
- tests/format/issue2047B.dhall +1/−0
- tests/format/issue2078A.dhall +1/−0
- tests/format/issue2078B.dhall +3/−0
- tests/format/issue2601A.dhall +11/−0
- tests/format/issue2601B.dhall +11/−0
- tests/format/largeExponentB.dhall +1/−1
- tests/format/largeRecordA.dhall +142/−0
- tests/format/largeRecordB.dhall +141/−0
- tests/format/letA.dhall +1/−0
- tests/format/letAnnotatedShortA.dhall +1/−0
- tests/format/letAnnotatedShortB.dhall +5/−0
- tests/format/letB.dhall +5/−0
- tests/format/letCommentsA.dhall +7/−0
- tests/format/letCommentsB.dhall +8/−0
- tests/format/letLineCommentsAfterVariableA.dhall +10/−0
- tests/format/letLineCommentsAfterVariableB.dhall +12/−0
- tests/format/letLongCommentsA.dhall +3/−0
- tests/format/letLongCommentsB.dhall +5/−0
- tests/format/letNewlineCommentsA.dhall +7/−0
- tests/format/letNewlineCommentsB.dhall +9/−0
- tests/format/letShortCommentsA.dhall +3/−0
- tests/format/letShortCommentsB.dhall +7/−0
- tests/format/multilineArgumentA.dhall +1/−0
- tests/format/multilineArgumentB.dhall +3/−0
- tests/format/multilineB.dhall +0/−0
- tests/format/multilineTrailingSingleQuoteA.dhall +1/−0
- tests/format/multilineTrailingSingleQuoteB.dhall +3/−0
- tests/format/multilineTrailingWhitespaceA.dhall +1/−0
- tests/format/multilineTrailingWhitespaceB.dhall +7/−0
- tests/format/negativeTimeZoneA.dhall +1/−0
- tests/format/negativeTimeZoneB.dhall +1/−0
- tests/format/nestedAnnotationA.dhall +1/−0
- tests/format/nestedAnnotationB.dhall +1/−0
- tests/format/numericLiteralsA.dhall +1/−0
- tests/format/numericLiteralsB.dhall +1/−0
- tests/format/parentB.dhall +0/−0
- tests/format/parenthesizeUsingA.dhall +6/−0
- tests/format/parenthesizeUsingB.dhall +6/−0
- tests/format/preserveShebangA.dhall +2/−0
- tests/format/preserveShebangB.dhall +2/−0
- tests/format/projectionOrderB.dhall +0/−0
- tests/format/punA.dhall +1/−0
- tests/format/punB.dhall +1/−0
- tests/format/punCommentsA.dhall +7/−0
- tests/format/punCommentsB.dhall +7/−0
- tests/format/recordCompletionA.dhall +26/−0
- tests/format/recordCompletionB.dhall +25/−0
- tests/format/recordLitComments0A.dhall +6/−0
- tests/format/recordLitComments0B.dhall +6/−0
- tests/format/recordLitComments1A.dhall +4/−0
- tests/format/recordLitComments1B.dhall +3/−0
- tests/format/recordLitMultilineBlockCommentsA.dhall +9/−0
- tests/format/recordLitMultilineBlockCommentsB.dhall +9/−0
- tests/format/recordTypeCommentsA.dhall +6/−0
- tests/format/recordTypeCommentsB.dhall +6/−0
- tests/format/sha256PrintingB.dhall +2/−1
- tests/format/significantLeadingSpacesA.dhall +1/−0
- tests/format/significantLeadingSpacesB.dhall +5/−0
- tests/format/stringWithNullA.dhall +1/−0
- tests/format/stringWithNullB.dhall +3/−0
- tests/format/textLitNewlinesOnlyA.dhall +1/−0
- tests/format/textLitNewlinesOnlyB.dhall +1/−0
- tests/format/timePrecisionA.dhall +3/−0
- tests/format/timePrecisionB.dhall +3/−0
- tests/format/unicodeA.dhall +5/−5
- tests/format/unicodeB.dhall +7/−13
- tests/format/urlsA.dhall +7/−0
- tests/format/urlsB.dhall +7/−0
- tests/format/usingToMapA.dhall +1/−0
- tests/format/usingToMapB.dhall +1/−0
- tests/format/withA.dhall +5/−0
- tests/format/withB.dhall +58/−0
- tests/format/withPrecedenceA.dhall +5/−0
- tests/format/withPrecedenceB.dhall +1/−0
- tests/format/withQuestionA.dhall +1/−0
- tests/format/withQuestionB.dhall +1/−0
- tests/freeze/cached/True.dhall +1/−0
- tests/freeze/cached/cachedA.dhall +2/−0
- tests/freeze/cached/cachedB.dhall +3/−0
- tests/freeze/cached/idempotentA.dhall +5/−0
- tests/freeze/cached/idempotentB.dhall +3/−0
- tests/freeze/cached/incorrectHashA.dhall +1/−0
- tests/freeze/cached/incorrectHashB.dhall +3/−0
- tests/freeze/cached/protectedA.dhall +1/−0
- tests/freeze/cached/protectedB.dhall +3/−0
- tests/freeze/cached/unprotectedA.dhall +1/−0
- tests/freeze/cached/unprotectedB.dhall +3/−0
- tests/freeze/secure/True.dhall +1/−0
- tests/freeze/secure/cachedA.dhall +2/−0
- tests/freeze/secure/cachedB.dhall +2/−0
- tests/freeze/secure/incorrectHashA.dhall +1/−0
- tests/freeze/secure/incorrectHashB.dhall +2/−0
- tests/freeze/secure/protectedA.dhall +1/−0
- tests/freeze/secure/protectedB.dhall +2/−0
- tests/freeze/secure/unprotectedA.dhall +1/−0
- tests/freeze/secure/unprotectedB.dhall +2/−0
- tests/lint/success/PreludeExtensionA.dhall +1/−0
- tests/lint/success/PreludeExtensionB.dhall +1/−0
- tests/lint/success/assertA.dhall +14/−0
- tests/lint/success/assertB.dhall +12/−0
- tests/lint/success/fixAssertA.dhall +5/−0
- tests/lint/success/fixAssertB.dhall +1/−0
- tests/lint/success/issue1586A.dhall +1/−0
- tests/lint/success/issue1586B.dhall +5/−0
- tests/lint/success/multiletA.dhall +1/−2
- tests/lint/success/multiletB.dhall +20/−20
- tests/lint/success/regression0A.dhall +1/−1
- tests/lint/success/regression0B.dhall +1/−1
- tests/package/dir/package.dhall +0/−0
- tests/package/dir/subdirectory1/test.dhall +0/−0
- tests/package/dir/subdirectory2/wrong-extension.txt +0/−0
- tests/package/dir/test.dhall +0/−0
- tests/package/dir/wrong-extension.txt +0/−0
- tests/package/empty/wrong-extension.txt +0/−0
- tests/package/other/package.dhall +0/−0
- tests/package/package.dhall +0/−0
- tests/package/test.dhall +0/−0
- tests/package/test/test.dhall +0/−0
- tests/recursive/expr0.dhall +17/−0
- tests/recursive/expr1.dhall +15/−0
- tests/regression/issue151a.dhall +1/−1
- tests/regression/issue151b.dhall +1/−1
- tests/regression/issue1584.dhall +19/−0
- tests/regression/issue1646.dhall +1/−0
- tests/regression/issue1732.dhall +1/−0
- tests/regression/issue1884.dhall +4/−0
- tests/regression/issue2088.dhall +1/−0
- tests/regression/issue216a.dhall +1/−1
- tests/regression/issue216b.dhall +2/−2
- tests/schemas/multipleA.dhall +1/−0
- tests/schemas/multipleB.dhall +1/−0
- tests/schemas/multipleSchema.dhall +3/−0
- tests/schemas/personA.dhall +4/−0
- tests/schemas/personB.dhall +6/−0
- tests/schemas/personSchema.dhall +11/−0
- tests/tags/all.tags +61/−0
- tests/tags/let.dhall +4/−0
- tests/tags/let.tags +6/−0
- tests/tags/nonunicode.dhall +3/−0
- tests/tags/nonunicode.tags +5/−0
- tests/tags/record.dhall +35/−0
- tests/tags/record.tags +13/−0
- tests/tags/recordlit.dhall +14/−0
- tests/tags/recordlit.tags +10/−0
- tests/tags/simple.dhall +39/−0
- tests/tags/simple.tags +11/−0
- tests/tags/unicode.dhall +3/−0
- tests/tags/unicode.tags +5/−0
- tests/tags/union.dhall +4/−0
- tests/tags/union.tags +11/−0
- tests/th/Department.dhall +1/−0
- tests/th/Employee.dhall +1/−0
- tests/th/HigherKindSingle.dhall +1/−0
- tests/th/HigherKindUnion.dhall +1/−0
- tests/th/Time.dhall +1/−0
- tests/th/example.dhall +1/−0
- tests/th/issue2066.dhall +7/−0
- tests/to-directory-tree/fixpoint-allow-path-separators.dhall +25/−0
- tests/to-directory-tree/fixpoint-empty.dhall +3/−0
- tests/to-directory-tree/fixpoint-helper.dhall +30/−0
- tests/to-directory-tree/fixpoint-permissions.dhall +24/−0
- tests/to-directory-tree/fixpoint-simple.dhall +25/−0
- tests/to-directory-tree/fixpoint-usergroup.dhall +25/−0
- tests/to-directory-tree/type.dhall +36/−0
- tests/tutorial/Union.dhall +1/−0
- tests/tutorial/substitution1.dhall +1/−0
- tests/tutorial/substitution2.dhall +1/−0
- tests/tutorial/substitution3.dhall +1/−0
- tests/tutorial/unions0A.dhall +1/−1
- tests/tutorial/unions1A.dhall +1/−1
- tests/tutorial/unions2A.dhall +0/−8
- tests/tutorial/unions2B.dhall +0/−5
@@ -1,504 +1,1521 @@-1.24.0--* Supports version 8.0.0 of the standard- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v8.0.0-* BREAKING CHANGE: Allow tabs and blank lines in multi-line strings- * Blank lines are now ignored for the purpose of dedenting multiline strings- * Lines with leading tabs (or mixed tabs and spaces) are now dedented, too,- so long as they all share the same prefix- * This is technically a breaking change, but unlikely to affect programs- in practice, especially if they were formatted with `dhall format`. This- change mainly affects programs that were not indented correctly.- * See the changelog for standard version 8.0.0 for more details-* BREAKING CHANGE: Simplify bare interpolations- * Expressions like `λ(x : Text) → "${x}"` now simplify to `λ(x : Text) → x`- * This is a technically breaking change because it changes how these sorts- of expressions are serialized. This does not affect semantic integrity- checks and the new simplified expressions are extensionally equivalent to- their older counterpart expressions.- * See the changelog for standard version 8.0.0 for more details-* BREAKING CHANGE: Encode integrity check as multihash- * Semantic integrity checks are now encoded using the multihash spec- * This is a technically breaking change that does not perturb the hash for- user-facing semantic integrity checks. This only affects how expressions- with unresolved imports are serialized, but semantic integrity checks are- only computed for fully-resolved imports.- * See the changelog for standard version 8.0.0 for more details-* BUG FIX: Fix type-checker to reject invalid record type annotations- * e.g. `{ x = 1 } : { x : Text }` was not properly rejected by the type- checker- * See: https://github.com/dhall-lang/dhall-haskell/pull/965-* BUG FIX: Custom header forwarding fixed- * Forwarding custom headers could previously fail in various ways, such as:- * Cyclic imports leading to endless network requests- * Resolving a non-existent import for the custom headers- * Resolving an existing but incorrect import for the custom headers- * This change fixes that by forwarding custom headers by value instead of- by reference- * See: https://github.com/dhall-lang/dhall-haskell/pull/967-* BUG FIX: Fix GHCJS support- * `Natural/fold` was broken in version 1.22, which this change fixes- * Specifically, it would hang for `Natural` numbers greater than 1- * See: https://github.com/dhall-lang/dhall-haskell/pull/985-* BUG FIX: `dhall diff` no longer double-prints key-value separators- * See: https://github.com/dhall-lang/dhall-haskell/pull/952-* Feature: Record projection by expression- * You can now project out a subset of record fields by the expected type- * `let t = { x : Natural } let p = { x = 1, y = 2 } in p.(t) = { x = 1 }`- * See the changelog for standard version 8.0.0 for more details-* Feature: Inline headers- * You no longer need to specify custom headers in a separate import. You- can now specify them inline within the same file.- * e.g.: `https://example.com/x using [ { header = "Foo", value = "Bar" } ]`- * See the changelog for standard version 8.0.0 for more details-* Feature: Allow `Sort` as a type annotation- * An expression such as `Kind → Kind : Sort` will now type-check- * `Sort` is still disallowed outside of a type annotation- * See the changelog for standard version 8.0.0 for more details-* Feature: Allow self-describe-cbor when decoding- * Dhall expressions serialized as CBOR can be tagged to describe themselves- as CBOR without affecting decoding- * See the changelog for standard version 8.0.0 for more details-* Feature: New `--file` option for `dhall` commands- * In other words, instead of `dhall <<< './some/file` you can now use- `dhall --file some/file`- * See: https://github.com/dhall-lang/dhall-haskell/pull/949-* Feature: New `--cache` flag for `dhall freeze` command- * This automates the idiom used by the Prelude to optimistically cache- imports but gracefully degrade if the semantic integrity check fails- * See: https://github.com/dhall-lang/dhall-haskell/pull/980-* Feature: Add `:clear` command to `dhall repl`- * This deletes previous bindings from the history so that they can be- garbage collected- * See: https://github.com/dhall-lang/dhall-haskell/pull/966-* Feature: New `chunkExprs` `Traversal` added to `Dhall.Core`- * See: https://github.com/dhall-lang/dhall-haskell/pull/954-* Feature: New `Dhall.Optics` module- * This re-exports some convenient @lens@ utilities used internally for- packages trying to avoid a @lens@ dependency- * See: https://github.com/dhall-lang/dhall-haskell/pull/986-* More GHC 8.8 support- * See: https://github.com/dhall-lang/dhall-haskell/pull/961--1.23.0--* BREAKING CHANGE: Fix marshaling union literals- * 1.22.0 introduced two separate bugs in marshaling union literals between- Dhall and Haskell, which this release fixes:- * Dhall enums did not correctly map onto Haskell enums- * New-style union literals (i.e. `< A : T >.A x`) were not correctly- supported- * See: https://github.com/dhall-lang/dhall-haskell/pull/918- * See: https://github.com/dhall-lang/dhall-haskell/pull/927- * See: https://github.com/dhall-lang/dhall-haskell/pull/936-* BUG FIX: Fix α-normalization- * Version 1.22.0 introduced a new faster evaluation algorithm, but the new- algorithm introduced two α-normalization regression, which this release- fixes- * The primary effect of this bug was that semantic integrity checks would- fail for expressions that contain an `if`/`then`/else` expression in their- normal form- * See: https://github.com/dhall-lang/dhall-haskell/pull/931- * See: https://github.com/dhall-lang/dhall-haskell/pull/938-* BUG FIX: Fix merging of sort-level record types- * The language standard requires that `{ a : Kind } ⩓ { b : Kind }` is- valid, which this change fixes- * See: https://github.com/dhall-lang/dhall-haskell/pull/891-* BUG FIX: `dhall freeze` respects the `--ascii` flag- * See: https://github.com/dhall-lang/dhall-haskell/pull/934-* BUG FIX: Don't autocomplete fields for record types- * This prevents the REPL from expanding `{ x : T }.<TAB>` to `{ x : T }.x`- * See: https://github.com/dhall-lang/dhall-haskell/pull/937-* Support `MonadFail`-related changes in GHC 8.8- * See: https://github.com/dhall-lang/dhall-haskell/pull/912-* Add `cross` flag to simplify cross-compilation- * This allows the `dhall` package to be built without using- `TemplateHaskell`- * See: https://github.com/dhall-lang/dhall-haskell/pull/928-* Increase lines of context for error messages - * Error messages now provide at least 20 lines of context instead of 3- before truncating large expressions- * See: https://github.com/dhall-lang/dhall-haskell/pull/916-* Add line numbers to error messages- * The bottom of every Dhall type error includes the original source code,- which now has line numbers on the left margin- * See: https://github.com/dhall-lang/dhall-haskell/pull/919-* Expand lower bounds on `megaparsec`/`transformers-compat` dependencies- * This is to support `dhall` on Debian Sid- * See: https://github.com/dhall-lang/dhall-haskell/pull/939--1.22.0--* Supports version 7.0.0 of the standard- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v7.0.0-* BREAKING CHANGE: Add support for empty alternatives- * The `Union` type now has an optional (`Maybe`) type for each alternative- * See the changelog for standard version 7.0.0 for more details- * See: https://github.com/dhall-lang/dhall-haskell/pull/863-* BREAKING CHANGE: Remove support for URL fragments- * The `URL` type no longer has a field for a URL fragment since the language- no longer supports fragments- * See the changelog for standard version 7.0.0 for more details- * See: https://github.com/dhall-lang/dhall-haskell/pull/851-* BREAKING CHANGE: Remove deprecated `Path` type synonym- * See: https://github.com/dhall-lang/dhall-haskell/pull/858-* BUG FIX: Correctly parse identifiers beginning with `http`- * i.e. `httpPort` was supposed to be a valid identifier name and now is- * See: https://github.com/dhall-lang/dhall-haskell/pull/870-* BUG FIX: Fix `dhall encode` bug- * `dhall encode` bug was generating binary expressions that were valid- (i.e. they would decode correctly) but were non-standard (i.e. hashing- them would not match the hash you would normally get from a semantic- integrity check)- * Semantic integrity checks were not affected by this bug since they used- a slightly different code path that generated the correct binary input to- the hash. Only the `dhall decode` subcommand was affected- * See: https://github.com/dhall-lang/dhall-haskell/pull/859-* BUG FIX: Fix for `Dhall.UnionType`- * This fixes some expressions that would previously fail to marshal into- Haskell, specifically those were the marshalling logic was built using- the `UnionType` utilities- * See: https://github.com/dhall-lang/dhall-haskell/pull/857-* Feature: New `--alpha` flag to α-normalize command-line output- * See: https://github.com/dhall-lang/dhall-haskell/pull/855-* Performance improvements- * The normalizer is now *much* faster- * See: https://github.com/dhall-lang/dhall-haskell/pull/876--1.21.0--* Supports version 6.0.0 of the language standard- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v6.0.0-* BREAKING CHANGE: Remove the `constructors` keyword- * ... as standardized in version 6.0.0 of the language standard- * The deprecation cycle is over, so the keyword is no longer supported- * For more details, see: https://github.com/dhall-lang/dhall-lang/wiki/Migration%3A-Deprecation-of-constructors-keyword- * See: https://github.com/dhall-lang/dhall-haskell/pull/829-* BREAKING CHANGE: CBOR-encode only special `Double`s as half-floats- * ... as standardized in version 6.0.0 of the language standard- * CBOR `Double`s except `Infinity`/`-Infinity`/`NaN`/`0.0` are now encoded in at- least 32 bits- * See: https://github.com/dhall-lang/dhall-haskell/pull/822-* BREAKING CHANGE: Sort record and union fields when CBOR-encoding- * Fields and alternatives are now sorted when serialized- * This does not affect semantic integrity checks, which already sorted these- fields/alternatives before hashing expressions- * This does affect the serialization of expressions that have not been- normalized (e.g. uninterpreted expressions transmitted over the wire)- * See: https://github.com/dhall-lang/dhall-haskell/pull/835-* BUG FIX: Fix non-exhaustive pattern match in `dhall lint`- * This fixes: `Irrefutable pattern failed for pattern Let (l' :| ls') d'`- * This bug would cause `dhall lint` to fail on some nested `let`/`in`- expressions- * See: https://github.com/dhall-lang/dhall-haskell/pull/780- * See: https://github.com/dhall-lang/dhall-haskell/pull/784-* BUG FIX: Don't fail if `$HOME` environment variable is unset- * The interpreter was incorrectly throwing an exception if `HOME` was unset- * The standard requires that implementations should handle the `HOME`- environment variable being missing- * See: https://github.com/dhall-lang/dhall-haskell/pull/789-* Feature: Remove version tag from semantic integrity check- * ... as standardized in version 6.0.0 of the language standard- * This is not a breaking change because this change also includes- backwards-compatible support for semantic integrity checks produced by- older versions of the interpreter-* Feature: Support Unicode path components- * ... as standardized in version 6.0.0 of the language standard- * You can now use Unicode in path components if they are quoted- * i.e. `./families/"禺.dhall"` is now legal-* Feature: Add `Text/show` built-in- * ... as standardized in version 6.0.0 of the language standard- * You can now convert a `Text` literal to its equivalent Dhall source code- (which is itself a `Text` literal)- * This comes in handy when using Dhall code to generate JSON or Dhall code- * See: https://github.com/dhall-lang/dhall-haskell/pull/811-* Feature: Add `--immediate-dependencies`/`--transitive-dependencies` flags for- `dhall resolve`- * You can now retrieve all of your immediate or transitive dependencies as a- textual list- * This simplifies integration with other command-line tools (such as file- watchers)- * See: https://github.com/dhall-lang/dhall-haskell/pull/795- * See: https://github.com/dhall-lang/dhall-haskell/pull/803-* Feature: `dhall freeze` now only freezes remote imports by default- * `dhall freeze` used to freeze all imports (including local imports and- environment variables)- * Now `dhall freeze` only freezes remote imports by default, which is what- most users want- * You can install freeze all imports using the `--all` flag- * See: https://github.com/dhall-lang/dhall-haskell/pull/808-* Feature: `:save` and `:load` REPL state- * `:save` with no arguments now saves the REPL state to a `.dhall-repl-N`- file- * The file format is a list of `dhall repl` commands- * You can use `:load` to load the saved state back into the REPL- * See: https://github.com/dhall-lang/dhall-haskell/pull/807-* Feature: Add `:hash` command to `dhall repl`- * This lets you conveniently hash expressions within the `dhall repl`- * See: https://github.com/dhall-lang/dhall-haskell/pull/806-* Feature: Add `--check` flag to `dhall format`- * Use this to check if the input is already formatted- * Useful for continuous integration when you want to ensure that all code- under version control remains formatted- * See: https://github.com/dhall-lang/dhall-haskell/pull/810-* Feature: Add `UnionInputType` builder for `InputType`s- * This is the union analog of `RecordInputType`, letting you build a- record explicitly instead of deriving the instance using GHC generics- * See: https://github.com/dhall-lang/dhall-haskell/pull/775-* Feature: Add `:set`/`:unset` commands to `dhall repl`- * You can use these commands to set or unset command-line options- * Currently only setting/unsetting `--explain` is supported-* Standards-compliance fixes:- * See: https://github.com/dhall-lang/dhall-haskell/pull/779- * See: https://github.com/dhall-lang/dhall-haskell/pull/804- * See: https://github.com/dhall-lang/dhall-haskell/pull/833-* Documentation fixes:- * See: https://github.com/dhall-lang/dhall-haskell/pull/792- * See: https://github.com/dhall-lang/dhall-haskell/pull/825-* Test fixes:- * See: https://github.com/dhall-lang/dhall-haskell/pull/782- * See: https://github.com/dhall-lang/dhall-haskell/pull/836-* Improved error messages:- * See: https://github.com/dhall-lang/dhall-haskell/pull/812- * See: https://github.com/dhall-lang/dhall-haskell/pull/815- * See: https://github.com/dhall-lang/dhall-haskell/pull/824-* Formatting fixes:- * See: https://github.com/dhall-lang/dhall-haskell/pull/831-* REPL fixes:- * See: https://github.com/dhall-lang/dhall-haskell/pull/837--1.20.1--* BUG FIX: Fix binary encoding to use correct standard version- * This fixes computed hashes to correctly match standard version 5.0.0- * This is not marked as a breaking change since it is a bug fix. The- 1.20.0 release will be blacklisted on Hackage and users should upgrade- from 1.19.* directly to 1.20.1- * See: https://github.com/dhall-lang/dhall-haskell/pull/771--1.20.0--* Supports version 5.0.0 of the language standard- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v5.0.0-* BREAKING CHANGE TO THE LANGUAGE: Implement standardized support for multi-line- literals- * This updates the multi-line support to match the standard- * This is a breaking change because empty lines within the multi-line- literal now require leading whitespace whereas previously they did not- * This is also a breaking change because now a newline is required after- the opening `''` quotes whereas previously it was not required- * If you use `dhall format` then your multi-line literals already have the- necessary leading whitespace-* BREAKING CHANGE TO THE LANGUAGE: `constructors x = x`- * Now the `constructors` keyword behaves like an identity function, since- constructors can already be accessed as fields off the original union- type.- * This is a breaking change since any record of terms that contains a- `constructors` field will now be a forbidden mixed record of types and- terms.- * This is also a breaking change if you annotated the type of what used to- be a `constructors` record.- * `dhall lint` will now remove the obsolete `constructors` keyword for you- * See: https://github.com/dhall-lang/dhall-haskell/pull/693- * See: https://github.com/dhall-lang/dhall-haskell/pull/701-* BREAKING CHANGE TO THE API: Restore `Parent` constructor for `Local` type- * This more closely matches the standard and also enables `dhall format` to- produce a leading `../` for imports instead of `./../`- * See: https://github.com/dhall-lang/dhall-haskell/pull/718-* BUG FIX: Fix type-checking bug for unions- * The first fix was that the inferred type was wrong for unions where- alternatives were types or kinds- * The second fix was that unions that mixed terms/types/kinds were not- properly rejected- * See: https://github.com/dhall-lang/dhall-haskell/pull/763-* BUG FIX: Change how `dhall repl` handles prior definitions- * This changes the REPL to handle previous bindings as if they were- defined using a large `let` expression instead of adding them to the- context- * This fixes some type-checking false negatives- * See: https://github.com/dhall-lang/dhall-haskell/pull/729-* Feature: Autocomplete for `dhall repl`- * You can now auto-complete record fields, union constructors, and- identifiers that are in scope- * See: https://github.com/dhall-lang/dhall-haskell/pull/727-* Feature: GHCJS support- * `dhall` can now be built using GHCJS, although some features are still- not supported for GHCJS, such as:- * Semantic integrity checks- * Custom HTTP headers- * Also, HTTP imports only work for URLs that support CORS- * See: https://github.com/dhall-lang/dhall-haskell/pull/739-* Feature: Add support for records of records of types- * You can now nest records of types- * See: https://github.com/dhall-lang/dhall-haskell/pull/700-* Feature: Add `:quit` command for `dhall repl`- * See: https://github.com/dhall-lang/dhall-haskell/pull/719-* Feature: Add `--json` flag for `dhall {encode,decode}`- * You can now produce/consume CBOR expressions via JSON instead of binary- * See: https://github.com/dhall-lang/dhall-haskell/pull/717-* Feature: Add decoding logic for `as Text`- * You can now preserve the `as Text` qualifier on imports when serializing- them- * See: https://github.com/dhall-lang/dhall-haskell/pull/712-* Prenormalize substituted expressions- * This is a performance improvement that reduces the time and memory- consumption when normalizing expressions- * See: https://github.com/dhall-lang/dhall-haskell/pull/765--1.19.1---* BUG FIX: Fix serious `dhall lint` bug- * `dhall lint` would sometimes remove `let` expressions that were still- in use- * See: https://github.com/dhall-lang/dhall-haskell/pull/703-* BUG FIX: Fix import caching efficiency bug- * Some imports were being wastefully fetched multiple times- * See: https://github.com/dhall-lang/dhall-haskell/pull/702-* Feature: Generate dot graph to visualize import graph- * Use the `dhall resolve --dot` command- * See: https://github.com/dhall-lang/dhall-haskell/pull/698- * See: https://github.com/dhall-lang/dhall-haskell/pull/713-* Improve HTTP error messages- * See: https://github.com/dhall-lang/dhall-haskell/pull/710--1.19.0--* Supports version 4.0.0 of the language standard- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v4.0.0-* BREAKING CHANGE TO THE LANGUAGE AND API: Prevent Hurkens' paradox- * This fixes a type-checking soundness bug which permitted infinite loops- * This is a breaking change because infinite loops are no longer possible- * This is also a breaking change because a record of types is now treated as- a kind instead of a type- * See: https://github.com/dhall-lang/dhall-haskell/pull/680-* BREAKING CHANGE TO THE LANGUAGE AND API: `Double`s are now double-precision- floating point numbers- * This restricts the range of `Double`s to IEEE 754 double-precision- floating point- * This also implies that you can no longer convert `Scientific` values to- `Dhall` expressions (i.e. no `Inject` instance for `Scientific`)- * See: https://github.com/dhall-lang/dhall-haskell/pull/667-* BREAKING CHANGE TO THE API: Preserve field order for record projection- * The API uses a new `Dhall.Set.Set` type instead of `Data.Set.Set`- * See: https://github.com/dhall-lang/dhall-haskell/pull/670-* BREAKING CHANGE TO THE API: Add support for multi-`let` expressions- * This changes the `Let` constructor to now support storing multiple- bindings per `let` expression- * See: https://github.com/dhall-lang/dhall-haskell/pull/675-* Access constructors as if they were fields of the union type- * In other words: `< Left : Bool | Right : Natural >.Left`- * See: https://github.com/dhall-lang/dhall-haskell/pull/657-* Support GHC 8.6- * See: https://github.com/dhall-lang/dhall-haskell/pull/669-* Add support for quoted path components- * i.e. `/"foo"/bar/"baz qux"` or `https://example.com/foo/"bar?baz"?qux`- * See: https://github.com/dhall-lang/dhall-haskell/pull/690-* Fix parsing of `//\\` operator- * See: https://github.com/dhall-lang/dhall-haskell/commit/9d0fd42d95ab69fa64da4afd8b60d69aca8e65a6-* Preserve Unicode characters when formatting code- * See: https://github.com/dhall-lang/dhall-haskell/pull/679-* Allow identifier names to begin with `Some`- * See: https://github.com/dhall-lang/dhall-haskell/pull/658-* Add `subExpressions` `Traversal`- * See: https://github.com/dhall-lang/dhall-haskell/pull/660-* Add `normalizeWithM` for monadic normalization- * See: https://github.com/dhall-lang/dhall-haskell/pull/371-* Custom normalizers now take precedence over default normalization logic- * This allows one to override the implementation of built-in operators- * See: https://github.com/dhall-lang/dhall-haskell/pull/684--1.18.0--* Supports version 3.0.0 of the language standard:- * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v3.0.0-* BREAKING CHANGE TO THE LANGUAGE AND API: New `Some`/`None` constructors for- `Optional` values- * Example: `[ Some 1, None Natural ]`- * This is a breaking change to the language because `Some` and `None` are- now reserved keywords- * This is a breaking change to the API because `Some` and `None` are new- constructors for the `Expr` type-* BREAKING CHANGE TO THE LANGUAGE AND API: Support for kind polymorphism- * This adds a new `Sort` constant above `Kind` in the hierarchy- * i.e. `Type : Kind : Sort`- * This is a breaking change to the language because `Sort` is now a- reserved keyword- * This is a breaking change to the API because `Sort` is a new- constructor for the `Expr` type-* BREAKING CHANGE TO THE API: New `Dhall.Map` module- * This replaces `InsOrdHashMap` in the API- * The primary motivation is to improve performance and to remove the- dependency on `insert-ordered-containers`-* BREAKING CHANGE TO THE API: Use standard version instead of protocol version- * The binary protocol is now versioned alongside the standard- * The `ProtocolVersion` type is renamed to `StandardVersion` and the- * `--protocol-version` option is renamed to `--standard-version`- * See: https://github.com/dhall-lang/dhall-haskell/pull/634-* BUG FIX: Fix import chaining for custom header imports- * See: https://github.com/dhall-lang/dhall-haskell/pull/618-* BUG FIX: Fix import chaining for imports protected by semantic integrity- checks- * See: https://github.com/dhall-lang/dhall-haskell/pull/584-* BUG FIX: Record literals and types produced by `∧`/`⫽`/`⩓` are now sorted- * This ensures that β-normalization is idempotent- * See: https://github.com/dhall-lang/dhall-haskell/pull/572-* BUG FIX: `dhall freeze` now correctly handles the starting file being- located outside the current working directory- * See: https://github.com/dhall-lang/dhall-haskell/commit/a22aa79d1957be9ecf166ea066e2a9a5b309e1ae-* BUG FIX: Fix parsing of IPv4-mapped IPv6 addresses- * See: https://github.com/dhall-lang/dhall-haskell/pull/632-* FEATURE: New `--ascii` flag for ASCII output- * See: https://github.com/dhall-lang/dhall-haskell/pull/570-* FEATURE: New `dhall encode` and `dhall decode` subcommands- * These allow you to transform Dhall source code to and from its binary- representation- * See: https://github.com/dhall-lang/dhall-haskell/pull/588-* LARGE parsing performance improvements- * Parsing is about 10x-100x faster on most code- * See: https://github.com/dhall-lang/dhall-haskell/pull/591- * See: https://github.com/dhall-lang/dhall-haskell/pull/592- * See: https://github.com/dhall-lang/dhall-haskell/pull/597- * See: https://github.com/dhall-lang/dhall-haskell/pull/601- * See: https://github.com/dhall-lang/dhall-haskell/pull/602- * See: https://github.com/dhall-lang/dhall-haskell/pull/604- * See: https://github.com/dhall-lang/dhall-haskell/pull/606-* Type-checking performance improvements:- * See: https://github.com/dhall-lang/dhall-haskell/pull/566-* Normalization performance improvements:- * See: https://github.com/dhall-lang/dhall-haskell/pull/610-* `dhall freeze` now caches the imports as it freezes them- * See: https://github.com/dhall-lang/dhall-haskell/pull/587-* `dhall freeze` now refreezes imports with invalid semantic integrity checks- * See: https://github.com/dhall-lang/dhall-haskell/pull/637-* `dhall freeze` now adds a trailing newline- * See: https://github.com/dhall-lang/dhall-haskell/pull/629-* Build against `megaparsec-7.0.*`- * See: https://github.com/dhall-lang/dhall-haskell/pull/565-* Support GHC 8.6- * See: https://github.com/dhall-lang/dhall-haskell/pull/599- * See: https://github.com/dhall-lang/dhall-haskell/pull/623-* Support GHC all the way back to 7.10.3- * See: https://github.com/dhall-lang/dhall-haskell/pull/595- * See: https://github.com/dhall-lang/dhall-haskell/pull/621-* Improvements to error messages:- * See: https://github.com/dhall-lang/dhall-haskell/pull/563- * See: https://github.com/dhall-lang/dhall-haskell/pull/576- * See: https://github.com/dhall-lang/dhall-haskell/pull/583- * See: https://github.com/dhall-lang/dhall-haskell/pull/589---1.17.0--* This release corresponds to version 2.0.0 of the language standard-* BREAKING CHANGE TO THE LANGUAGE AND API: Binary serialization support- * This is a breaking change to the hash for all semantic integrity checks- * The hash used by the semantic integrity check is now based on the- binary representation instead of a text representation of the- expression- * You can pin the new hashes by supplying the `--protocol-version 1.0`- option on the command line until you need support for newer language- features +1.42.3++* [Fix the typechecking rule for `Optional` + `with`](https://github.com/dhall-lang/dhall-haskell/pull/2650)+* [Add `*WithIndex` instances for `Map`](https://github.com/dhall-lang/dhall-haskell/pull/2633)+* [`dhall package`: Add support for automatic sub-packags](https://github.com/dhall-lang/dhall-haskell/pull/2639)+* [`dhall to-directory-tree`: Add `binary-file` support](https://github.com/dhall-lang/dhall-haskell/pull/2641)+* [Support GHC 9.12.1](https://github.com/dhall-lang/dhall-haskell/pull/2649)+* [`dhall to-directory-tree`: create parents of files when using fixpoint representation](https://github.com/dhall-lang/dhall-haskell/pull/2653)++1.42.2++* [Supports standard version 23.1.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v23.1.0)+ * [Allow `Natural` and `Integer` literals in binary notation](https://github.com/dhall-lang/dhall-haskell/pull/2540)+* Fix macOS build [[#2561](https://github.com/dhall-lang/dhall-haskell/pull/2561)] / [[#2586](https://github.com/dhall-lang/dhall-haskell/pull/2586)]+* [`dhall to-directory-tree`: Fix support for empty `Map`s](https://github.com/dhall-lang/dhall-haskell/pull/2609)+* [`Dhall.TH`: Improve recompilation checking](https://github.com/dhall-lang/dhall-haskell/pull/2620)+ * `Dhall.TH` utilities now use `addDependentFile` internally so that GHC will recompile if any Dhall dependencies change+* Performance improvements+ * Optimize `Natural/fold`: [[#2585](https://github.com/dhall-lang/dhall-haskell/pull/2585)] / [[#2596](https://github.com/dhall-lang/dhall-haskell/pull/2596)]+ * [Improve `Dhall.Map.traverseWithKey` performance](https://github.com/dhall-lang/dhall-haskell/pull/2589)+ * The fold will now short-circuit if it reaches a fixed point+ * [#2611](https://github.com/dhall-lang/dhall-haskell/pull/2611)+* Fixes and improvements to test suite+ * [#2593](https://github.com/dhall-lang/dhall-haskell/pull/2593)+* Fixes and improvements to haddocks+ * [#2546](https://github.com/dhall-lang/dhall-haskell/pull/2546)+* Fixes and improvements to code formatting+ * [#2608](https://github.com/dhall-lang/dhall-haskell/pull/2608)++1.42.1++* Add several new entrypoints to `Dhall` module [[#2534](https://github.com/dhall-lang/dhall-haskell/pull/2534)] / [[#2544](https://github.com/dhall-lang/dhall-haskell/pull/2544)]+* Build against latest versions of:+ * [`ansi-terminal`](https://github.com/dhall-lang/dhall-haskell/pull/2521)+ * [`optparse-applicative`](https://github.com/dhall-lang/dhall-haskell/pull/2543)+ * [`optparse-generic`](https://github.com/dhall-lang/dhall-haskell/pull/2519)+ * [`lens`](https://github.com/dhall-lang/dhall-haskell/pull/2539)+ * `template-haskell` [[#2532](https://github.com/dhall-lang/dhall-haskell/pull/2532)] / [[#2542](https://github.com/dhall-lang/dhall-haskell/pull/2542)]+ * [`unix-compat`](https://github.com/dhall-lang/dhall-haskell/pull/2532)+1.42.0++* [Supports standard version 23.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v23.0.0)+ * [BREAKING CHANGE TO THE API AND LANGUAGE: Language support for `Bytes` literals](https://github.com/dhall-lang/dhall-haskell/pull/2499)+ * This is a breaking change to the API due to adding new `Bytes` and `BytesLiteral` constructors to the `Expr` type+ * This is a breaking change to the language now that `Bytes` is a reserved identifier+ * [BREAKING CHANGE TO THE API AND LANGUAGE: New `{Date,Time,TimeZone}/show` builtins](https://github.com/dhall-lang/dhall-haskell/pull/2493)+ * This is a breaking change to the API due to adding new `{Date,Time,TimeZone}Show` constructors to the `Expr` type+ * This is a breaking change to the language now that `{Date,Time,TimeZone}/show` are not reserved identifiers+* [BREAKING CHANGE: `dhall lint` no longer sorts `let` bindings](https://github.com/dhall-lang/dhall-haskell/pull/2503)+ * This had to be removed because the old behavior was not always correct+ * The old behavior would sometimes change the behavior of a Dhall program or break the program+ * Out of an abundance of caution we're disabling the feature until it can be properly fixed (which is't trivial)+* [BUG FIX: Fix pretty-printing of `Time` literals](https://github.com/dhall-lang/dhall-haskell/pull/2466)+ * The pretty-printer was stripping leading zeros from the fractional component+ of seconds+* [BUG FIX: Fix custom normalizers to work for things other than functions](https://github.com/dhall-lang/dhall-haskell/pull/2464)+ * Before this change you could extend the language with custom functions, but+ not custom values (e.g. `foo = 1`)+* [BUG FIX: Don't URL encode path components](https://github.com/dhall-lang/dhall-haskell/pull/2505)+ * The pretty-printer was URL-encoding path components, which is not correct (according to the standard)+ * URL path components are supposed to be already URL-encoded by the user and left undisturbed by the interpreter (which is now what it correctly does)+* New `dhall package` command: [#2478](https://github.com/dhall-lang/dhall-haskell/pull/2487), [#2508](https://github.com/dhall-lang/dhall-haskell/pull/2508)+ * This command makes it easier to turn a directory full of Dhall expressions+ into a dhall package (e.g. `package.dhall`)+* [Improved `dhall to-directory-tree` subcommand](https://github.com/dhall-lang/dhall-haskell/pull/2437)+ * The `dhall to-directory-tree` subcommand now optionally supports specifying+ metadata for generated paths+ * For a worked example, see: https://github.com/dhall-lang/dhall-haskell/blob/main/dhall/examples/to-directory-tree.dhall+* `dhall freeze --cache --all` is now idempotent: [#2486](https://github.com/dhall-lang/dhall-haskell/pull/2486), [#2500](https://github.com/dhall-lang/dhall-haskell/pull/2500)+ * Before this change a second run would fail due to attempting to resolve+ the `missing` import it would generate+* [New Template Haskell options for adding strictness annotations to generated Haskell types](https://github.com/dhall-lang/dhall-haskell/pull/2504)+* [Template Haskell can now generate higher-kinded Haskell types from higher-kinded Dhall types](https://github.com/dhall-lang/dhall-haskell/pull/2506)+* [New `Dhall.Freeze` utilities for working with custom evaluators](https://github.com/dhall-lang/dhall-haskell/pull/2478)+* [Add `Data` instances for `Import` and various other types](https://github.com/dhall-lang/dhall-haskell/pull/2462)+* [Add `Eq` instances for `InvalidDecoder` and `ExtractError`](https://github.com/dhall-lang/dhall-haskell/pull/2482)++1.41.2++* [BUG FIX: Fix `:hash` REPL command to α-normalize input](https://github.com/dhall-lang/dhall-haskell/pull/2420)+* [Add `{From,To}Dhall` instances for `DayOfWeek`](https://github.com/dhall-lang/dhall-haskell/pull/2413)+* [Add `{From,To}Dhall` instances for `ShortText`](https://github.com/dhall-lang/dhall-haskell/pull/2413)+* Performance improvements+ * [#2423](https://github.com/dhall-lang/dhall-haskell/pull/2423)+* Fixes and improvements to haddocks+ * [#2396](https://github.com/dhall-lang/dhall-haskell/pull/2396)+* Fixes and improvements to test suite+ * [#2342](https://github.com/dhall-lang/dhall-haskell/pull/2382)+ * [#2394](https://github.com/dhall-lang/dhall-haskell/pull/2394)+* Build against newer dependencies+ * [`pretty-simple-4.1`](https://github.com/dhall-lang/dhall-haskell/pull/2408)+ * [`aeson-2.1`](https://github.com/dhall-lang/dhall-haskell/pull/2424)+ * [`vector-0.13`](https://github.com/dhall-lang/dhall-haskell/pull/2427)+ * [`turtle-1.6`](https://github.com/dhall-lang/dhall-haskell/pull/2431)++1.41.1++* [BUG FIX: Don't escape `?` path component when pretty-printing `with` expressions](https://github.com/dhall-lang/dhall-haskell/pull/2392)++1.41.0++* [Support standard version 22.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v22.0.0)+ * [Allow `with` expressions to update `Optional` values using `?`](https://github.com/dhall-lang/dhall-haskell/pull/2386)+ * [Add `showConstructor` keyword](https://github.com/dhall-lang/dhall-haskell/pull/2384)+* [BUG FIX: Fix pretty-printing of time zones](https://github.com/dhall-lang/dhall-haskell/pull/2379)+ * Timezones with a negative offset were previously being rendered with two+ leading minus signs instead of one+* [BUG FIX: `dhall freeze --cache` to work with standard version 21.0.0](https://github.com/dhall-lang/dhall-haskell/pull/2350)+ * `dhall freeze` will now use `missing sha256:…` for the first import so that+ the latter import will be tried if the import is not in cache+ * The old behavior is incompatible with standard version 21.0.0 because the+ new behavior of the `?` operator doesn't fall back on hash mismatches+* [BUG FIX: Allow `with` expression to update a field named `Some`](https://github.com/dhall-lang/dhall-haskell/pull/2354)+ * This fixes a discrepancy between the Haskell implementation and the standard+ where the Haskell implementation would not permit+ `{ Some = 0 } with Some = 1 `+* [Fix `dhall {format,lint,freeze}` to preserve leading shebangs](https://github.com/dhall-lang/dhall-haskell/pull/2364)+* [Add `FromDhall` instances for `Int{8,16,32,64}`](https://github.com/dhall-lang/dhall-haskell/pull/2349)++1.40.2++* [Supports standard version 21.1.0](https://github.com/dhall-lang/dhall-haskell/pull/2236)+ * [The interpreter now supports customizing headers using a `headers.dhall`+ configuration file](https://github.com/dhall-lang/dhall-haskell/pull/2236)+ * [Generalize grammar for certain annotations](https://github.com/dhall-lang/dhall-haskell/pull/2320)+ * [Add support for a trailing line comment without a newline](https://github.com/dhall-lang/dhall-haskell/pull/2309)+* [BUG FIX: `dhall repl` no longer ignores type annotations on `:let` commands](https://github.com/dhall-lang/dhall-haskell/pull/2297)+ * Before this fix, `:let x : T = 3` would ignore the `: T` type annotation+* [BUG FIX: Don't accept a bar after an empty union](https://github.com/dhall-lang/dhall-haskell/pull/2338)+ * Before this fix, the interpreter would accept something like `<>|`, which+ is not valid according to the standard grammar+* New `FromDhall`/`ToDhall` instances for `Day`/`TimeOfDay`/`TimeZone` [#2294](https://github.com/dhall-lang/dhall-haskell/pull/2294) [#2300](https://github.com/dhall-lang/dhall-haskell/pull/2300)+ * These types correspond to the recent temporal literals added to the+ language+* [New `subExpressionsWith` `Traversal`](https://github.com/dhall-lang/dhall-haskell/pull/2302)+* [Add Template Haskell support for modifying field names in generated Haskell+ types](https://github.com/dhall-lang/dhall-haskell/pull/2285)+ * This adds a new `makeHaskellTypesWith` utility with takes a+ `GenerateOptions` function argument for customizing the code-generation+ logic+ * This comes in handy when Dhall fields have names are reserved keywords in+ Haskell code. You can now transform the Haskell field names to avoid+ collisions+* [Support GHC 9.2](https://github.com/dhall-lang/dhall-haskell/pull/2328)+* Fixes and improvements to documentation+ * [#2290](https://github.com/dhall-lang/dhall-haskell/pull/2290)+* Fixes and improvements to error messages+ * [#2303](https://github.com/dhall-lang/dhall-haskell/pull/2303)++1.40.1++* [BUG FIX: Fix equivalence check for `Date` / `Time` / `TimeZone`](https://github.com/dhall-lang/dhall-haskell/pull/2291)+ * This fixes a serious bug in the recently introduced support for temporal+ literals where they would fail to type-check when given a correct type+ annotation or when they were checked against an existing type+ * For example, `00:00:00 : Time` was failing to type-check++1.40.0++* [Almost supports version 20.2.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v20.2.0)+ * The main thing that is missing is support for the `headers.dhall` file+ * [BREAKING CHANGE TO THE LANGUAGE: Add support for `Date` / `Time` / `TimeZone` ](https://github.com/dhall-lang/dhall-haskell/pull/2247)+ * This is a breaking change because `Date`, `Time`, and `TimeZone` are+ now reserved identifiers+ * [Improved fallback behavior for `?`](https://github.com/dhall-lang/dhall-haskell/pull/2203)+* [BREAKING CHANGE TO THE LANGUAGE: Require whitespace before `with`](https://github.com/dhall-lang/dhall-haskell/pull/2213)+ * The parser now requires whitespace before the `with` keyword, which brings+ the Haskell implementation into closer compliance with the standard+ * In practice this is a technically breaking change which will not affect+ most programs+* [New `FromDhall` instances for `Predicate`, `Equivalence`, and `Op`](https://github.com/dhall-lang/dhall-haskell/pull/2278)+* [`dhall lint` will now sort `let` bindings with imports](https://github.com/dhall-lang/dhall-haskell/pull/2205)+ * `dhall lint` now reorders `let` bindings to move imports to the top so+ long as doing so does not change the behavior of the program+* Fixes and improvements to code formatting+ * [#2280](https://github.com/dhall-lang/dhall-haskell/pull/2280)+* Fixes and improvements to error messages+ * [#2244](https://github.com/dhall-lang/dhall-haskell/pull/2244)+ * [#2238](https://github.com/dhall-lang/dhall-haskell/pull/2238)++1.39.0++* [Supports version 20.2.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v20.2.0)+ * [Add support for Unix shebangs](https://github.com/dhall-lang/dhall-haskell/pull/2175)+* [BREAKING CHANGE TO THE API: `dhall {format,freeze,lint}` now accept multiple+ files](https://github.com/dhall-lang/dhall-haskell/pull/2169)+ * The `--inplace` flag is no longer necessary and you can now specify+ multiple files to update in place on the command line, like+ `dhall format foo.dhall bar.dhall`+ * The `--inplace` flag is still accepted, but does nothing, and will emit a+ warning+ * This is a breaking change to the API for formatting/freezing/linting files+ because now you can specify multiple inputs instead of one input+* [BREAKING CHANGE: Pre-6.0.0 hashes are no longer supported](https://github.com/dhall-lang/dhall-haskell/pull/2190)+ * The interpreter no longer provides backwards compatibility for integrity+ checks computed before standard version 6.0.0+ * This is a breaking change to the API of the `Dhall.Binary` module, where+ certain utilities are no longer parameterized on a `StandardVersion`+ * This is also a breaking change to any Dhall code that depended on these+ really old integrity checks+* [BUG FIX: Formatting `≡` now correctly preserves the original character set](https://github.com/dhall-lang/dhall-haskell/pull/2176)+* [BUG FIX: Don't panic on `Text/replace ""`](https://github.com/dhall-lang/dhall-haskell/pull/2184)+* [Quasiquotation support for Dhall](https://github.com/dhall-lang/dhall-haskell/pull/2198)+ * You can now convert a Dhall expression to the corresponding syntax tree+ using a quasiquoter like this: `[dhall| \x -> x + 2 ]`+* [New `Dhall.Marshal.{Encode,Decode}` modules](https://github.com/dhall-lang/dhall-haskell/pull/2193)+ * These modules split up the `Dhall` module into two smaller modules for+ encoding and decoding logic, respectively+ * The `Dhall` module still re-exports the same functionality as before, so+ this is not a breaking change+* [Support GHC 9.0.1](https://github.com/dhall-lang/dhall-haskell/pull/2154)+* Fixes and improvements to code formatting+ * [Improve pretty-printing of `sha256`](https://github.com/dhall-lang/dhall-haskell/pull/2189)++1.38.1++* [Add `INLINABLE` annotations in more places](https://github.com/dhall-lang/dhall-haskell/pull/2164)+ * This may improve performance by enabling more specializations+* [Fix `hashable`-related test failures](https://github.com/dhall-lang/dhall-haskell/pull/2152)+* [Fix support for GHC 8.4.4](https://github.com/dhall-lang/dhall-haskell/pull/2143)+ * … by using `GeneralizedNewtypeDeriving` (with a `z`)+* [Allow doctest-0.18](https://github.com/dhall-lang/dhall-haskell/pull/2148)+* [Allow bytestring-0.11](https://github.com/dhall-lang/dhall-haskell/pull/2144)++1.38.0++* [BREAKING CHANGE: Detect preferred character set from input](https://github.com/dhall-lang/dhall-haskell/pull/2108)+ * `dhall format` will now preserve the character set of the formatted file+ by default. In other words, if the file uses ASCII punctuation then+ `dhall format` will format the file using ASCII punctuation.+ * If the file contains both ASCII and Unicode punctuation it will prefer+ Unicode by default+ * This is a breaking change because the `Lam` / `Pi` / `Combine` /+ `CombineTypes`, and `Prefer` constructors now take an additional argument+ to record which character set was used+* [BUG FIX: Fix CORS compliance check](https://github.com/dhall-lang/dhall-haskell/pull/2121)+ * Previous versions were not correctly enforcing CORS compliance+ * This implies that some imports that would have worked previously by+ accident will now fail; specifically: an import from one domain+ transitively importing something from another domain that has not opted+ into CORS+* [Add `ToDhall (Fix f)` instance](https://github.com/dhall-lang/dhall-haskell/pull/2122)+* Fixes and improvements to error messages+ * [#2130](https://github.com/dhall-lang/dhall-haskell/pull/2130)++1.37.1++* [Fix performance regression for `with` expressions](https://github.com/dhall-lang/dhall-haskell/pull/2112)++1.37.0++* [Supports version 20.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v20.0.0)+ * [Implement revised `Text/replace` β-normalization](https://github.com/dhall-lang/dhall-haskell/pull/2072)+ * [Allow `Text/replace ""` to support an abstract haystack](https://github.com/dhall-lang/dhall-haskell/pull/2084)+ * [Support `if` expressions returning a type or kind](https://github.com/dhall-lang/dhall-haskell/pull/2080)+* BREAKING CHANGE TO THE API: [Improve error message for duplicate projection label](https://github.com/dhall-lang/dhall-haskell/pull/2097)+ * This also makes the implementation more standards-compliant, by treating+ a duplicate label as a type error instead of a parse error+ * This is a breaking change since the `Project` constructor now stores a+ `[Text]` instead of `Set Text`+* [Add `--cache` flag to `dhall hash`](https://github.com/dhall-lang/dhall-haskell/pull/2093)+ * This flag adds the hashed expression to the cache when enabled+* [Deprecate `Inject` / `Interpret`](https://github.com/dhall-lang/dhall-haskell/pull/2099)+ * You should instead use `ToDhall` / `FromDhall`, respectively+* Fixes and improvements to the haddocks:+ * [#2098](https://github.com/dhall-lang/dhall-haskell/pull/2098)+ * [#2100](https://github.com/dhall-lang/dhall-haskell/pull/2100)+* Fixes and improvements to error messages:+ * [#2082](https://github.com/dhall-lang/dhall-haskell/pull/2082)+ * [#2095](https://github.com/dhall-lang/dhall-haskell/pull/2095)+* Fixes and improvements to the parser:+ * [#2083](https://github.com/dhall-lang/dhall-haskell/pull/2089)+* Fixes and improvements to the pretty printer:+ * [#2083](https://github.com/dhall-lang/dhall-haskell/pull/2083)+ * [#2101](https://github.com/dhall-lang/dhall-haskell/pull/2101)++1.36.0++* [Supports version 19.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v19.0.0)+ * BREAKING CHANGE TO THE API: [Add `Text/replace` built-in](https://github.com/dhall-lang/dhall-haskell/pull/2063)+ * [Implement `with` without syntactic sugar](https://github.com/dhall-lang/dhall-haskell/pull/2055)+* [`dhall lint` will now add a `.dhall` extension to all Prelude imports](https://github.com/dhall-lang/dhall-haskell/pull/2061)+ * The old extension-free Prelude imports are deprecated+* [Fix command-line completions for files](https://github.com/dhall-lang/dhall-haskell/pull/2016)+* [Improve Template Haskell support for record constructors](https://github.com/dhall-lang/dhall-haskell/pull/2070)+* Fixes and improvements to code formatting+ * [#2037](https://github.com/dhall-lang/dhall-haskell/pull/2037)+ * [#2048](https://github.com/dhall-lang/dhall-haskell/pull/2048)+ * [#2069](https://github.com/dhall-lang/dhall-haskell/pull/2069)++1.35.0++* [Supports version 18.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v18.0.0)+ * [Implement more efficient `with` desugaring](https://github.com/dhall-lang/dhall-haskell/pull/1993)+ * Chained `with` expressions will now be much more efficient+* [BREAKING CHANGE TO THE API: Preserve whitespace for `Lam` constructor](https://github.com/dhall-lang/dhall-haskell/pull/1980)+ * This change extends the `Lam` constructor to preserve whitespace around+ the variable binding+ * The motivation for this change is to enable `dhall-docs` to support+ jumping to definitions+ * You can replace your existing `Lam` constructors with+ `Dhall.Core.makeFunctionBinding`+* [BREAKING CHANGE TO THE API: Preserve whitespace for `Field` constructors](https://github.com/dhall-lang/dhall-haskell/pull/1991)+ * This change extends the `Field` constructor to preserve whitespace around+ the selected field+ * The motivation for this change is to enable `dhall-docs` to support+ jumping to definitions+ * You can use `Dhall.Core.makeFieldSelection` and+ `Dhall.Core.fieldSelectionLabel` to convert between the detailed and the+ simple representation of the selected field.+* [Add `FromDhall` instances for `{Int,Word}{,8,16,32,64}`](https://github.com/dhall-lang/dhall-haskell/pull/2012)+* [Add `--output` option for `dhall text` subcommand](https://github.com/dhall-lang/dhall-haskell/pull/1974)+* [Add `Dhall.Crypto.toString`](https://github.com/dhall-lang/dhall-haskell/pull/1976)+* [Make the HTTP `Manager` configurable](https://github.com/dhall-lang/dhall-haskell/pull/2027)+ * Several import-related functions now provide an alternative variants that+ allows the user to supply a custom `Manager`+ * You can use this to tweak HTTP request timeouts or use a different TLS+ manager (e.g. one from `http-client-openssl`)+* Fixes and improvements to code formatting+ * [#2000](https://github.com/dhall-lang/dhall-haskell/pull/2000)+ * [#2021](https://github.com/dhall-lang/dhall-haskell/pull/2021)++ The formatter now preserves comments for record fields (both record types+ and record literals)+* Fixes and improvements to documentation+ * [#2011](https://github.com/dhall-lang/dhall-haskell/pull/2011)+ * [#2013](https://github.com/dhall-lang/dhall-haskell/pull/2013)+ * [#2014](https://github.com/dhall-lang/dhall-haskell/pull/2014)+* Fixes and improvements to test suite+ * [#2020](https://github.com/dhall-lang/dhall-haskell/pull/2020)++1.34.0++* [Supports version 17.1.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v17.1.0)+ * [Add support for trailing commas](https://github.com/dhall-lang/dhall-haskell/pull/1885)+* BREAKING CHANGE to the API: [Support prefix comments on record key-value pairs](https://github.com/dhall-lang/dhall-haskell/pull/1908)+ * The Dhall AST (i.e. `Expr`) now preserves some comments for record types+ and record literals+ * The impact of this change is that you will need to add+ `Dhall.Syntax.makeRecordField` or `Dhall.Syntax.recordFieldValue` in a few+ places wherever your Haskell assembles or disassembles record expressions+ * The motivation of this change is two-fold:+ * To eventually enable `dhall-docs` support for rendering record+ comments as documentation+ * To eventually enable support for preserving record-related comments+ when formatting Dhall code+* BUG FIX: [Fix `with` expressions to permit functions on their left-hand side](https://github.com/dhall-lang/dhall-haskell/pull/1897)+ * This was a case of the Haskell implementation not being compliant with the+ standard grammar+* [Drop support for GHC 8.2](https://github.com/dhall-lang/dhall-haskell/pull/1949)+* [Add a new `dhall rewrite-with-schemas` command](https://github.com/dhall-lang/dhall-haskell/pull/1902)+ * You can now simplify a Dhall expression using a schema record (e.g. a+ `./schemas.dhall` record that a package might provide)+ * This simplification replaces large anonymous records with an+ equivalent use of a record completion when possible+* [Add `--transitive` flag to `dhall {format,lint,freeze}](https://github.com/dhall-lang/dhall-haskell/pull/1880)+ * This flag lets you format/lint/freeze a file and all of its transitive+ dependencies that are reachable via relative file imports+* [Move `man/dhall.1` to `data-files`](https://github.com/dhall-lang/dhall-haskell/pull/1921)+ * This ensures that Cabal will install `dhall`'s `man` pages in the+ correct directory+* Performance improvements+ * [#1879](https://github.com/dhall-lang/dhall-haskell/pull/1879)+* Standards compliance+ * [#1953](https://github.com/dhall-lang/dhall-haskell/pull/1953)+ * [#1954](https://github.com/dhall-lang/dhall-haskell/pull/1954)+ * [#1956](https://github.com/dhall-lang/dhall-haskell/pull/1956)+ * [#1957](https://github.com/dhall-lang/dhall-haskell/pull/1957)+ * [#1958](https://github.com/dhall-lang/dhall-haskell/pull/1958)+* Fixes and improvements to haddocks+ * [#1881](https://github.com/dhall-lang/dhall-haskell/pull/1881)+ * [#1955](https://github.com/dhall-lang/dhall-haskell/pull/1955)++1.33.1++* [Multi-line REPL / support `repline-0.4.0.0`](https://github.com/dhall-lang/dhall-haskell/pull/1867)+ * `dhall repl` supports a new `:paste` command that lets you input a command+ by pasting one or more lines++1.33.0++* [Supports version 17.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v17.0.0)+ * BREAKING CHANGE: [URLs no longer support quoted path components](https://github.com/dhall-lang/dhall-haskell/pull/1812)+ * BREAKING CHANGE: [`Optional/{fold,build}` are no longer built-ins](https://github.com/dhall-lang/dhall-haskell/pull/1802)+ * [Record fields now permit empty labels](https://github.com/dhall-lang/dhall-haskell/pull/1812)+* BREAKING CHANGE: [Fail instead of hanging when deriving `FromDhall` for recursive types](https://github.com/dhall-lang/dhall-haskell/pull/1825)+ * This is a breaking change as now the `expected` type returns an+ `Expector (Expr Src Void)` (essentially an `Either`) instead of+ `Expr Src Void`+ * If you really don't want to handle the new error-related wrapper, you can+ get the old behavior using a partial pattern match (which will be partial,+ still an improvement over the previous behavior, which was hanging)+* BREAKING CHANGE: [Records can no longer contain attributes named after language keywords](https://github.com/dhall-lang/dhall-haskell/pull/1801)+ * This is a bugfix, because the language standard disallows using+ keywords as record labels. However, some users were relying on+ this bug.+ * If you need to use a keyword as a record label, enclose it in backticks:+ ``{ `assert` = 1 }``.+* [Fix invalid cache entries](https://github.com/dhall-lang/dhall-haskell/pull/1793)+ * The interpreter will now correct cached expressions that are incorrect+ and warn you when this happens+ * Specifically, if there is a hash mismatch from the cached expression the+ interpreter will resolve the import again and fix the cache if the+ resolved import matches the expected hash+* [Make `encodeExpression` polymorphic](https://github.com/dhall-lang/dhall-haskell/pull/1789)+ * `encodeExpression` now has a more general type, which means that you+ can use it to serialise expressions without imports (i.e.+ ones of type `Expr Void Void`)+* [Add `--quiet` option for `dhall decode`](https://github.com/dhall-lang/dhall-haskell/pull/1803)+* [Add `--noted` flag for `dhall haskell-syntax-tree`](https://github.com/dhall-lang/dhall-haskell/pull/1843)+* Performance improvements:+ * There were several performance improvements related to binary decoding,+ which should improve cache lookup speed+ * [#1807](https://github.com/dhall-lang/dhall-haskell/pull/1807)+ * [#1809](https://github.com/dhall-lang/dhall-haskell/pull/1809)+ * [#1857](https://github.com/dhall-lang/dhall-haskell/pull/1857)+* Improvements to error messages+ * [#1824](https://github.com/dhall-lang/dhall-haskell/pull/1824)+ * [#1849](https://github.com/dhall-lang/dhall-haskell/pull/1849)+ * [#1851](https://github.com/dhall-lang/dhall-haskell/pull/1851)+* Fixes to haddocks+ * [#1815](https://github.com/dhall-lang/dhall-haskell/pull/1815)++1.32.0++* [Supports version 16.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v16.0.0)+ * BREAKING CHANGE: Change the precedence of `with` and `===`+ * The precedence change to `with` means that some old expressions that+ were valid now require explicit parentheses+ * BREAKING CHANGE: Use RFC7049bis encoding for `Double`s+ * This is a breaking change because the hashes of expressions with small+ `Double` literals will change now+ * Add support for unions mixing terms and types+ * For example, `< A : Bool | B : Type >` is legal now+ * You can now write `someRecord with a.b.c = x` to update a nested+ fields+* DEPRECATION: [Deprecate `Dhall.Parser.exprA`](https://github.com/dhall-lang/dhall-haskell/pull/1740)+ * `Dhall.Parser` module will eventually drop support for parsing custom+ import types+ * This is necessary in order to fix several parsing bugs and improve+ parsing error messages+* BUG FIX: [GHC Generics instance for `:+:` now uses `union`](https://github.com/dhall-lang/dhall-haskell/pull/1725)+ * This fixes a few subtle bugs in how Dhall unions are marshalled into+ Haskell types, and also improves the error messages+* Formatting improvements+ * [Change formatting of `if` expressions](https://github.com/dhall-lang/dhall-haskell/pull/1767)+ * [Change formatting for functions and their types](https://github.com/dhall-lang/dhall-haskell/pull/1759)+ * [Prefer puns when formatting record completions](https://github.com/dhall-lang/dhall-haskell/pull/1736)+* [Convert union alternatives to directory tree](https://github.com/dhall-lang/dhall-haskell/pull/1757)+ * `dhall to-directory-tree` now supports unions which are automatically+ unwrapped+* [Fix `dhall freeze --cache` to better handle protected imports](https://github.com/dhall-lang/dhall-haskell/pull/1772)+ * `dhall freeze --cache` will now also update imports that already have+ integrity checks+* [Don't normalized partially saturated `{List,Natural}/fold`](https://github.com/dhall-lang/dhall-haskell/pull/1742)+ * The behavior now matches the standard. Previously, the Haskell+ implementation was not standards-compliant because it would normalize+ these partially saturated built-ins++1.31.1++* BUG FIX: [Allow whitespace after record pun entry](https://github.com/dhall-lang/dhall-haskell/pull/1733)+ * The record pun feature introduced in the previous release did not+ correctly parse record puns with trailing whitespace, which this change+ fixes.+* [Expose `{default,}InputNormalizer`](https://github.com/dhall-lang/dhall-haskell/pull/1727)+ * The previous version introduced a breaking change to the `autoWith` type+ that required access to the implementation of `InputNormalizer`, which was+ not exported. This change fixes that.+* Build against latest dependencies+ * [`QuickCheck-2.14`](https://github.com/dhall-lang/dhall-haskell/pull/1721)+ * [`haskell-lsp-0.21`](https://github.com/dhall-lang/dhall-haskell/pull/1730)+ * [`repline-0.3` / `haskeline-0.8`](https://github.com/dhall-lang/dhall-haskell/pull/1717)+ * [`template-haskell-2.16`](https://github.com/dhall-lang/dhall-haskell/pull/1719)+* [Prefer to format using record puns when possible](https://github.com/dhall-lang/dhall-haskell/pull/1729)+ * `dhall format` will now reformat code to use record puns when applicable+* Fixes and improvements to error messages:+ * [#1721](https://github.com/dhall-lang/dhall-haskell/pull/1724)++1.31.0++* [Supports version 15.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v15.0.0)+ * [Implement `with` keyword](https://github.com/dhall-lang/dhall-haskell/pull/1685)+ * You can now write `someRecord with a.b.c = x` to update a nested+ fields+ * [Add support for record puns](https://github.com/dhall-lang/dhall-haskell/pull/1710)+ * You can now write `{ x, y }` as a shorthand for `{ x = x, y = y }`+* BREAKING CHANGE TO THE API: [Auto-derive `Generic`/`FromDhall`/`ToDhall` with Template Haskell](https://github.com/dhall-lang/dhall-haskell/pull/1682)+ * Now the `Dhall.TH.makeHaskell*` utilities will include these derived+ instances in the generated declarations+ * This is a breaking change since users were likely already generating these+ instances separately, which will now conflict with the included instances+* BREAKING CHANGE TO THE API: [`From/ToDhall` no longer takes `InterpretOptions` argument](https://github.com/dhall-lang/dhall-haskell/pull/1696)+ * The types of the `autoWith` and `injectWith` methods have changed to+ take an `InputNormalizer` instead of an `InterpretOptions`+ * Note that `InputNormalizer` is a subset of `InterpretOptions`+ * This is a breaking change to how derived `FromDhall` / `ToDhall` instances+ are customized to more closely match how other Haskell packages customize+ derived instances (e.g. `aeson` with `FromJSON` / `ToJSON`)+ * Previously you would customize the behavior globally by passing in+ a top-level `InterpretOptions` record to `autoWith`+ * Now you can customize the behavior locally on a per-instance basis+ * This change enables the following change ...+* [Add `Dhall.Deriving` module for `deriving-via` helpers](https://github.com/dhall-lang/dhall-haskell/pull/1700)+ * Now you can take advantage of the `-XDerivingVia` language extension to+ customize derived `FromDhall`/`ToDhall` instances, like this:+ * `deriving (FromDhall, ToDhall) via Codec (SetSingletonConstructors Bare) Name`+* BREAKING CHANGE TO THE LANGUAGE: [Match standard with respect to `using toMap`](https://github.com/dhall-lang/dhall-haskell/pull/1673)+ * `https://example.com using toMap customHeaders` is now a parse error+ and needs to be explicitly parenthesized as+ `https://example.com using (toMap customHeaders)`+ * The language standard had always required the parentheses, but the Haskell+ implementation was not correctly matching the standard+* [Fix formatting of indented comments containing empty lines](https://github.com/dhall-lang/dhall-haskell/pull/1688)+ * `dhall format` was previously not idempotent when formatting indented+ comments with empty lines+ * Specifically, the formatter kept indenting things further with each+ format, which this change fixes+* [Fix pretty-printer to preserve original numeric literals](https://github.com/dhall-lang/dhall-haskell/pull/1674)+ * Now `dhall format` will preserve numeric literals exactly how you wrote+ them+ * For example, `0xFF` will no longer be reformatted as `255`+* [Add `dhall to-directory-tree` support for `Map`s](https://github.com/dhall-lang/dhall-haskell/pull/1705)+ * `Map`s are now converted to directories (just like records)+* [Add manpage](https://github.com/dhall-lang/dhall-haskell/pull/1677)+ * ... mainly for the benefit of people packaging Dhall for various+ distributions+* [Group commands in CLI](https://github.com/dhall-lang/dhall-haskell/pull/1692)+ * The command-line `--help` output now groups commands into useful+ sections+* [Fix numeric parsing for GHCJS](https://github.com/dhall-lang/dhall-haskell/pull/1681)+ * The GHCJS backend for Dhall was failing to parse numbers, which this+ change fixes+* Fixes and improvements to error messages:+ * [#1656](https://github.com/dhall-lang/dhall-haskell/pull/1656)+ * [#1698](https://github.com/dhall-lang/dhall-haskell/pull/1698)+ * [#1702](https://github.com/dhall-lang/dhall-haskell/pull/1702)+* Fixes and improvements to the haddocks:+ * [#1708](https://github.com/dhall-lang/dhall-haskell/pull/1708)+ * [#1712](https://github.com/dhall-lang/dhall-haskell/pull/1712)++1.30.0++* [Supports version 14.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0)+* BREAKING CHANGE TO THE API: [Add `--check` flag to `dhall {lint,freeze}`](https://github.com/dhall-lang/dhall-haskell/pull/1636)+ * You can now use the `--check` flag to verify that a file has already been+ linted or frozen+ * This is a breaking change to the types used by the `Dhall.Format` module+* BREAKING CHANGE TO THE LANGUAGE: [Disallow `Natural` literals with leading zeros](https://github.com/dhall-lang/dhall-haskell/pull/1658)+ * Now a literal like `042` is no longer valid+ * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* BUG FIX: [Fix parsing of `Double` literal trailing whitespace](https://github.com/dhall-lang/dhall-haskell/pull/1647)+ * Certain expressions using `Double` literals would fail to parse, which this+ change fixes+* BUG FIX: [Use `DeriveLift` instead of GHC Generics to derive `Lift` ](https://github.com/dhall-lang/dhall-haskell/pull/1640)+ * This fixes a build failure on GHC 8.10+* [Drop support for GHC 7.10.3](https://github.com/dhall-lang/dhall-haskell/pull/1649)+ * GHC 8.0.2 is now the earliest supported version+* [Add support for dotted field syntax](https://github.com/dhall-lang/dhall-haskell/pull/1651)+ * `{ x.y.z = 1 }` now legal syntax for nested fields+ * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* [Add support for duplicate record fields](https://github.com/dhall-lang/dhall-haskell/pull/1643)+ * This combines with the previous feature to let you write+ `{ x.y = 1, x.z = True }`, which is equivalent to+ `{ x = { y = 1, z = True } }`+ * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* [Add `dhall lint` support for deprecating `Optional/{fold,build}`](https://github.com/dhall-lang/dhall-haskell/pull/1628)+ * The `Optional/{fold,build}` built-ins are deprecated and can be implemented+ in terms of other language features+ * `Optional/fold` can be implemented in terms of `merge` (which now works on+ `Optional` values)+ * `Optional/build` could always be implemented using `Some`/`None`+ * `dhall lint` now transforms the deprecated built-ins to use their+ equivalent built-in-free versions+* [Support Template Haskell for multiple datatypes](https://github.com/dhall-lang/dhall-haskell/pull/1664)+ * This extends the Template Haskell support added in the previous release to+ work for datatypes that refer to one another+* [Add support for custom substitutions](https://github.com/dhall-lang/dhall-haskell/pull/1650)+ * You can now add custom substitutions, which are like `let` bindings that+ propagate to transitive imports+* [Small formatting fixes](https://github.com/dhall-lang/dhall-haskell/pull/1652)++1.29.0++* [Supports version 13.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v13.0.0)+* BREAKING CHANGE: [Generate Haskell datatype declarations from Dhall types](https://github.com/dhall-lang/dhall-haskell/commit/b0280826790930d18a5498fb802120478fa11767#diff-a9729dccf50be61ce3d8c68c16f0fd50)+ * You can now use the `makeHaskellTypeFromUnion` Template Haskell utility+ to generate a Haskell datatype declaration from a Dhall union type+ * This helps ensure that your Haskell types and Dhall types stay in sync,+ when you want the Dhall type to be the source of truth+ * This is a breaking change because the default `InterpretOptions` changed+ the default handling of singleton constructors from `Wrapped` to `Smart`+ * You can preserve the old behavior using:+ `autoWith defaultInterpretOptions{ singletonConstructors = Wrapped }`+* BUG FIX: [Fix `dhall freeze --cache` and `dhall lint` to preserve `let`-related comments](https://github.com/dhall-lang/dhall-haskell/pull/1597)+ * Now they match the behavior of `dhall format` with regard to preserving+ these comments+* BUG FIX: [Fix escaping of significant leading whitespace when formatting code](https://github.com/dhall-lang/dhall-haskell/pull/1598)+ * The formatter would sometimes unnecessarily escape significant leading+ whitespace for the final line of multiline string literals, which this+ change fixes+* BUG FIX: [Fix `dhall encode --json` for `Double` values](https://github.com/dhall-lang/dhall-haskell/issues/1350)+* NEW FEATURE: [`dhall to-directory-tree` command](https://github.com/dhall-lang/dhall-haskell/pull/1606)+ * You can now generate a directory tree from a Dhall expression+ * Specifically:+ * records are converted to directories+ * `Text` fields are converted to files named after the field+ * `Optional` values are omitted if `None`+ * Everything else is rejected+* NEW FEATURE: [Hexadecimal literals](https://github.com/dhall-lang/dhall-haskell/pull/1607)+ * See the [changelog for standard version 13.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v13.0.0) for more details+* NEW FEATURE: [`merge` works on `Optional` values](https://github.com/dhall-lang/dhall-haskell/pull/1608)+ * See the [changelog for standard version 13.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v13.0.0) for more details+* [Improve formatter](https://github.com/dhall-lang/dhall-haskell/pull/1609)+ * `dhall format` will now render expressions nested inside record fields or+ alternatives more compactly, including:+ * Records+ * Record completion expressions+ * Expressions wrapped in `Some`+ * Lists+* [Exclude the `using ...` suffix from imports listed by `dhall resolve`](https://github.com/dhall-lang/dhall-haskell/pull/1603)+ * Specifically when using the `--{immediate,transitive}-dependencies` flags++1.28.0++* [Supports version 12.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v12.0.0)+* BREAKING CHANGE: [Add `Integer/{clamp,negate}` built-ins](https://github.com/dhall-lang/dhall-haskell/pull/1486)+ * This is a technically breaking change API since this adds a new+ constructor to the `Expr` type+ * This is also a technically breaking change to the language. See the [changelog for standard version 12.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v12.0.0) for more details+* BREAKING CHANGE: [Remove support for fusion](https://github.com/dhall-lang/dhall-haskell/pull/1478)+ * This is also a technically breaking change to the language. See the [changelog for standard version 12.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v12.0.0) for more details+* BREAKING CHANGE: [Parse whitespace more precisely](https://github.com/dhall-lang/dhall-haskell/pull/1483)+ * The Haskell implementation now matches the official grammar much more+ closely, but as a result will now reject some programs that it used to+ accept+ * For example, `1:Natural` used to be valid and now is no longer valid as+ the standard requires mandatory whitespace after the `:`+ * Consult the [standard grammar](https://github.com/dhall-lang/dhall-lang/blob/master/standard/dhall.abnf) if you run into a new parsing error as a result of this change+ * This is also a parsing performance regression (specifically for parsing+ comments), but should not be noticeable in practice. See [#1512](https://github.com/dhall-lang/dhall-haskell/pull/1512) for more details+* BREAKING CHANGE: Rename `Type` to `Decoder` and `InputType` to `Encoder` [#1483](https://github.com/dhall-lang/dhall-haskell/pull/1485) / [#1489](https://github.com/dhall-lang/dhall-haskell/pull/1489)+* BUG FIX: [Fix `dhall format --check`](https://github.com/dhall-lang/dhall-haskell/pull/1462)+ * Before this change `dhall format --check` would fail due to attempting to+ read all of standard input in twice+* BUG FIX: [Fix `dhall freeze` to always re-freeze an import](https://github.com/dhall-lang/dhall-haskell/pull/1471)+ * Before this fix, `dhall freeze` would not attempt to refreeze an already+ frozen import+* [Permit spaces around completion operator](https://github.com/dhall-lang/dhall-haskell/pull/1532)+ * See the [changelog for standard version 12.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v12.0.0) for more details+* [Make `missing` referentially transparent](https://github.com/dhall-lang/dhall-haskell/pull/1509)+ * `missing` can now be imported transitively via a remote import+ * Normally resolving `missing` would still still fail, except for+ `missing as Location`, which is now a valid transitive import+ * See the [changelog for standard version 12.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v12.0.0) for more details+* [Write cache files atomically](https://github.com/dhall-lang/dhall-haskell/pull/1544)+ * This is a resilience improvement so that the cache is not left in a+ corrupt state in the event of a power outage or exhausting disk/memory+* [New `Dhall.function` utility](https://github.com/dhall-lang/dhall-haskell/pull/1507)+ * This is provides the same functionality as the `Interpret` instance for+ `(->)`, except without the use of typeclasses+* [New `dhall haskell-syntax-tree` command](https://github.com/dhall-lang/dhall-haskell/pull/1553)+ * This command displays the Haskell syntax tree of an expression+ (primarily for debugging purposes)+ * Note that this is highly-volatile and subject to change, so don't depend+ on this programmatically. We may break the output of this command without+ any notice.+* [Add `instance Show Ann`](https://github.com/dhall-lang/dhall-haskell/pull/1567)+* [Move normalization code from `Dhall.Core` to `Dhall.Normalize`](https://github.com/dhall-lang/dhall-haskell/pull/1452)+ * Note that this is not a breaking change. The relocated utilities are+ still re-exported from `Dhall.Core`+* [Fix `dhall resolve --transitive-dependencies` to list dependencies in "post-order"](https://github.com/dhall-lang/dhall-haskell/pull/1539)+* Performance improvements+ * [#1500](https://github.com/dhall-lang/dhall-haskell/pull/1500)+ * [#1522](https://github.com/dhall-lang/dhall-haskell/pull/1522)+ * [#1568](https://github.com/dhall-lang/dhall-haskell/pull/1568)+ * [#1580](https://github.com/dhall-lang/dhall-haskell/pull/1578)+* Fixes and improvements to code formatting+ * [#1460](https://github.com/dhall-lang/dhall-haskell/pull/1460)+ * [#1466](https://github.com/dhall-lang/dhall-haskell/pull/1466)+ * [#1508](https://github.com/dhall-lang/dhall-haskell/pull/1508)+ * [#1527](https://github.com/dhall-lang/dhall-haskell/pull/1527)+ * [#1422](https://github.com/dhall-lang/dhall-haskell/pull/1422)+ * [#1552](https://github.com/dhall-lang/dhall-haskell/pull/1552)+ * [#1543](https://github.com/dhall-lang/dhall-haskell/pull/1543)+ * [#1554](https://github.com/dhall-lang/dhall-haskell/pull/1554)+ * [#1569](https://github.com/dhall-lang/dhall-haskell/pull/1569)+* Fixes and improvements to code linting+ * [#1518](https://github.com/dhall-lang/dhall-haskell/pull/1518)+ * [#1531](https://github.com/dhall-lang/dhall-haskell/pull/1531)+* Fixes and improvements to error messages+ * [#1443](https://github.com/dhall-lang/dhall-haskell/pull/1443)+ * [#1448](https://github.com/dhall-lang/dhall-haskell/pull/1448)+ * [#1482](https://github.com/dhall-lang/dhall-haskell/pull/1482)+ * [#1519](https://github.com/dhall-lang/dhall-haskell/pull/1519)+ * [#1556](https://github.com/dhall-lang/dhall-haskell/pull/1556)+ * [#1528](https://github.com/dhall-lang/dhall-haskell/pull/1528)+* Fixes and improvements to the parser+ * [#1473](https://github.com/dhall-lang/dhall-haskell/pull/1473)+ * [#1549](https://github.com/dhall-lang/dhall-haskell/pull/1549)+ * [#1563](https://github.com/dhall-lang/dhall-haskell/pull/1563)+ * [#1584](https://github.com/dhall-lang/dhall-haskell/pull/1584)+* Fixes and improvements to diffs+ * [#1585](https://github.com/dhall-lang/dhall-haskell/pull/1585)+* Fixes and improvements to the REPL+ * [#1573](https://github.com/dhall-lang/dhall-haskell/pull/1573)+* Fixes and improvements to documentation+ * [#1530](https://github.com/dhall-lang/dhall-haskell/pull/1530)++1.27.0++* [Supports version 11.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v11.0.0)+* BREAKING CHANGE: Rename `Inject`/`Interpret` to `ToDhall`/`FromDhall`+ * This change `ConstraintKinds` to minimize disruption by keeping around+ `Inject`/`Interpret` as synonyms for `ToDhall`/`FromDhall`+ * In other words, constraints and derived instances using `Inject` or+ `Interpret` will still work+ * However, manual instances using `Inject` or `Interpret` won't work+ unless you rename them to `ToDhall`/`FromDhall` or enable the+ `TypeSynonymInstances` extension+* BREAKING CHANGE: Fix `Eq` instance for `Expr`s with special `Double`s+ * This fixes the `Eq` instance for `Expr`s to match the standard regarding+ `Double` comparisons+ * Specifically: `NaN == NaN` and `-0.0 /= 0.0`+ * This is a breaking change because the `DoubleLit` constructor of `Expr`+ now stores a `DhallDouble` instead of a `Double`+* BREAKING CHANGE: [Add `--file` option for `dhall hash`](https://github.com/dhall-lang/dhall-haskell/pull/1445)+ * This is a breaking change because it also removes the `Dhall.Hash` module,+ which wasn't really carrying its own weight+* [Add support for leading separators](https://github.com/dhall-lang/dhall-haskell/pull/1355)+ * See the [changelog for standard version 11.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v11.0.0) for more details+* [Add record completion operator](https://github.com/dhall-lang/dhall-haskell/pull/1375)+ * See the [changelog for standard version 11.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v11.0.0) for more details+* [Add `dhall tags` subcommand](https://github.com/dhall-lang/dhall-haskell/pull/1398)+ * This generates an ETags file from an input file or directory+* [Add `dhall lint` support for fixing malformed assertions](https://github.com/dhall-lang/dhall-haskell/pull/1353)+ * `dhall lint` now fixes `let example = foo === bar` to be+ `let example = assert : foo === bar`+* Normalize inferred types [#1337](https://github.com/dhall-lang/dhall-haskell/pull/1337)+* New `FromDhall`/`ToDhall` (previously `Interpret`/`Inject`) instances for:+ * [`Void`](https://github.com/dhall-lang/dhall-haskell/pull/1382)+ * `Map` [#1391](https://github.com/dhall-lang/dhall-haskell/pull/1391) / [#1412](https://github.com/dhall-lang/dhall-haskell/pull/1412)+ * [`HashMap`](https://github.com/dhall-lang/dhall-haskell/pull/1426)+ * [`Set` and `HashSet`](https://github.com/dhall-lang/dhall-haskell/pull/1405)+ * [`()`](https://github.com/dhall-lang/dhall-haskell/pull/1388)+* [Add `--output` option to `dhall`](https://github.com/dhall-lang/dhall-haskell/pull/1399)+* [Move syntax things from `Dhall.Core` to a new `Dhall.Syntax` module](https://github.com/dhall-lang/dhall-haskell/pull/1440)+ * This is not a breaking change. `Dhall.Core` still re-exports the same+ API as before+* Performance improvements+ * [#1362](https://github.com/dhall-lang/dhall-haskell/pull/1362)+ * [#1366](https://github.com/dhall-lang/dhall-haskell/pull/1366)+ * [#1368](https://github.com/dhall-lang/dhall-haskell/pull/1368)+ * [#1397](https://github.com/dhall-lang/dhall-haskell/pull/1397)+ * [#1401](https://github.com/dhall-lang/dhall-haskell/pull/1401)+* Fixes and improvements to code formatting+ * [#1360](https://github.com/dhall-lang/dhall-haskell/pull/1360)+ * [#1372](https://github.com/dhall-lang/dhall-haskell/pull/1372)+ * [#1380](https://github.com/dhall-lang/dhall-haskell/pull/1380)+ * [#1415](https://github.com/dhall-lang/dhall-haskell/pull/1415)++1.26.1++* TECHNICALLY BREAKING CHANGES: [Simplify `⫽` within projection](https://github.com/dhall-lang/dhall-haskell/pull/1283) / [Simplify nested record projections](https://github.com/dhall-lang/dhall-haskell/pull/1307)+ * These are technically breaking changes because you will need to update+ integrity checks that protect code simplified in this way+ * We're not bumping the major version since the likelihood that you're+ affected is quite low+* BUG FIX: [Fix performance regression](https://github.com/dhall-lang/dhall-haskell/pull/1335)+ * This change fixes the performance regression introduced in the previous+ release (version 1.26.0)+* BUG FIX: [Prevent REPL from inserting inferred `Sort`s into context](https://github.com/dhall-lang/dhall-haskell/pull/1318)+ * This protects the REPL from getting hosed if you define an expression+ using `:let` that has an inferred type of `Sort`+* NEW FEATURE: Improved `Inject`/`Interpret` support for 1-field constructors - ([#1315](https://github.com/dhall-lang/dhall-haskell/pull/1315) / [#1321](https://github.com/dhall-lang/dhall-haskell/pull/1321))+ * This adds a new `singletonConstructors` field to `InterpretOptions` that+ lets you control what Dhall type 1-field Haskell constructors correspond+ to+ * The default (`Wrapped`) is backwards compatible with the old behavior+ * The `Smart` option is probably what you want: it will strip the+ Haskell constructor from the Dhall type if the constructor has one+ anonymous field+ * The `Bare` option always strips 1-field Haskell constructors from the+ Dhall type+* NEW FEATURE: `--censor` flag that disables source code display ([#1312](https://github.com/dhall-lang/dhall-haskell/pull/1312) / [#1329](https://github.com/dhall-lang/dhall-haskell/pull/1329))+ * Use this flag when you don't want sensitive `Text` literals showing up in+ parsing or type-checking error messages+* [Format record fields more compactly if they fit on 1 line](https://github.com/dhall-lang/dhall-haskell/pull/1314)+ * The formatter will now format record fields on a field-by-field basis to+ avoid unnecessary vertical sprawl of formatted records+ * Specifically, record fields that fit on one line will now be formatted+ on one line+* [Add `--quiet` option to `dhall type`](https://github.com/dhall-lang/dhall-haskell/pull/1325)+ * This lets you use `dhall type` in "check only" mode (e.g. for CI for+ for development feedback)+* Improved GHCJS support - ([#1311](https://github.com/dhall-lang/dhall-haskell/pull/1311) / [#1330](https://github.com/dhall-lang/dhall-haskell/pull/1330))+* [Fix all executables to accept `--version`](https://github.com/dhall-lang/dhall-haskell/pull/1334)+ * Note that the `dhall version` subcommand is still supported, too+* [New `Dhall.Version` module](https://github.com/dhall-lang/dhall-haskell/pull/1332)+* [Don't normalize inferred types](https://github.com/dhall-lang/dhall-haskell/pull/1317)+ * This fixes `dhall type` to more accurately follow the standard+* [Initial changes for GHC 8.8 support](https://github.com/dhall-lang/dhall-haskell/pull/1324)+* [Fix Haddock formatting for `dhallFromJSON`](https://github.com/dhall-lang/dhall-haskell/pull/1316)+* [Improved Windows caching support](https://github.com/dhall-lang/dhall-haskell/pull/1272)+ * `dhall` will now prefer the `%LOCALAPPDATA%` directory for caching if it is+ available+* [Warn about missing cache directories](https://github.com/dhall-lang/dhall-haskell/pull/1320)++1.26.0++* [Supports version 10.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0)+* BREAKING CHANGE TO THE LANGUAGE: [Remove old union literal syntax](https://github.com/dhall-lang/dhall-haskell/pull/1176)+ * Union literals of the form `< x = e | ... >` are no longer valid+ * For more details, see: [Migration: Deprecation of old union literal syntax](https://github.com/dhall-lang/dhall-lang/wiki/Migration%3A-Deprecation-of-old-union-literal-syntax)+ * Also see the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* BREAKING CHANGE TO THE API: [Change `X` to be a type synonym for `Data.Void`](https://github.com/dhall-lang/dhall-haskell/pull/1172)+ * This is a breaking change if you were previously pattern matching on the+ `X` constructor. You can replace that with the use of `Data.Void.absurd`+* BREAKING CHANGE TO THE API: [Treat multi-`let`s as syntactic sugar](https://github.com/dhall-lang/dhall-haskell/pull/1242)+ * This is a breaking change because the `Let` constructor now only stores+ one `Binding` instead of a `NonEmpty` list of `Binding`s+* PERFORMANCE REGRESSION & TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Dependent types](https://github.com/dhall-lang/dhall-haskell/pull/1164)+ * You can now write functions from terms to types+ * There is also now language support for tests of the form+ `assert : x === y`+ * This deteriorates the performance of large multi-`let` expressions+ (See: [#1306](https://github.com/dhall-lang/dhall-haskell/issues/1306))+ * Splitting large multi-`let` expressions into smaller files may mitigate+ the problem as a work-around for now+ * Follow [#1129](https://github.com/dhall-lang/dhall-haskell/issues/1129)+ for work to fix this performance regression+ * This is also a technically breaking change because `assert` is now a+ reserved keyword+ * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Add `Natural/subtract` built-in](https://github.com/dhall-lang/dhall-haskell/pull/1133)+ * The language now supports machine subtraction, which can be used to+ support several other high-performance operations (like `Natural`+ comparisons)+ * This is a technically breaking change if you used `Natural/subtract` as an+ identifier in your code+ * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [More simplifications for field selection](https://github.com/dhall-lang/dhall-haskell/pull/1174)+ * Now the interpreter will more intelligently simplify certain field+ projections+ * For example: `λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).{ a, c }.c`+ will now simplify to `λ(x : { a : Bool, b : Bool }) → 0 `+ * This is a technically breaking change because you will need to update+ integrity checks that protect code simplified in this way+ * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* TECHNICALLY BREAKING CHANGE TO THE LANGUAGE: [Simplify `⫽` when its arguments are equivalent](https://github.com/dhall-lang/dhall-haskell/pull/1196)+ * This is a technically breaking change for the same reason: this will+ perturb semantic integrity checks for affected code+ * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* NEW FEATURE: [Restore support for records containing both types and terms](https://github.com/dhall-lang/dhall-haskell/pull/1173)+ * In other words `{ foo = 1, bar = Bool }` is now valid again+ * This means that you now can export a single package containing both types+ and terms+ * See the [changelog for standard version 10.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v10.0.0) for more details+* [`dhall format` now preserves `let` comments](https://github.com/dhall-lang/dhall-haskell/pull/1273)+ * `dhall` format will now preserve comments in the following locations of+ a `let` binding:+ * `let {- HERE -} x {- HERE -} : {- HERE -} Bool = {- HERE -} True in x`+ * This support handles both single-line and multi-line comments and also+ takes care of correctly indenting/dedenting them+ * Note that comments before the `let` keyword are still not preserved+ (unless it is the beginning of the file)+* [Add API support for marshalling recursive types](https://github.com/dhall-lang/dhall-haskell/pull/1195)+ * You can now marshal recursive types from Dhall into Haskell using the+ newly-added utilities+ * See also: [#1298](https://github.com/dhall-lang/dhall-haskell/pull/1298)+* [New `:help` command for `dhall repl`](https://github.com/dhall-lang/dhall-haskell/pull/1237)+* New `--no-cache` flag [#1290](https://github.com/dhall-lang/dhall-haskell/pull/1290) / [#1434](https://github.com/dhall-lang/dhall-haskell/pull/1434) / [#1436](https://github.com/dhall-lang/dhall-haskell/pull/1436)+ * You can now disable use of the cache with this flag+ * This comes in handy if you want to disable α-normalization for imports+ protected by a semantic integrity check+* Bug fixes+ * [Fix `isNormalized` for field selections](https://github.com/dhall-lang/dhall-haskell/pull/1210)+ * [Simplify `Natural/subtract` when its arguments are equivalent](https://github.com/dhall-lang/dhall-haskell/pull/1220)+ * [Fix `NaN` to be judgmentally equivalent to itself](https://github.com/dhall-lang/dhall-haskell/pull/1231)+ * [Fix `Inject` instance for lists](https://github.com/dhall-lang/dhall-haskell/pull/1261)+ * [Fix typechecking of `toMap`](https://github.com/dhall-lang/dhall-haskell/pull/1279)+* Performance optimizations+ * [Optimize a few `Set` instances](https://github.com/dhall-lang/dhall-haskell/pull/1184)+ * [Remove some redundant sorting during normalization](https://github.com/dhall-lang/dhall-haskell/pull/1228)+* Improvements to error messages+ * [Improve error reporting for failed remote imports](https://github.com/dhall-lang/dhall-haskell/pull/1188)+ * [Improve HTTP errors](https://github.com/dhall-lang/dhall-haskell/pull/1253)+* Improvements to formatting+ * [Indent function arguments when formatting](https://github.com/dhall-lang/dhall-haskell/pull/1167)+ * [Prefer unquoted URLs](https://github.com/dhall-lang/dhall-haskell/pull/1235)+ * [Strip leading whitespace](https://github.com/dhall-lang/dhall-haskell/pull/1270)+* Improvements to diffs+ * [Fix diffs for lists](https://github.com/dhall-lang/dhall-haskell/pull/1213)+ * [Improve diff for non-empty lists](https://github.com/dhall-lang/dhall-haskell/pull/1244)+ * [Small fixes to `dhall diff`](https://github.com/dhall-lang/dhall-haskell/pull/1263)+* Improvements to documentation+ * [Fix documentation for `UnionInputType`](https://github.com/dhall-lang/dhall-haskell/pull/1230)+ * [Document support for caching protected imports](https://github.com/dhall-lang/dhall-haskell/pull/1247)+* Improvements to command-line interface+ * [Improve description of `dhall lint`](https://github.com/dhall-lang/dhall-haskell/pull/1264)+ * [Change `dhall type` to resolve imports](https://github.com/dhall-lang/dhall-haskell/pull/1281)++1.25.0++* Supports version 9.0.0 of the standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v9.0.0+* BREAKING CHANGE: Remove support for old-style `List`-like `Optional` literals+ * List-like `Optional` Literals (i.e. `[ 1 ] : Optional Natural`) are no+ longer valid+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1002+* BREAKING CHANGE: Add support for semi-semantic caching+ * This change significantly improves the performance of imports+ * This change also automatically caches imports without an integrity check+ * This changes several types in `Dhall.Import` to support this new+ feature+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1113+* BREAKING CHANGE: Implement new Unicode braced escape sequence+ * Escape sequences encoding surrogate pairs are no longer valid+ * Instead, characters previously encoded as surrogate pairs can instead be+ encoded as a braced sequence+ * For example: "\uD834\uDD1E" must now be written as "\u{1D11E}"+ * See: https://github.com/dhall-lang/dhall-haskell/pull/987+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1104+* BREAKING CHANGE: Make the type of extract richer:+ * `Dhall.extract` can now return a detailed error instead of just a `Maybe`+ * This is a breaking chnage because the type of `extract` changed+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1011+* BREAKING CHANGE: Add support for importing expressions `as Location`+ * This is a breaking change because a new `Location` constructor was added+ to `ImportMode`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1019+* BREAKING CHANGE: Switch `Var` to use an `Int`+ * This is a performance improvement, but also a breaking change since the+ `Integer` in the `Var` constructor was changed to an `Int`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1044+* BREAKING CHANGE: Add new `toMap` keyword+ * This is a breaking change to the API because a new `ToMap` constructor+ was added to the `Expr` type+ * This is also a technically breaking change to the language because `toMap`+ is now a reserved keyword, although most code should be unaffected in+ practice+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1041+* BREAKING CHANGE: Sort the fields of a record projection during normalization+ * This is a technically breaking change to the language because any+ expressions with an uninterpreted record projection will have a different+ semantic integrity check. However, most could should be unaffected in+ practice+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1111+* BUG FIX: Fix substitution into record projection by type+ * An expression like this one was being incorrectly rejected:+ `let e = { a = 10, b = "Text" } let s = { a : Natural } in e.(s)`, which+ this change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1012+* BUG FIX: Reject record projection when there is a field type mismatch+ * Record projection by type was previously not checking the expected+ field types, which this change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1027+* BUG FIX: Fix linting of unused let bindings+ * Certain let bindings were not correctly detected as unused, which this+ change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1001+* BUG FIX: Fix `--file` option+ * The `--file` option from the previous release did not work, due to not+ computing relative paths correctly, which this change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1004+* BUG FIX: Minor fix to `dhall diff`+ * `dhall diff` was incorrectly displaying spurious differences for+ identical lists that were function arguments, which this change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1006+* BUG FIX: Allow `Sort` as type annotation+ * This should have been implemented in the previous release as part of+ supporting version 8.0.0 of the standard, but was missed+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1024+* BUG FIX: `Dhall.Map`: Reflect original key ordering in `Ord` instance+ * `Dhall.Map` now considers key order when comparing `Map`s, which it should+ have done before, but didn't+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1050+* BUG FIX: Consistently format multi-line strings+ * The formatter now formats naked multi-line strings the same as nested+ multi-line strings+ * Specifically, naked multi-line strings can now be formatted on a single+ (just like nested multi-line strings)+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1056+* BUG FIX: Make `isNormalized` consistent with `normalize`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1115+* BUG FIX: Make `normalizeWithM` consistent with `normalize`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1126+* BUG FIX: Fix import alternatives to recover from type errors+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1152+* Feature: Semi-semantic caching+ * The Haskell implementation now implicitly caches *all* local imports, not+ just imports frozen by integrity checks, so that you don't have to freeze+ them when doing local development+ * These cached imports are still correctly invalidated if they or any of+ their dependencies change+ * This new implicit cache is stored underneath `~/.cache/dhall-haskell` by+ default+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1154+* Feature: New `dhall text` subcommand+ * This new subcommand supersedes the old `dhall-to-text` executable+* Feature: Add `instance Lift (Expr s a)`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1119+* Fixes and improvements to error messages:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1030+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1137+* Fixes and improvements to tests:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1155+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1159+* Performance improvements+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1036+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1051+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1048+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1057+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1065+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1066+ * See: https://github.com/dhall-lang/dhall-haskell/pull/1085++1.24.0++* Supports version 8.0.0 of the standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v8.0.0+* BREAKING CHANGE: Allow tabs and blank lines in multi-line strings+ * Blank lines are now ignored for the purpose of dedenting multiline strings+ * Lines with leading tabs (or mixed tabs and spaces) are now dedented, too,+ so long as they all share the same prefix+ * This is technically a breaking change, but unlikely to affect programs+ in practice, especially if they were formatted with `dhall format`. This+ change mainly affects programs that were not indented correctly.+ * See the changelog for standard version 8.0.0 for more details+* BREAKING CHANGE: Simplify bare interpolations+ * Expressions like `λ(x : Text) → "${x}"` now simplify to `λ(x : Text) → x`+ * This is a technically breaking change because it changes how these sorts+ of expressions are serialized. This does not affect semantic integrity+ checks and the new simplified expressions are extensionally equivalent to+ their older counterpart expressions.+ * See the changelog for standard version 8.0.0 for more details+* BREAKING CHANGE: Encode integrity check as multihash+ * Semantic integrity checks are now encoded using the multihash spec+ * This is a technically breaking change that does not perturb the hash for+ user-facing semantic integrity checks. This only affects how expressions+ with unresolved imports are serialized, but semantic integrity checks are+ only computed for fully-resolved imports.+ * See the changelog for standard version 8.0.0 for more details+* BUG FIX: Fix type-checker to reject invalid record type annotations+ * e.g. `{ x = 1 } : { x : Text }` was not properly rejected by the type+ checker+ * See: https://github.com/dhall-lang/dhall-haskell/pull/965+* BUG FIX: Custom header forwarding fixed+ * Forwarding custom headers could previously fail in various ways, such as:+ * Cyclic imports leading to endless network requests+ * Resolving a non-existent import for the custom headers+ * Resolving an existing but incorrect import for the custom headers+ * This change fixes that by forwarding custom headers by value instead of+ by reference+ * See: https://github.com/dhall-lang/dhall-haskell/pull/967+* BUG FIX: Fix GHCJS support+ * `Natural/fold` was broken in version 1.22, which this change fixes+ * Specifically, it would hang for `Natural` numbers greater than 1+ * See: https://github.com/dhall-lang/dhall-haskell/pull/985+* BUG FIX: `dhall diff` no longer double-prints key-value separators+ * See: https://github.com/dhall-lang/dhall-haskell/pull/952+* Feature: Record projection by expression+ * You can now project out a subset of record fields by the expected type+ * `let t = { x : Natural } let p = { x = 1, y = 2 } in p.(t) = { x = 1 }`+ * See the changelog for standard version 8.0.0 for more details+* Feature: Inline headers+ * You no longer need to specify custom headers in a separate import. You+ can now specify them inline within the same file.+ * e.g.: `https://example.com/x using [ { header = "Foo", value = "Bar" } ]`+ * See the changelog for standard version 8.0.0 for more details+* Feature: Allow `Sort` as a type annotation+ * An expression such as `Kind → Kind : Sort` will now type-check+ * `Sort` is still disallowed outside of a type annotation+ * See the changelog for standard version 8.0.0 for more details+* Feature: Allow self-describe-cbor when decoding+ * Dhall expressions serialized as CBOR can be tagged to describe themselves+ as CBOR without affecting decoding+ * See the changelog for standard version 8.0.0 for more details+* Feature: New `--file` option for `dhall` commands+ * In other words, instead of `dhall <<< './some/file` you can now use+ `dhall --file some/file`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/949+* Feature: New `--cache` flag for `dhall freeze` command+ * This automates the idiom used by the Prelude to optimistically cache+ imports but gracefully degrade if the semantic integrity check fails+ * See: https://github.com/dhall-lang/dhall-haskell/pull/980+* Feature: Add `:clear` command to `dhall repl`+ * This deletes previous bindings from the history so that they can be+ garbage collected+ * See: https://github.com/dhall-lang/dhall-haskell/pull/966+* Feature: New `chunkExprs` `Traversal` added to `Dhall.Core`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/954+* Feature: New `Dhall.Optics` module+ * This re-exports some convenient @lens@ utilities used internally for+ packages trying to avoid a @lens@ dependency+ * See: https://github.com/dhall-lang/dhall-haskell/pull/986+* More GHC 8.8 support+ * See: https://github.com/dhall-lang/dhall-haskell/pull/961++1.23.0++* BREAKING CHANGE: Fix marshaling union literals+ * 1.22.0 introduced two separate bugs in marshaling union literals between+ Dhall and Haskell, which this release fixes:+ * Dhall enums did not correctly map onto Haskell enums+ * New-style union literals (i.e. `< A : T >.A x`) were not correctly+ supported+ * See: https://github.com/dhall-lang/dhall-haskell/pull/918+ * See: https://github.com/dhall-lang/dhall-haskell/pull/927+ * See: https://github.com/dhall-lang/dhall-haskell/pull/936+* BUG FIX: Fix α-normalization+ * Version 1.22.0 introduced a new faster evaluation algorithm, but the new+ algorithm introduced two α-normalization regression, which this release+ fixes+ * The primary effect of this bug was that semantic integrity checks would+ fail for expressions that contain an `if`/`then`/else` expression in their+ normal form+ * See: https://github.com/dhall-lang/dhall-haskell/pull/931+ * See: https://github.com/dhall-lang/dhall-haskell/pull/938+* BUG FIX: Fix merging of sort-level record types+ * The language standard requires that `{ a : Kind } ⩓ { b : Kind }` is+ valid, which this change fixes+ * See: https://github.com/dhall-lang/dhall-haskell/pull/891+* BUG FIX: `dhall freeze` respects the `--ascii` flag+ * See: https://github.com/dhall-lang/dhall-haskell/pull/934+* BUG FIX: Don't autocomplete fields for record types+ * This prevents the REPL from expanding `{ x : T }.<TAB>` to `{ x : T }.x`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/937+* Support `MonadFail`-related changes in GHC 8.8+ * See: https://github.com/dhall-lang/dhall-haskell/pull/912+* Add `cross` flag to simplify cross-compilation+ * This allows the `dhall` package to be built without using+ `TemplateHaskell`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/928+* Increase lines of context for error messages+ * Error messages now provide at least 20 lines of context instead of 3+ before truncating large expressions+ * See: https://github.com/dhall-lang/dhall-haskell/pull/916+* Add line numbers to error messages+ * The bottom of every Dhall type error includes the original source code,+ which now has line numbers on the left margin+ * See: https://github.com/dhall-lang/dhall-haskell/pull/919+* Expand lower bounds on `megaparsec`/`transformers-compat` dependencies+ * This is to support `dhall` on Debian Sid+ * See: https://github.com/dhall-lang/dhall-haskell/pull/939++1.22.0++* Supports version 7.0.0 of the standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v7.0.0+* BREAKING CHANGE: Add support for empty alternatives+ * The `Union` type now has an optional (`Maybe`) type for each alternative+ * See the changelog for standard version 7.0.0 for more details+ * See: https://github.com/dhall-lang/dhall-haskell/pull/863+* BREAKING CHANGE: Remove support for URL fragments+ * The `URL` type no longer has a field for a URL fragment since the language+ no longer supports fragments+ * See the changelog for standard version 7.0.0 for more details+ * See: https://github.com/dhall-lang/dhall-haskell/pull/851+* BREAKING CHANGE: Remove deprecated `Path` type synonym+ * See: https://github.com/dhall-lang/dhall-haskell/pull/858+* BUG FIX: Correctly parse identifiers beginning with `http`+ * i.e. `httpPort` was supposed to be a valid identifier name and now is+ * See: https://github.com/dhall-lang/dhall-haskell/pull/870+* BUG FIX: Fix `dhall encode` bug+ * `dhall encode` bug was generating binary expressions that were valid+ (i.e. they would decode correctly) but were non-standard (i.e. hashing+ them would not match the hash you would normally get from a semantic+ integrity check)+ * Semantic integrity checks were not affected by this bug since they used+ a slightly different code path that generated the correct binary input to+ the hash. Only the `dhall decode` subcommand was affected+ * See: https://github.com/dhall-lang/dhall-haskell/pull/859+* BUG FIX: Fix for `Dhall.UnionType`+ * This fixes some expressions that would previously fail to marshal into+ Haskell, specifically those were the marshalling logic was built using+ the `UnionType` utilities+ * See: https://github.com/dhall-lang/dhall-haskell/pull/857+* Feature: New `--alpha` flag to α-normalize command-line output+ * See: https://github.com/dhall-lang/dhall-haskell/pull/855+* Performance improvements+ * The normalizer is now *much* faster+ * See: https://github.com/dhall-lang/dhall-haskell/pull/876++1.21.0++* Supports version 6.0.0 of the language standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v6.0.0+* BREAKING CHANGE: Remove the `constructors` keyword+ * ... as standardized in version 6.0.0 of the language standard+ * The deprecation cycle is over, so the keyword is no longer supported+ * For more details, see: https://github.com/dhall-lang/dhall-lang/wiki/Migration%3A-Deprecation-of-constructors-keyword+ * See: https://github.com/dhall-lang/dhall-haskell/pull/829+* BREAKING CHANGE: CBOR-encode only special `Double`s as half-floats+ * ... as standardized in version 6.0.0 of the language standard+ * CBOR `Double`s except `Infinity`/`-Infinity`/`NaN`/`0.0` are now encoded in at+ least 32 bits+ * See: https://github.com/dhall-lang/dhall-haskell/pull/822+* BREAKING CHANGE: Sort record and union fields when CBOR-encoding+ * Fields and alternatives are now sorted when serialized+ * This does not affect semantic integrity checks, which already sorted these+ fields/alternatives before hashing expressions+ * This does affect the serialization of expressions that have not been+ normalized (e.g. uninterpreted expressions transmitted over the wire)+ * See: https://github.com/dhall-lang/dhall-haskell/pull/835+* BUG FIX: Fix non-exhaustive pattern match in `dhall lint`+ * This fixes: `Irrefutable pattern failed for pattern Let (l' :| ls') d'`+ * This bug would cause `dhall lint` to fail on some nested `let`/`in`+ expressions+ * See: https://github.com/dhall-lang/dhall-haskell/pull/780+ * See: https://github.com/dhall-lang/dhall-haskell/pull/784+* BUG FIX: Don't fail if `$HOME` environment variable is unset+ * The interpreter was incorrectly throwing an exception if `HOME` was unset+ * The standard requires that implementations should handle the `HOME`+ environment variable being missing+ * See: https://github.com/dhall-lang/dhall-haskell/pull/789+* Feature: Remove version tag from semantic integrity check+ * ... as standardized in version 6.0.0 of the language standard+ * This is not a breaking change because this change also includes+ backwards-compatible support for semantic integrity checks produced by+ older versions of the interpreter+* Feature: Support Unicode path components+ * ... as standardized in version 6.0.0 of the language standard+ * You can now use Unicode in path components if they are quoted+ * i.e. `./families/"禺.dhall"` is now legal+* Feature: Add `Text/show` built-in+ * ... as standardized in version 6.0.0 of the language standard+ * You can now convert a `Text` literal to its equivalent Dhall source code+ (which is itself a `Text` literal)+ * This comes in handy when using Dhall code to generate JSON or Dhall code+ * See: https://github.com/dhall-lang/dhall-haskell/pull/811+* Feature: Add `--immediate-dependencies`/`--transitive-dependencies` flags for+ `dhall resolve`+ * You can now retrieve all of your immediate or transitive dependencies as a+ textual list+ * This simplifies integration with other command-line tools (such as file+ watchers)+ * See: https://github.com/dhall-lang/dhall-haskell/pull/795+ * See: https://github.com/dhall-lang/dhall-haskell/pull/803+* Feature: `dhall freeze` now only freezes remote imports by default+ * `dhall freeze` used to freeze all imports (including local imports and+ environment variables)+ * Now `dhall freeze` only freezes remote imports by default, which is what+ most users want+ * You can install freeze all imports using the `--all` flag+ * See: https://github.com/dhall-lang/dhall-haskell/pull/808+* Feature: `:save` and `:load` REPL state+ * `:save` with no arguments now saves the REPL state to a `.dhall-repl-N`+ file+ * The file format is a list of `dhall repl` commands+ * You can use `:load` to load the saved state back into the REPL+ * See: https://github.com/dhall-lang/dhall-haskell/pull/807+* Feature: Add `:hash` command to `dhall repl`+ * This lets you conveniently hash expressions within the `dhall repl`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/806+* Feature: Add `--check` flag to `dhall format`+ * Use this to check if the input is already formatted+ * Useful for continuous integration when you want to ensure that all code+ under version control remains formatted+ * See: https://github.com/dhall-lang/dhall-haskell/pull/810+* Feature: Add `UnionInputType` builder for `InputType`s+ * This is the union analog of `RecordInputType`, letting you build a+ record explicitly instead of deriving the instance using GHC generics+ * See: https://github.com/dhall-lang/dhall-haskell/pull/775+* Feature: Add `:set`/`:unset` commands to `dhall repl`+ * You can use these commands to set or unset command-line options+ * Currently only setting/unsetting `--explain` is supported+* Standards-compliance fixes:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/779+ * See: https://github.com/dhall-lang/dhall-haskell/pull/804+ * See: https://github.com/dhall-lang/dhall-haskell/pull/833+* Documentation fixes:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/792+ * See: https://github.com/dhall-lang/dhall-haskell/pull/825+* Test fixes:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/782+ * See: https://github.com/dhall-lang/dhall-haskell/pull/836+* Improved error messages:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/812+ * See: https://github.com/dhall-lang/dhall-haskell/pull/815+ * See: https://github.com/dhall-lang/dhall-haskell/pull/824+* Formatting fixes:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/831+* REPL fixes:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/837++1.20.1++* BUG FIX: Fix binary encoding to use correct standard version+ * This fixes computed hashes to correctly match standard version 5.0.0+ * This is not marked as a breaking change since it is a bug fix. The+ 1.20.0 release will be blacklisted on Hackage and users should upgrade+ from 1.19.* directly to 1.20.1+ * See: https://github.com/dhall-lang/dhall-haskell/pull/771++1.20.0++* Supports version 5.0.0 of the language standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v5.0.0+* BREAKING CHANGE TO THE LANGUAGE: Implement standardized support for multi-line+ literals+ * This updates the multi-line support to match the standard+ * This is a breaking change because empty lines within the multi-line+ literal now require leading whitespace whereas previously they did not+ * This is also a breaking change because now a newline is required after+ the opening `''` quotes whereas previously it was not required+ * If you use `dhall format` then your multi-line literals already have the+ necessary leading whitespace+* BREAKING CHANGE TO THE LANGUAGE: `constructors x = x`+ * Now the `constructors` keyword behaves like an identity function, since+ constructors can already be accessed as fields off the original union+ type.+ * This is a breaking change since any record of terms that contains a+ `constructors` field will now be a forbidden mixed record of types and+ terms.+ * This is also a breaking change if you annotated the type of what used to+ be a `constructors` record.+ * `dhall lint` will now remove the obsolete `constructors` keyword for you+ * See: https://github.com/dhall-lang/dhall-haskell/pull/693+ * See: https://github.com/dhall-lang/dhall-haskell/pull/701+* BREAKING CHANGE TO THE API: Restore `Parent` constructor for `Local` type+ * This more closely matches the standard and also enables `dhall format` to+ produce a leading `../` for imports instead of `./../`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/718+* BUG FIX: Fix type-checking bug for unions+ * The first fix was that the inferred type was wrong for unions where+ alternatives were types or kinds+ * The second fix was that unions that mixed terms/types/kinds were not+ properly rejected+ * See: https://github.com/dhall-lang/dhall-haskell/pull/763+* BUG FIX: Change how `dhall repl` handles prior definitions+ * This changes the REPL to handle previous bindings as if they were+ defined using a large `let` expression instead of adding them to the+ context+ * This fixes some type-checking false negatives+ * See: https://github.com/dhall-lang/dhall-haskell/pull/729+* Feature: Autocomplete for `dhall repl`+ * You can now auto-complete record fields, union constructors, and+ identifiers that are in scope+ * See: https://github.com/dhall-lang/dhall-haskell/pull/727+* Feature: GHCJS support+ * `dhall` can now be built using GHCJS, although some features are still+ not supported for GHCJS, such as:+ * Semantic integrity checks+ * Custom HTTP headers+ * Also, HTTP imports only work for URLs that support CORS+ * See: https://github.com/dhall-lang/dhall-haskell/pull/739+* Feature: Add support for records of records of types+ * You can now nest records of types+ * See: https://github.com/dhall-lang/dhall-haskell/pull/700+* Feature: Add `:quit` command for `dhall repl`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/719+* Feature: Add `--json` flag for `dhall {encode,decode}`+ * You can now produce/consume CBOR expressions via JSON instead of binary+ * See: https://github.com/dhall-lang/dhall-haskell/pull/717+* Feature: Add decoding logic for `as Text`+ * You can now preserve the `as Text` qualifier on imports when serializing+ them+ * See: https://github.com/dhall-lang/dhall-haskell/pull/712+* Prenormalize substituted expressions+ * This is a performance improvement that reduces the time and memory+ consumption when normalizing expressions+ * See: https://github.com/dhall-lang/dhall-haskell/pull/765++1.19.1+++* BUG FIX: Fix serious `dhall lint` bug+ * `dhall lint` would sometimes remove `let` expressions that were still+ in use+ * See: https://github.com/dhall-lang/dhall-haskell/pull/703+* BUG FIX: Fix import caching efficiency bug+ * Some imports were being wastefully fetched multiple times+ * See: https://github.com/dhall-lang/dhall-haskell/pull/702+* Feature: Generate dot graph to visualize import graph+ * Use the `dhall resolve --dot` command+ * See: https://github.com/dhall-lang/dhall-haskell/pull/698+ * See: https://github.com/dhall-lang/dhall-haskell/pull/713+* Improve HTTP error messages+ * See: https://github.com/dhall-lang/dhall-haskell/pull/710++1.19.0++* Supports version 4.0.0 of the language standard+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v4.0.0+* BREAKING CHANGE TO THE LANGUAGE AND API: Prevent Hurkens' paradox+ * This fixes a type-checking soundness bug which permitted infinite loops+ * This is a breaking change because infinite loops are no longer possible+ * This is also a breaking change because a record of types is now treated as+ a kind instead of a type+ * See: https://github.com/dhall-lang/dhall-haskell/pull/680+* BREAKING CHANGE TO THE LANGUAGE AND API: `Double`s are now double-precision+ floating point numbers+ * This restricts the range of `Double`s to IEEE 754 double-precision+ floating point+ * This also implies that you can no longer convert `Scientific` values to+ `Dhall` expressions (i.e. no `Inject` instance for `Scientific`)+ * See: https://github.com/dhall-lang/dhall-haskell/pull/667+* BREAKING CHANGE TO THE API: Preserve field order for record projection+ * The API uses a new `Dhall.Set.Set` type instead of `Data.Set.Set`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/670+* BREAKING CHANGE TO THE API: Add support for multi-`let` expressions+ * This changes the `Let` constructor to now support storing multiple+ bindings per `let` expression+ * See: https://github.com/dhall-lang/dhall-haskell/pull/675+* Access constructors as if they were fields of the union type+ * In other words: `< Left : Bool | Right : Natural >.Left`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/657+* Support GHC 8.6+ * See: https://github.com/dhall-lang/dhall-haskell/pull/669+* Add support for quoted path components+ * i.e. `/"foo"/bar/"baz qux"` or `https://example.com/foo/"bar?baz"?qux`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/690+* Fix parsing of `//\\` operator+ * See: https://github.com/dhall-lang/dhall-haskell/commit/9d0fd42d95ab69fa64da4afd8b60d69aca8e65a6+* Preserve Unicode characters when formatting code+ * See: https://github.com/dhall-lang/dhall-haskell/pull/679+* Allow identifier names to begin with `Some`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/658+* Add `subExpressions` `Traversal`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/660+* Add `normalizeWithM` for monadic normalization+ * See: https://github.com/dhall-lang/dhall-haskell/pull/371+* Custom normalizers now take precedence over default normalization logic+ * This allows one to override the implementation of built-in operators+ * See: https://github.com/dhall-lang/dhall-haskell/pull/684++1.18.0++* Supports version 3.0.0 of the language standard:+ * See: https://github.com/dhall-lang/dhall-lang/releases/tag/v3.0.0+* BREAKING CHANGE TO THE LANGUAGE AND API: New `Some`/`None` constructors for+ `Optional` values+ * Example: `[ Some 1, None Natural ]`+ * This is a breaking change to the language because `Some` and `None` are+ now reserved keywords+ * This is a breaking change to the API because `Some` and `None` are new+ constructors for the `Expr` type+* BREAKING CHANGE TO THE LANGUAGE AND API: Support for kind polymorphism+ * This adds a new `Sort` constant above `Kind` in the hierarchy+ * i.e. `Type : Kind : Sort`+ * This is a breaking change to the language because `Sort` is now a+ reserved keyword+ * This is a breaking change to the API because `Sort` is a new+ constructor for the `Expr` type+* BREAKING CHANGE TO THE API: New `Dhall.Map` module+ * This replaces `InsOrdHashMap` in the API+ * The primary motivation is to improve performance and to remove the+ dependency on `insert-ordered-containers`+* BREAKING CHANGE TO THE API: Use standard version instead of protocol version+ * The binary protocol is now versioned alongside the standard+ * The `ProtocolVersion` type is renamed to `StandardVersion` and the+ * `--protocol-version` option is renamed to `--standard-version`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/634+* BUG FIX: Fix import chaining for custom header imports+ * See: https://github.com/dhall-lang/dhall-haskell/pull/618+* BUG FIX: Fix import chaining for imports protected by semantic integrity+ checks+ * See: https://github.com/dhall-lang/dhall-haskell/pull/584+* BUG FIX: Record literals and types produced by `∧`/`⫽`/`⩓` are now sorted+ * This ensures that β-normalization is idempotent+ * See: https://github.com/dhall-lang/dhall-haskell/pull/572+* BUG FIX: `dhall freeze` now correctly handles the starting file being+ located outside the current working directory+ * See: https://github.com/dhall-lang/dhall-haskell/commit/a22aa79d1957be9ecf166ea066e2a9a5b309e1ae+* BUG FIX: Fix parsing of IPv4-mapped IPv6 addresses+ * See: https://github.com/dhall-lang/dhall-haskell/pull/632+* FEATURE: New `--ascii` flag for ASCII output+ * See: https://github.com/dhall-lang/dhall-haskell/pull/570+* FEATURE: New `dhall encode` and `dhall decode` subcommands+ * These allow you to transform Dhall source code to and from its binary+ representation+ * See: https://github.com/dhall-lang/dhall-haskell/pull/588+* LARGE parsing performance improvements+ * Parsing is about 10x-100x faster on most code+ * See: https://github.com/dhall-lang/dhall-haskell/pull/591+ * See: https://github.com/dhall-lang/dhall-haskell/pull/592+ * See: https://github.com/dhall-lang/dhall-haskell/pull/597+ * See: https://github.com/dhall-lang/dhall-haskell/pull/601+ * See: https://github.com/dhall-lang/dhall-haskell/pull/602+ * See: https://github.com/dhall-lang/dhall-haskell/pull/604+ * See: https://github.com/dhall-lang/dhall-haskell/pull/606+* Type-checking performance improvements:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/566+* Normalization performance improvements:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/610+* `dhall freeze` now caches the imports as it freezes them+ * See: https://github.com/dhall-lang/dhall-haskell/pull/587+* `dhall freeze` now refreezes imports with invalid semantic integrity checks+ * See: https://github.com/dhall-lang/dhall-haskell/pull/637+* `dhall freeze` now adds a trailing newline+ * See: https://github.com/dhall-lang/dhall-haskell/pull/629+* Build against `megaparsec-7.0.*`+ * See: https://github.com/dhall-lang/dhall-haskell/pull/565+* Support GHC 8.6+ * See: https://github.com/dhall-lang/dhall-haskell/pull/599+ * See: https://github.com/dhall-lang/dhall-haskell/pull/623+* Support GHC all the way back to 7.10.3+ * See: https://github.com/dhall-lang/dhall-haskell/pull/595+ * See: https://github.com/dhall-lang/dhall-haskell/pull/621+* Improvements to error messages:+ * See: https://github.com/dhall-lang/dhall-haskell/pull/563+ * See: https://github.com/dhall-lang/dhall-haskell/pull/576+ * See: https://github.com/dhall-lang/dhall-haskell/pull/583+ * See: https://github.com/dhall-lang/dhall-haskell/pull/589+++1.17.0++* This release corresponds to version 2.0.0 of the language standard+* BREAKING CHANGE TO THE LANGUAGE AND API: Binary serialization support+ * This is a breaking change to the hash for all semantic integrity checks+ * The hash used by the semantic integrity check is now based on the+ binary representation instead of a text representation of the+ expression+ * You can pin the new hashes by supplying the `--protocol-version 1.0`+ option on the command line until you need support for newer language+ features * This also includes a breaking change to `ImportType` in the API * BREAKING CHANGE TO THE LANGUAGE: Disallow combining records of terms and types
@@ -1,4 +1,4 @@-Copyright (c) 2018 Gabriel Gonzalez+Copyright (c) 2020 Gabriella Gonzalez All rights reserved. Redistribution and use in source and binary forms, with or without
@@ -1,12 +1,12 @@ {-# LANGUAGE OverloadedStrings #-} module Main (main) where -import Criterion.Main (defaultMain)+import Data.Void (Void)+import Test.Tasty.Bench -import qualified Criterion as Criterion-import qualified Data.Sequence as Seq-import qualified Dhall.Core as Core-import qualified Dhall.Import as Import+import qualified Data.Sequence as Seq+import qualified Dhall.Core as Core+import qualified Dhall.Import as Import import qualified Dhall.TypeCheck as TypeCheck dhallPreludeImport :: Core.Import@@ -21,32 +21,52 @@ } } -issue412 :: Core.Expr s TypeCheck.X -> Criterion.Benchmarkable-issue412 prelude = Criterion.whnf TypeCheck.typeOf expr+issue412 :: Core.Expr s Void -> Benchmarkable+issue412 prelude = whnf TypeCheck.typeOf expr where expr- = Core.Let (pure (Core.Binding "prelude" Nothing prelude))+ = Core.Let (Core.Binding Nothing "prelude" Nothing Nothing Nothing prelude) $ Core.ListLit Nothing $ Seq.replicate 5- $ Core.Var (Core.V "prelude" 0) `Core.Field` "types" `Core.Field` "Little" `Core.Field` "Foo"+ $ Core.Var (Core.V "prelude" 0) `Core.Field` types `Core.Field` little `Core.Field` foo+ types = Core.makeFieldSelection "types"+ little = Core.makeFieldSelection "little"+ foo = Core.makeFieldSelection "Foo" -unionPerformance :: Core.Expr s TypeCheck.X -> Criterion.Benchmarkable-unionPerformance prelude = Criterion.whnf TypeCheck.typeOf expr+unionPerformance :: Core.Expr s Void -> Benchmarkable+unionPerformance prelude = whnf TypeCheck.typeOf expr where- innerBinding =- Core.Binding "big" Nothing- (prelude `Core.Field` "types" `Core.Field` "Big")-- outerBinding =- Core.Binding "x" Nothing- (Core.Let (pure innerBinding) (Core.Prefer "big" "big"))-- expr = Core.Let (pure outerBinding) "x"+ expr =+ Core.Let+ (Core.Binding+ Nothing+ "x"+ Nothing+ Nothing+ Nothing+ (Core.Let+ (Core.Binding+ Nothing+ "big"+ Nothing+ Nothing+ Nothing+ (prelude `Core.Field` types `Core.Field` big)+ )+ (Core.Prefer mempty Core.PreferFromSource "big" "big")+ )+ )+ "x"+ types = Core.makeFieldSelection "types"+ big = Core.makeFieldSelection "Big" main :: IO ()-main = do- prelude <- Import.load (Core.Embed dhallPreludeImport)+main = defaultMain- [ Criterion.bench "issue 412" (issue412 prelude)- , Criterion.bench "union performance" (unionPerformance prelude)+ [ env prelude $ \p ->+ bgroup "Prelude"+ [ bench "issue 412" (issue412 p)+ , bench "union performance" (unionPerformance p)+ ] ]+ where prelude = Import.load (Core.Embed dhallPreludeImport)
@@ -1,5 +1,5 @@ { types =- { Big = constructors ./BigEnum.dhall- , Little = constructors ./LittleEnum.dhall+ { Big = ./BigEnum.dhall+ , Little = ./LittleEnum.dhall } }
@@ -1,20 +0,0 @@--{-# LANGUAGE OverloadedStrings #-}--module Main where--import qualified Dhall.Main as Main-import Dhall.Binary (defaultStandardVersion)--options :: Main.Options-options = Main.Options- { Main.mode = Main.Default Nothing False False- , Main.explain = False- , Main.plain = False- , Main.ascii = False- , Main.standardVersion = defaultStandardVersion- }--main :: IO ()-main = do- Main.command options
@@ -1,61 +0,0 @@-λ(xs : List { cores : Natural, host : Text, key : Text, mandatoryFeatures : -List Text, platforms : List < AArch64_Linux : {} | ARMv5tel_Linux : {} | -ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | -PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : -{} | X86_64_Linux : {} | X86_64_Solaris : {} >, speedFactor : Natural, -supportedFeatures : List Text, user : Optional Text }) → List/fold { cores : -Natural, host : Text, key : Text, mandatoryFeatures : List Text, platforms : -List < AArch64_Linux : {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | -I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | -X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : -{} | X86_64_Solaris : {} >, speedFactor : Natural, supportedFeatures : List -Text, user : Optional Text } xs Text (λ(x : { cores : Natural, host : Text, -key : Text, mandatoryFeatures : List Text, platforms : List < AArch64_Linux : -{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : -{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | -X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : -{} >, speedFactor : Natural, supportedFeatures : List Text, user : Optional -Text }) → λ(y : Text) → (Optional/fold Text x.user Text (λ(user : Text) -→ user ++ "@" ++ x.host ++ "") x.host ++ " " ++ (merge { Empty = λ(_ : {}) -→ "", NonEmpty = λ(result : Text) → result } (List/fold < AArch64_Linux : -{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : -{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | -X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : -{} > x.platforms < Empty : {} | NonEmpty : Text > (λ(element : < AArch64_Linux -: {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux -: {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | -X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : -{} >) → λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = -λ(_ : {}) → < NonEmpty = merge { AArch64_Linux = λ(_ : {}) → -"aarch64-linux", ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux -= λ(_ : {}) → "armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", -I686_Linux = λ(_ : {}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → -"mips64el-linux", PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin -= λ(_ : {}) → "x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → -"x86_64-darwin", X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd", X86_64_Linux -= λ(_ : {}) → "x86_64-linux", X86_64_Solaris = λ(_ : {}) → -"x86_64-solaris" } element | Empty : {} >, NonEmpty = λ(result : Text) → < -NonEmpty = (merge { AArch64_Linux = λ(_ : {}) → "aarch64-linux", -ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux = λ(_ : {}) → -"armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", I686_Linux = λ(_ : -{}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → "mips64el-linux", -PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin = λ(_ : {}) → -"x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → "x86_64-darwin", X86_64_FreeBSD -= λ(_ : {}) → "x86_64-freebsd", X86_64_Linux = λ(_ : {}) → -"x86_64-linux", X86_64_Solaris = λ(_ : {}) → "x86_64-solaris" } element) ++ -"," ++ result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < -Empty = {=} | NonEmpty : Text >) : Text) ++ " " ++ x.key ++ " " ++ Integer/show -(Natural/toInteger x.cores) ++ " " ++ Integer/show (Natural/toInteger -x.speedFactor) ++ " " ++ (merge { Empty = λ(_ : {}) → "", NonEmpty = -λ(result : Text) → result } (List/fold Text x.supportedFeatures < Empty : {} -| NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} | NonEmpty -: Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | Empty : {} ->, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ result | -Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = {=} | -NonEmpty : Text >) : Text) ++ " " ++ (merge { Empty = λ(_ : {}) → "", -NonEmpty = λ(result : Text) → result } (List/fold Text x.mandatoryFeatures < -Empty : {} | NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} -| NonEmpty : Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | -Empty : {} >, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ -result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = -{=} | NonEmpty : Text >) : Text) ++ "\n") ++ y) ""
@@ -1,22 +0,0 @@--let Nat = ∀(N : Type) → (N → N) → N → N-let n2 = λ(N : Type) → λ(s : N → N) → λ(z : N) → s (s z)-let n5 = λ(N : Type) → λ(s : N → N) → λ(z : N) → s (s (s (s (s z))))--let mul =- λ(a : Nat) → λ(b : Nat) → λ(N : Type) → λ(s : N → N) → λ(z : N) → a N (b N s) z--let add =- λ(a : Nat) → λ(b : Nat) → λ(N : Type) → λ(s : N → N) → λ(z : N) → a N s (b N s z)--let n10 = mul n2 n5-let n100 = mul n10 n10-let n1k = mul n10 n100-let n10k = mul n100 n100-let n100k = mul n10 n10k-let n1M = mul n10k n100-let n5M = mul n1M n5-let n10M = mul n1M n10-let n20M = mul n10M n2--in n1M Natural (λ (x:Natural) → x + 1) 0
@@ -1,18 +0,0 @@--let compose- : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c- = λ(A : Type)- → λ(B : Type)- → λ(C : Type)- → λ(f : A → B)- → λ(g : B → C)- → λ(x : A)- → g (f x)--let composeN : ∀ (a : Type) → Natural → (a → a) → a → a- = λ (a : Type)- → λ (n : Natural)- → λ (f : a → a)- → Natural/fold n (a → a) (compose a a a f) (λ (x : a) → x)--in composeN Natural 100000 (λ (x : Natural) → x + 1) 0
@@ -1,75 +0,0 @@--let iterate- = λ(n : Natural)- → λ(a : Type)- → λ(f : a → a)- → λ(x : a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- { index : Natural, value : {} }- ( List/indexed- {}- ( List/build- {}- ( λ(list : Type)- → λ(cons : {} → list → list)- → Natural/fold n list (cons {=})- )- )- )- list- ( λ(y : { index : Natural, value : {} })- → cons (Natural/fold y.index a f x)- )- )--let countTo =- λ (x : Natural)- → iterate x Natural (λ (x : Natural) → x + 1) 0--let sum =- λ (xs : List Natural)- → List/fold Natural xs Natural (λ (x : Natural) → λ (acc : Natural) → x + acc) 0---let map- : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b- = λ(a : Type)- → λ(b : Type)- → λ(f : a → b)- → λ(xs : List a)- → List/build- b- ( λ(list : Type)- → λ(cons : b → list → list)- → List/fold a xs list (λ(x : a) → cons (f x))- )--let any- : ∀(a : Type) → (a → Bool) → List a → Bool- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False--let filter- : ∀(a : Type) → (a → Bool) → List a → List a- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- a- xs- list- (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)- )--in sum (filter Natural Natural/even- (map Natural Natural (λ(x:Natural) → x + 10) (countTo 1000)))
@@ -1,45 +0,0 @@--let iterate =- λ(n : Natural)- → λ(a : Type)- → λ(f : a → a)- → λ(x : a)- → (Natural/fold n- (a → List a → {fst:a, snd:List a})- (λ (hyp : a → List a → {fst:a, snd:List a}) →- λ (x : a) → λ (xs : List a)- → let tup = hyp x xs- in {fst = f (tup.fst), snd = tup.snd # [tup.fst]})- (λ (x : a) → λ (xs : List a) → {fst=x, snd=xs})- x ([] : List a)).snd--let countTo =- λ (x : Natural)- → iterate x Natural (λ (x : Natural) → x + 1) 0--let sum =- λ (xs : List Natural)- → List/fold Natural xs Natural (λ (x : Natural) → λ (acc : Natural) → x + acc) 0--let map- = λ(a : Type)- → λ(b : Type)- → λ(f : a → b)- → λ(xs : List a)- → List/fold a xs (List b) (λ (x : a) → λ (xs : List b) → [f x] # xs) ([] : List b)--let any- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False--let filter- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/fold a xs (List a)- (λ (x : a) → λ (xs : List a) → if f x then [x] # xs else xs) ([] : List a)--in sum (filter Natural Natural/even- (map Natural Natural (λ(x:Natural) → x + 10) (countTo 1000)))
@@ -1,44 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE TypeApplications #-}--module Main where--import Criterion.Main (defaultMain, bgroup, bench, whnf, nfIO)--import qualified Criterion.Main as Criterion-import qualified Dhall.Map as Map--testData :: Integer -> Map.Map Integer Integer-testData i = foldr (\j -> Map.insert j j) mempty [1 .. i]--benchOrderedTraversal :: String -> Map.Map Integer Integer -> Criterion.Benchmark-benchOrderedTraversal dataLabel mapData =- bgroup ("Ordered Traversals: " <> dataLabel)- [ bench "traverseWithKey" $- whnf (Map.traverseWithKey (\_ i -> pure @Maybe $ i ^ i)) mapData- , bench "traverseWithKey_" $- whnf (Map.traverseWithKey_ (\_ i -> pure @Maybe (i ^ i) *> pure ())) mapData- ]--benchUnorderedTraversal :: String -> Map.Map Integer Integer -> Criterion.Benchmark-benchUnorderedTraversal dataLabel mapData =- bgroup ("Unordered Traversals: " <> dataLabel)- [ bench "unorderedTraverseWithKey_" $- whnf (Map.unorderedTraverseWithKey_ (\_ i -> pure @Maybe (i ^ i) *> pure ())) mapData- ]--main :: IO ()-main = do- let !smallMap = testData 10- !mediumMap = testData 1000- !largeMap = testData 100000- defaultMain- [ benchOrderedTraversal "small" smallMap- , benchUnorderedTraversal "small" smallMap-- , benchOrderedTraversal "medium" mediumMap- , benchUnorderedTraversal "medium" mediumMap-- , benchOrderedTraversal "large" largeMap- , benchUnorderedTraversal "large" largeMap- ]
@@ -1,98 +1,91 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-} module Main where -import Control.Monad (forM)-import Criterion.Main (defaultMain, bgroup, bench, whnf, nfIO)-import Data.Map (Map, foldrWithKey, singleton, unions)-import Data.Monoid ((<>))--import System.Directory+import Control.Exception (throw)+import Control.Monad (forM)+import Data.Map (Map)+import Data.Text (Text)+import Data.Void (Void)+import Test.Tasty.Bench -import qualified Codec.Serialise-import qualified Criterion.Main as Criterion import qualified Data.ByteString.Lazy-import qualified Data.Text as T-import qualified Data.Text.IO as TIO+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Data.Text.IO import qualified Dhall.Binary-import qualified Dhall.Parser as Dhall--#if MIN_VERSION_directory(1,2,3)-#else-import Control.Exception (bracket)--withCurrentDirectory :: FilePath -- ^ Directory to execute in- -> IO a -- ^ Action to be executed- -> IO a-withCurrentDirectory dir action =- bracket getCurrentDirectory setCurrentDirectory $ \ _ -> do- setCurrentDirectory dir- action--listDirectory :: FilePath -> IO [FilePath]-listDirectory path = filter f <$> getDirectoryContents path- where f filename = filename /= "." && filename /= ".."-#endif+import qualified Dhall.Core as Dhall+import qualified Dhall.Parser as Dhall+import qualified System.Directory as Directory -type PreludeFiles = Map FilePath T.Text+type PreludeFiles = Map FilePath Text loadPreludeFiles :: IO PreludeFiles-loadPreludeFiles = loadDirectory "Prelude"+loadPreludeFiles = loadDirectory "./dhall-lang/Prelude" where loadDirectory :: FilePath -> IO PreludeFiles loadDirectory dir =- withCurrentDirectory dir $ do- files <- getCurrentDirectory >>= listDirectory+ Directory.withCurrentDirectory dir $ do+ files <- Directory.getCurrentDirectory >>= Directory.listDirectory results <- forM files $ \file -> do- file' <- makeAbsolute file- doesExist <- doesFileExist file'+ file' <- Directory.makeAbsolute file+ doesExist <- Directory.doesFileExist file' if doesExist then loadFile file' else loadDirectory file'- pure $ unions results+ pure $ Map.unions results loadFile :: FilePath -> IO PreludeFiles- loadFile path = singleton path <$> TIO.readFile path+ loadFile path = Map.singleton path <$> Data.Text.IO.readFile path -benchParser :: PreludeFiles -> Criterion.Benchmark+benchParser :: PreludeFiles -> Benchmark benchParser = bgroup "exprFromText"- . foldrWithKey (\name expr -> (benchExprFromText name expr :)) []+ . Map.foldrWithKey (\name expr -> (benchExprFromText name expr :)) [] -benchExprFromText :: String -> T.Text -> Criterion.Benchmark-benchExprFromText name expr =+benchExprFromText :: String -> Text -> Benchmark+benchExprFromText name !expr = bench name $ whnf (Dhall.exprFromText "(input)") expr -benchExprFromBytes- :: String -> Data.ByteString.Lazy.ByteString -> Criterion.Benchmark-benchExprFromBytes name bytes = bench name (whnf f bytes)+benchExprFromBytes :: String -> Data.ByteString.Lazy.ByteString -> Benchmark+benchExprFromBytes name bs = bench name (nf f bs) where- f bytes = do- term <- case Codec.Serialise.deserialiseOrFail bytes of- Left _ -> Nothing- Right term -> return term- case Dhall.Binary.decodeExpression term of- Left _ -> Nothing- Right expression -> return expression+ f bytes =+ case Dhall.Binary.decodeExpression bytes of+ Left exception -> error (show exception)+ Right expression -> expression :: Dhall.Expr Void Dhall.Import +benchNfExprFromText :: String -> Text -> Benchmark+benchNfExprFromText name !expr =+ bench name $ nf (either throw id . Dhall.exprFromText "(input)") expr+ main :: IO () main = do prelude <- loadPreludeFiles- issue108Text <- TIO.readFile "benchmark/examples/issue108.dhall"- issue108Bytes <- Data.ByteString.Lazy.readFile "benchmark/examples/issue108.dhall.bin" defaultMain- [ bgroup "Issue #108"- [ benchExprFromText "Text" issue108Text- , benchExprFromBytes "Binary" issue108Bytes- ]- , benchExprFromText "Long variable names" (T.replicate 1000000 "x")- , benchExprFromText "Large number of function arguments" (T.replicate 10000 "x ")- , benchExprFromText "Long double-quoted strings" ("\"" <> T.replicate 1000000 "x" <> "\"")- , benchExprFromText "Long single-quoted strings" ("''" <> T.replicate 1000000 "x" <> "''")- , benchExprFromText "Whitespace" (T.replicate 1000000 " " <> "x")- , benchExprFromText "Line comment" ("x -- " <> T.replicate 1000000 " ")- , benchExprFromText "Block comment" ("x {- " <> T.replicate 1000000 " " <> "-}")+ [ env issues $ \ ~(it, ib) ->+ bgroup "Issue #108"+ [ benchExprFromText "Text" it+ , benchExprFromBytes "Binary" ib+ ]+ , env kubernetesExample $+ benchExprFromBytes "Kubernetes/Binary"+ , benchExprFromText "Long variable names" (Text.replicate 1000000 "x")+ , benchExprFromText "Large number of function arguments" (Text.replicate 10000 "x ")+ , benchExprFromText "Long double-quoted strings" ("\"" <> Text.replicate 1000000 "x" <> "\"")+ , benchExprFromText "Long single-quoted strings" ("''" <> Text.replicate 1000000 "x" <> "''")+ , benchExprFromText "Whitespace" (Text.replicate 1000000 " " <> "x")+ , benchExprFromText "Line comment" ("x -- " <> Text.replicate 1000000 " ")+ , benchExprFromText "Block comment" ("x {- " <> Text.replicate 1000000 " " <> "-}") , benchExprFromText "Deeply nested parentheses" "((((((((((((((((x))))))))))))))))" , benchParser prelude+ , env cpkgExample $+ benchNfExprFromText "CPkg/Text" ]+ where+ cpkgExample = Data.Text.IO.readFile "benchmark/parser/examples/cpkg.dhall"+ issue108Text = Data.Text.IO.readFile "benchmark/parser/examples/issue108.dhall"+ issue108Bytes = Data.ByteString.Lazy.readFile "benchmark/parser/examples/issue108.dhallb"+ issues = (,) <$> issue108Text <*> issue108Bytes+ kubernetesExample = Data.ByteString.Lazy.readFile "benchmark/parser/examples/kubernetes.dhallb"
file too large to diff
@@ -0,0 +1,63 @@+λ ( xs : List { cores : Natural , host : Text , key : Text , mandatoryFeatures :+List Text , platforms : List < AArch64_Linux : {} | ARMv5tel_Linux : {} |+ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} |+PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD :+{} | X86_64_Linux : {} | X86_64_Solaris : {} > , speedFactor : Natural ,+supportedFeatures : List Text , user : Optional Text } )→ List/fold { cores :+Natural , host : Text , key : Text , mandatoryFeatures : List Text , platforms :+List < AArch64_Linux : {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} |+I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | PowerPC_Linux : {} |+X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux :+{} | X86_64_Solaris : {} > , speedFactor : Natural , supportedFeatures : List+Text , user : Optional Text } xs Text ( λ ( x : { cores : Natural , host : Text+, key : Text , mandatoryFeatures : List Text , platforms : List < AArch64_Linux+: {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux :+{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} |+X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris :+{} > , speedFactor : Natural , supportedFeatures : List Text , user : Optional+Text } ) → λ(y : Text) →+merge { None = x.host, Some = λ(user : Text) → "${user}@${x.host}" } x.user+++ " " ++ ( merge { Empty = λ(_ : {}) → "",+NonEmpty = λ(result : Text) → result } ( List/fold < AArch64_Linux : {} |+ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} |+MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin :+{} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : {} > x.platforms+< Empty : {} | NonEmpty : Text > ( λ ( element : < AArch64_Linux : {} |+ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} |+MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin :+{} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : {} > ) →+λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = λ(_ : {}) → <+NonEmpty : Text | Empty : {} >.NonEmpty ( merge { AArch64_Linux = λ(_ : {}) →+"aarch64-linux" , ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux" , ARMv7l_Linux =+λ(_ : {}) → "armv7l-linux" , I686_Cygwin = λ(_ : {}) → "i686-cygwin" ,+I686_Linux = λ(_ : {}) → "i686-linux" , MIPS64el_Linux = λ(_ : {}) →+"mips64el-linux" , PowerPC_Linux = λ(_ : {}) → "powerpc-linux" , X86_64_Cygwin =+λ(_ : {}) → "x86_64-cygwin" , X86_64_Darwin = λ(_ : {}) → "x86_64-darwin" ,+X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd" , X86_64_Linux = λ(_ : {}) →+"x86_64-linux" , X86_64_Solaris = λ(_ : {}) → "x86_64-solaris" } element ) ,+NonEmpty = λ(result : Text) → < NonEmpty : Text | Empty : {} >.NonEmpty ( (+merge { AArch64_Linux = λ(_ : {}) → "aarch64-linux" , ARMv5tel_Linux = λ(_ : {})+→ "armv5tel-linux" , ARMv7l_Linux = λ(_ : {}) → "armv7l-linux" , I686_Cygwin =+λ(_ : {}) → "i686-cygwin" , I686_Linux = λ(_ : {}) → "i686-linux" ,+MIPS64el_Linux = λ(_ : {}) → "mips64el-linux" , PowerPC_Linux = λ(_ : {}) →+"powerpc-linux" , X86_64_Cygwin = λ(_ : {}) → "x86_64-cygwin" , X86_64_Darwin =+λ(_ : {}) → "x86_64-darwin" , X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd" ,+X86_64_Linux = λ(_ : {}) → "x86_64-linux" , X86_64_Solaris = λ(_ : {}) →+"x86_64-solaris" } element ) ++ "," ++ result ) } status : < Empty : {} |+NonEmpty : Text > ) (< Empty : {} | NonEmpty : Text >.Empty {=}) ) : Text ) +++" " ++ x.key ++ " " ++ Integer/show (Natural/toInteger x.cores) ++ " " +++Integer/show (Natural/toInteger x.speedFactor) ++ " " ++ ( merge { Empty = λ(_ :+{}) → "", NonEmpty = λ(result : Text) → result } ( List/fold Text+x.supportedFeatures < Empty : {} | NonEmpty : Text > ( λ(element : Text) →+λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = λ(_ : {}) → <+NonEmpty : Text | Empty : {} >.NonEmpty element , NonEmpty = λ(result : Text) →+< NonEmpty : Text | Empty : {} >.NonEmpty (element ++ "," ++ result) } status :+< Empty : {} | NonEmpty : Text > ) (< Empty : {} | NonEmpty : Text >.Empty {=})+) : Text ) ++ " " ++ ( merge { Empty = λ(_ : {}) → "", NonEmpty = λ(result :+Text) → result } ( List/fold Text x.mandatoryFeatures < Empty : {} | NonEmpty :+Text > ( λ(element : Text) → λ(status : < Empty : {} | NonEmpty : Text >) →+merge { Empty = λ(_ : {}) → < NonEmpty : Text | Empty : {} >.NonEmpty element ,+NonEmpty = λ(result : Text) → < NonEmpty : Text | Empty : {} >.NonEmpty+(element ++ "," ++ result) } status : < Empty : {} | NonEmpty : Text > ) (<+Empty : {} | NonEmpty : Text+>.Empty {=}) ) : Text ) ++ "\n" ++ y ) ""
binary file changed (absent → 3818 bytes)
file too large to diff
@@ -0,0 +1,22 @@++let Nat = ∀(N : Type) → (N → N) → N → N+let n2 = λ(N : Type) → λ(s : N → N) → λ(z : N) → s (s z)+let n5 = λ(N : Type) → λ(s : N → N) → λ(z : N) → s (s (s (s (s z))))++let mul =+ λ(a : Nat) → λ(b : Nat) → λ(N : Type) → λ(s : N → N) → λ(z : N) → a N (b N s) z++let add =+ λ(a : Nat) → λ(b : Nat) → λ(N : Type) → λ(s : N → N) → λ(z : N) → a N s (b N s z)++let n10 = mul n2 n5+let n100 = mul n10 n10+let n1k = mul n10 n100+let n10k = mul n100 n100+let n100k = mul n10 n10k+let n1M = mul n10k n100+let n5M = mul n1M n5+let n10M = mul n1M n10+let n20M = mul n10M n2++in n1M Natural (λ (x:Natural) → x + 1) 0
@@ -0,0 +1,18 @@++let compose+ : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c+ = λ(A : Type)+ → λ(B : Type)+ → λ(C : Type)+ → λ(f : A → B)+ → λ(g : B → C)+ → λ(x : A)+ → g (f x)++let composeN : ∀ (a : Type) → Natural → (a → a) → a → a+ = λ (a : Type)+ → λ (n : Natural)+ → λ (f : a → a)+ → Natural/fold n (a → a) (compose a a a f) (λ (x : a) → x)++in composeN Natural 100000 (λ (x : Natural) → x + 1) 0
@@ -0,0 +1,75 @@++let iterate+ = λ(n : Natural)+ → λ(a : Type)+ → λ(f : a → a)+ → λ(x : a)+ → List/build+ a+ ( λ(list : Type)+ → λ(cons : a → list → list)+ → List/fold+ { index : Natural, value : {} }+ ( List/indexed+ {}+ ( List/build+ {}+ ( λ(list : Type)+ → λ(cons : {} → list → list)+ → Natural/fold n list (cons {=})+ )+ )+ )+ list+ ( λ(y : { index : Natural, value : {} })+ → cons (Natural/fold y.index a f x)+ )+ )++let countTo =+ λ (x : Natural)+ → iterate x Natural (λ (x : Natural) → x + 1) 0++let sum =+ λ (xs : List Natural)+ → List/fold Natural xs Natural (λ (x : Natural) → λ (acc : Natural) → x + acc) 0+++let map+ : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b+ = λ(a : Type)+ → λ(b : Type)+ → λ(f : a → b)+ → λ(xs : List a)+ → List/build+ b+ ( λ(list : Type)+ → λ(cons : b → list → list)+ → List/fold a xs list (λ(x : a) → cons (f x))+ )++let any+ : ∀(a : Type) → (a → Bool) → List a → Bool+ = λ(a : Type)+ → λ(f : a → Bool)+ → λ(xs : List a)+ → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False++let filter+ : ∀(a : Type) → (a → Bool) → List a → List a+ = λ(a : Type)+ → λ(f : a → Bool)+ → λ(xs : List a)+ → List/build+ a+ ( λ(list : Type)+ → λ(cons : a → list → list)+ → List/fold+ a+ xs+ list+ (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)+ )++in sum (filter Natural Natural/even+ (map Natural Natural (λ(x:Natural) → x + 10) (countTo 1000)))
@@ -0,0 +1,45 @@++let iterate =+ λ(n : Natural)+ → λ(a : Type)+ → λ(f : a → a)+ → λ(x : a)+ → (Natural/fold n+ (a → List a → {fst:a, snd:List a})+ (λ (hyp : a → List a → {fst:a, snd:List a}) →+ λ (x : a) → λ (xs : List a)+ → let tup = hyp x xs+ in {fst = f (tup.fst), snd = tup.snd # [tup.fst]})+ (λ (x : a) → λ (xs : List a) → {fst=x, snd=xs})+ x ([] : List a)).snd++let countTo =+ λ (x : Natural)+ → iterate x Natural (λ (x : Natural) → x + 1) 0++let sum =+ λ (xs : List Natural)+ → List/fold Natural xs Natural (λ (x : Natural) → λ (acc : Natural) → x + acc) 0++let map+ = λ(a : Type)+ → λ(b : Type)+ → λ(f : a → b)+ → λ(xs : List a)+ → List/fold a xs (List b) (λ (x : a) → λ (xs : List b) → [f x] # xs) ([] : List b)++let any+ = λ(a : Type)+ → λ(f : a → Bool)+ → λ(xs : List a)+ → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False++let filter+ = λ(a : Type)+ → λ(f : a → Bool)+ → λ(xs : List a)+ → List/fold a xs (List a)+ (λ (x : a) → λ (xs : List a) → if f x then [x] # xs else xs) ([] : List a)++in sum (filter Natural Natural/even+ (map Natural Natural (λ(x:Natural) → x + 10) (countTo 1000)))
@@ -1,18 +1,3 @@-{--The `and` function returns `False` if there are any `False` elements in the-`List` and returns `True` otherwise--Examples:--```-./and [ True, False, True ] = False--./and ([] : List Bool) = True-```--}-let and- : List Bool → Bool- = λ(xs : List Bool)- → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) True--in and+ missing+ sha256:0b2114fa33cd76652e4360f012bc082718944fe4c5b28c975483178f8d9b0a6d+? ./and.dhall
@@ -0,0 +1,14 @@+{-|+The `and` function returns `False` if there are any `False` elements in the+`List` and returns `True` otherwise+-}+let and+ : List Bool → Bool+ = λ(xs : List Bool) →+ List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) True++let example0 = assert : and [ True, False, True ] ≡ False++let example1 = assert : and ([] : List Bool) ≡ True++in and
@@ -1,17 +1,3 @@-{--`build` is the inverse of `fold`--Examples:--```-./build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → true) = True--./build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → false) = False-```--}-let build- : (∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool- = λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool)- → f Bool True False--in build+ missing+ sha256:add7cb9acacac705410088d876a7e4488e046a7aded304f06c51accffd7f1b7b+? ./build.dhall
@@ -0,0 +1,16 @@+--| `build` is the inverse of `fold`+let build+ : (∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool+ = λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) →+ f Bool True False++let example0 =+ assert+ : build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → true) ≡ True++let example1 =+ assert+ : build (λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)+ ≡ False++in build
@@ -0,0 +1,6 @@+--| Returns `True` if both arguments are equal and returns `False` otherwise+let equal+ : Bool -> Bool -> Bool+ = \(x : Bool) -> \(y : Bool) -> x == y++in equal
@@ -1,22 +1,3 @@-{--Returns `True` if there are an even number of `False` elements in the list and-returns `False` otherwise--Examples:--```-./even [ False, True, False ] = True--./even [ False, True ] = False--./even [ False ] = False--./even ([] : List Bool) = True-```--}-let even- : List Bool → Bool- = λ(xs : List Bool)- → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True--in even+ missing+ sha256:72a05ee550636a3acb768360fa51ba0db0326763e0cf1ceb737f0f3607fc0fe5+? ./even.dhall
@@ -0,0 +1,20 @@+{-|+Returns `True` if there are an even number of `False` elements in the list and+returns `False` otherwise.++This function is the `Monoid` for the `==` operation.+-}+let even+ : List Bool → Bool+ = λ(xs : List Bool) →+ List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True++let example0 = assert : even [ False, True, False ] ≡ True++let example1 = assert : even [ False, True ] ≡ False++let example2 = assert : even [ False ] ≡ False++let example3 = assert : even ([] : List Bool) ≡ True++in even
@@ -1,20 +1,3 @@-{--`fold` is essentially the same as `if`/`then`/else` except as a function--Examples:--```-./fold True Natural 0 1 = 0--./fold False Natural 0 1 = 1-```--}-let fold- : ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool- = λ(b : Bool)- → λ(bool : Type)- → λ(true : bool)- → λ(false : bool)- → if b then true else false--in fold+ missing+ sha256:39f60baf3950268c2e849e91dc6279ee41cd6b81892d54020d4fcd2ce30a96ae+? ./fold.dhall
@@ -0,0 +1,14 @@+--| `fold` is essentially the same as `if`/`then`/`else` except as a function+let fold+ : ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool+ = λ(b : Bool) →+ λ(bool : Type) →+ λ(true : bool) →+ λ(false : bool) →+ if b then true else false++let example0 = assert : fold True Natural 0 1 ≡ 0++let example1 = assert : fold False Natural 0 1 ≡ 1++in fold
@@ -1,12 +1,3 @@-{--Flip the value of a `Bool`--Examples:--```-./not True = False--./not False = True-```--}-let not : Bool → Bool = λ(b : Bool) → b == False in not+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+? ./not.dhall
@@ -0,0 +1,10 @@+--| Flip the value of a `Bool`+let not+ : Bool → Bool+ = λ(b : Bool) → b == False++let example0 = assert : not True ≡ False++let example1 = assert : not False ≡ True++in not
@@ -1,22 +1,3 @@-{--Returns `True` if there are an odd number of `True` elements in the list and-returns `False` otherwise--Examples:--```-./odd [ True, False, True ] = False--./odd [ True, False ] = True--./odd [ True ] = True--./odd ([] : List Bool) = False-```--}-let odd- : List Bool → Bool- = λ(xs : List Bool)- → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False--in odd+ missing+ sha256:6360fca3a745de32bd186cc7b71487a6398cd47d5119064eae491872c41d1999+? ./odd.dhall
@@ -0,0 +1,20 @@+{-|+Returns `True` if there are an odd number of `True` elements in the list and+returns `False` otherwise.++This function is the `Monoid` for the `!=` operation.+-}+let odd+ : List Bool → Bool+ = λ(xs : List Bool) →+ List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False++let example0 = assert : odd [ True, False, True ] ≡ False++let example1 = assert : odd [ True, False ] ≡ True++let example2 = assert : odd [ True ] ≡ True++let example3 = assert : odd ([] : List Bool) ≡ False++in odd
@@ -1,18 +1,3 @@-{--The `or` function returns `True` if there are any `True` elements in the `List`-and returns `False` otherwise--Examples:--```-./or [ True, False, True ] = True--./or ([] : List Bool) = False-```--}-let or- : List Bool → Bool- = λ(xs : List Bool)- → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False--in or+ missing+ sha256:5c50738e84e1c4fed8343ebd57608500e1b61ac1f502aa52d6d6edb5c20b99e4+? ./or.dhall
@@ -0,0 +1,14 @@+{-|+The `or` function returns `True` if there are any `True` elements in the `List`+and returns `False` otherwise+-}+let or+ : List Bool → Bool+ = λ(xs : List Bool) →+ List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False++let example0 = assert : or [ True, False, True ] ≡ True++let example1 = assert : or ([] : List Bool) ≡ False++in or
@@ -1,25 +1,37 @@ { and =- ./and sha256:0b2114fa33cd76652e4360f012bc082718944fe4c5b28c975483178f8d9b0a6d- ? ./and+ missing+ sha256:0b2114fa33cd76652e4360f012bc082718944fe4c5b28c975483178f8d9b0a6d+ ? ./and.dhall , build =- ./build sha256:add7cb9acacac705410088d876a7e4488e046a7aded304f06c51accffd7f1b7b- ? ./build+ missing+ sha256:add7cb9acacac705410088d876a7e4488e046a7aded304f06c51accffd7f1b7b+ ? ./build.dhall+, equal =+ missing+ sha256:f0dc047ca14644c2a979bb126f2a3c6659ec770c66bd7beb70ae4a9d05815709+ ? ./equal.dhall , even =- ./even sha256:72a05ee550636a3acb768360fa51ba0db0326763e0cf1ceb737f0f3607fc0fe5- ? ./even+ missing+ sha256:72a05ee550636a3acb768360fa51ba0db0326763e0cf1ceb737f0f3607fc0fe5+ ? ./even.dhall , fold =- ./fold sha256:39f60baf3950268c2e849e91dc6279ee41cd6b81892d54020d4fcd2ce30a96ae- ? ./fold+ missing+ sha256:39f60baf3950268c2e849e91dc6279ee41cd6b81892d54020d4fcd2ce30a96ae+ ? ./fold.dhall , not =- ./not sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4- ? ./not+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+ ? ./not.dhall , odd =- ./odd sha256:6360fca3a745de32bd186cc7b71487a6398cd47d5119064eae491872c41d1999- ? ./odd+ missing+ sha256:6360fca3a745de32bd186cc7b71487a6398cd47d5119064eae491872c41d1999+ ? ./odd.dhall , or =- ./or sha256:5c50738e84e1c4fed8343ebd57608500e1b61ac1f502aa52d6d6edb5c20b99e4- ? ./or+ missing+ sha256:5c50738e84e1c4fed8343ebd57608500e1b61ac1f502aa52d6d6edb5c20b99e4+ ? ./or.dhall , show =- ./show sha256:f85f6d2d921c37a2122cb2e2f8a0170e305b699debd0e6df5ef3370d806b5f61- ? ./show+ missing+ sha256:f85f6d2d921c37a2122cb2e2f8a0170e305b699debd0e6df5ef3370d806b5f61+ ? ./show.dhall }
@@ -1,13 +1,3 @@-{--Render a `Bool` as `Text` using the same representation as Dhall source code-(i.e. beginning with a capital letter)--Examples:--```-./show True = "True"--./show False = "False"-```--}-let show : Bool → Text = λ(b : Bool) → if b then "True" else "False" in show+ missing+ sha256:f85f6d2d921c37a2122cb2e2f8a0170e305b699debd0e6df5ef3370d806b5f61+? ./show.dhall
@@ -0,0 +1,13 @@+{-|+Render a `Bool` as `Text` using the same representation as Dhall source code+(i.e. beginning with a capital letter)+-}+let show+ : Bool → Text+ = λ(b : Bool) → if b then "True" else "False"++let example0 = assert : show True ≡ "True"++let example1 = assert : show False ≡ "False"++in show
@@ -0,0 +1,5 @@+{ show =+ missing+ sha256:8a0eb9732cbc3c8f161b7cb05b183493befacc4728d2d9b7ee1384f19106a5ff+ ? ./show.dhall+}
@@ -0,0 +1,15 @@+{-+Render a `Date` as `Text` using the same representation as Dhall source code+(i.e. `YYYY-MM-DD`)+-}+let show+ : Date → Text+ = Date/show++let example0 = assert : show 2000-09-02 ≡ "2000-09-02"++let example1 = assert : show 9999-12-31 ≡ "9999-12-31"++let example2 = assert : show 0000-01-01 ≡ "0000-01-01"++in show
@@ -0,0 +1,5 @@+{-|+A (total) set of access rights; See chmod(5) for an explanation of the flags.+For a partial set of of access rights see `Access`.+-}+{ execute : Bool, read : Bool, write : Bool }
@@ -0,0 +1,69 @@+{-|+@intersect a b@ intesects the flags of the two `Mask`s @a@ and @b@. This+resembles the bitwise "and", i.e. the value of a flag is 'True' if and only if+it is set to 'True' in both @a@ and @b@. As a consequence @intersect a rwx == a@+and @intersect a none == none@ for all @a@.+-}+let Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall++let intersect+ : Mask -> Mask -> Mask+ = \(m1 : Mask) ->+ \(m2 : Mask) ->+ { read = m1.read && m2.read+ , write = m1.write && m2.write+ , execute = m1.execute && m2.execute+ }++let example0 =+ let r =+ missing+ sha256:26d7fc8df6194a8051946eac88d0d7fecce690bff6819e69b3c74edf65ac027a+ ? ./r.dhall++ let w =+ missing+ sha256:9d10dfc672f61bbb2828c7be2121aae2502938c25adb47bb8cce3c40ba99821b+ ? ./w.dhall++ let x =+ missing+ sha256:a966fd88c05a5912a6daa8409e0c9e396f0a4810b51def1e1f62a95e18235f10+ ? ./x.dhall++ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ in assert : intersect r (intersect w (intersect x rwx)) === none++let example1 =+ \(a : Mask) ->+ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ in assert+ : intersect a rwx+ === { execute = a.execute, read = a.read, write = a.write }++let example2 =+ \(a : Mask) ->+ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ in assert : intersect a none === none++in intersect
@@ -0,0 +1,48 @@+{-|+Inverts the flags set in a `Mask`.+-}+let Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall++let Bool/not =+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+ ? ../../../Bool/not.dhall++let invert+ : Mask -> Mask+ = \(m : Mask) ->+ { read = Bool/not m.read+ , write = Bool/not m.write+ , execute = Bool/not m.execute+ }++let example0 =+ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ in assert : invert rwx === none++let example1 =+ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ in assert : invert none === rwx++in invert
@@ -0,0 +1,4 @@+ { read = False, write = False, execute = False }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,53 @@+{ Type =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall+, intersect =+ missing+ sha256:7c7dab3e305f43cba556e0778b5a797cf8e9b1d1a6c6f6fe0ea311c329919663+ ? ./intersect.dhall+, invert =+ missing+ sha256:8807fb02f694fe2117f8a7f794e5afbb967ec36eac3405184bf9232c33cdd830+ ? ./invert.dhall+, none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall+, r =+ missing+ sha256:26d7fc8df6194a8051946eac88d0d7fecce690bff6819e69b3c74edf65ac027a+ ? ./r.dhall+, rw =+ missing+ sha256:c3cce19f462b841e64adafbdf2963699a0031f5fc08b041c8ad364483c544d8b+ ? ./rw.dhall+, rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall+, rx =+ missing+ sha256:d9beaa853c0de6984c3e5b0e313b573942900f8024fd9aaad743d73df458dc5e+ ? ./rx.dhall+, toAccess =+ missing+ sha256:78fe016f0273b2551c8590da71bf204cc26d6879c6b84622d4d8ad5624328438+ ? ./toAccess.dhall+, toAccessWith =+ missing+ sha256:814ab74ad292c121620a1f468837d4a5473323423bf68c1bceca69e7b3c59077+ ? ./toAccessWith.dhall+, union =+ missing+ sha256:b40c4cbb266991e3f764af075e9db544b59c16b3d9aa680c0cf6cb7552da191f+ ? ./union.dhall+, w =+ missing+ sha256:9d10dfc672f61bbb2828c7be2121aae2502938c25adb47bb8cce3c40ba99821b+ ? ./w.dhall+, x =+ missing+ sha256:a966fd88c05a5912a6daa8409e0c9e396f0a4810b51def1e1f62a95e18235f10+ ? ./x.dhall+}
@@ -0,0 +1,4 @@+ { read = True, write = False, execute = False }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,4 @@+ { read = True, write = True, execute = False }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,4 @@+ { read = True, write = True, execute = True }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,4 @@+ { read = True, write = False, execute = True }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,20 @@+{-|+Convert a `Mask` value to an `Access` value. For a partial conversion see+`toAccessWith`.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../Type.dhall++let Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall++let toAccess+ : Mask -> Access+ = \(m : Mask) ->+ { execute = Some m.execute, read = Some m.read, write = Some m.write }++in toAccess
@@ -0,0 +1,42 @@+{-|+@toAccessWith x m@ converts some fields of a `Mask` @m@ to an `Access` setting:+If the respective field is set in the first `Mask` @x@, then the flag will be+set to the flags value given in @m@. Otherwise, the value set in @m@ is ignored+and the value of the flag in the result is `None`.++For a motivation of this function see the documenation on `toModeWith`.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../Type.dhall++let Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall++let toAccessWith+ : Mask -> Mask -> Access+ = \(set : Mask) ->+ \(m : Mask) ->+ { execute = if set.execute then Some m.execute else None Bool+ , read = if set.read then Some m.read else None Bool+ , write = if set.write then Some m.write else None Bool+ }++let example0 =+ \(a : Mask) ->+ let Access/none =+ missing+ sha256:955a2eed689139c811d4b9ef3dd8d0c484392b18c3bb8752c59fd69dbdaf4881+ ? ../none.dhall++ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ in assert : toAccessWith none a === Access/none++in toAccessWith
@@ -0,0 +1,64 @@+{-|+@union a b@ combines the flags of the two `Mask`s @a@ and @b@. This resembles+the bitwise "or", i.e. the value of a flag is 'True' if it is set to 'True' in+either @a@ and @b@. As a consequence @union a rwx == rwx@ and+@union a none == a@ for all @a@.+-}+let Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall++let union+ : Mask -> Mask -> Mask+ = \(m1 : Mask) ->+ \(m2 : Mask) ->+ { read = m1.read || m2.read+ , write = m1.write || m2.write+ , execute = m1.execute || m2.execute+ }++let example0 =+ let r =+ missing+ sha256:26d7fc8df6194a8051946eac88d0d7fecce690bff6819e69b3c74edf65ac027a+ ? ./r.dhall++ let w =+ missing+ sha256:9d10dfc672f61bbb2828c7be2121aae2502938c25adb47bb8cce3c40ba99821b+ ? ./w.dhall++ let x =+ missing+ sha256:a966fd88c05a5912a6daa8409e0c9e396f0a4810b51def1e1f62a95e18235f10+ ? ./x.dhall++ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ in assert : union r (union w x) === rwx++let example1 =+ \(a : Mask) ->+ let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ./rwx.dhall++ in assert : union a rwx === rwx++let example1 =+ \(a : Mask) ->+ let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ./none.dhall++ in assert+ : union a none+ === { execute = a.execute, read = a.read, write = a.write }++in union
@@ -0,0 +1,4 @@+ { read = False, write = True, execute = False }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,4 @@+ { read = False, write = False, execute = True }+: missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ./Type.dhall
@@ -0,0 +1,5 @@+{-|+A (partial) set of access rights; See chmod(5) for an explanation of the flags.+For a total set of access rights see `Mask`.+-}+{ execute : Optional Bool, read : Optional Bool, write : Optional Bool }
@@ -0,0 +1,29 @@+{-|+`equal` checks if two `Access` settings are equal.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ./Type.dhall++let Bool/equal =+ missing+ sha256:f0dc047ca14644c2a979bb126f2a3c6659ec770c66bd7beb70ae4a9d05815709+ ? ../../Bool/equal.dhall++let Optional/equal =+ missing+ sha256:5411888399fe9c6720f7f3b59caf5eff3e8e8c30402d09f34e46a4457649a35a+ ? ../../Optional/equal.dhall++let f+ : Optional Bool -> Optional Bool -> Bool+ = Optional/equal Bool Bool/equal++let equal+ : Access -> Access -> Bool+ = \(a1 : Access) ->+ \(a2 : Access) ->+ f a1.execute a2.execute && f a1.read a2.read && f a1.write a2.write++in equal
@@ -0,0 +1,4 @@+ { read = None Bool, write = None Bool, execute = None Bool }+: missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ./Type.dhall
@@ -0,0 +1,17 @@+{ Mask =+ missing+ sha256:ed736de51ea15a2ef671eaa7219dfbf3138bb52acfd0ae17894acf2ec4b06369+ ? ./Mask/package.dhall+, Type =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ./Type.dhall+, equal =+ missing+ sha256:5fa90f55505780a7be942275d6bbb2b1f1fb7857364332ed732a0241c2165e53+ ? ./equal.dhall+, schema =+ missing+ sha256:7d33a584a42a5d92411d5ca623e27ccb397762905be86ecfd01b106719fae690+ ? ./schema.dhall+}
@@ -0,0 +1,12 @@+{-|+A schema for blank access rights.+-}+{ Type =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ./Type.dhall+, default =+ missing+ sha256:955a2eed689139c811d4b9ef3dd8d0c484392b18c3bb8752c59fd69dbdaf4881+ ? ./none.dhall+}
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:75148ae19175750e38705e11cda8dcc775b2ac08f22518ff2ef3f33a6273ef15+ ? ./Type.dhall++in Entry Bytes
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:75148ae19175750e38705e11cda8dcc775b2ac08f22518ff2ef3f33a6273ef15+ ? ./Type.dhall++in \(tree : Type) -> Entry (List tree)
@@ -0,0 +1,24 @@+{-|+An `Entry` without content. That in turn implies that the type of the entry+(i.e. whether it is a file or a directory) is not (yet) fixed as well.+-}+let User =+ missing+ sha256:8b25916612d2c9b17130d16b55c6bdb085dd118e692f72bf351a83b1d0ac8833+ ? ../User/Type.dhall++let Group =+ missing+ sha256:83e6e8846153d94abf6f879808c94f5cdba3f486cc9e392eb6124b1dc67368cf+ ? ../Group/Type.dhall++let Mode =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ../Mode/Type.dhall++in { name : Text+ , user : Optional User+ , group : Optional Group+ , mode : Optional Mode+ }
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:75148ae19175750e38705e11cda8dcc775b2ac08f22518ff2ef3f33a6273ef15+ ? ./Type.dhall++in Entry Text
@@ -0,0 +1,6 @@+let Metadata =+ missing+ sha256:8c240a00094238a73904af63ac0924b3e6aba1655312f20a2a27f88554e2febe+ ? ./Metadata.dhall++in \(content : Type) -> Metadata //\\ { content : content }
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:742610b2a13e55ae6e344b54aa8a7ee1bfec8e8b313a1132eae9286309b520e6+ ? ./entry.dhall++in Entry Bytes
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:742610b2a13e55ae6e344b54aa8a7ee1bfec8e8b313a1132eae9286309b520e6+ ? ./entry.dhall++in \(tree : Type) -> Entry (List tree)
@@ -0,0 +1,24 @@+let Entry =+ missing+ sha256:75148ae19175750e38705e11cda8dcc775b2ac08f22518ff2ef3f33a6273ef15+ ? ./Type.dhall++let User =+ missing+ sha256:8b25916612d2c9b17130d16b55c6bdb085dd118e692f72bf351a83b1d0ac8833+ ? ../User/Type.dhall++let Group =+ missing+ sha256:83e6e8846153d94abf6f879808c94f5cdba3f486cc9e392eb6124b1dc67368cf+ ? ../Group/Type.dhall++let Mode =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ../Mode/Type.dhall++in \(content : Type) ->+ { Type = Entry content+ , default = { user = None User, group = None Group, mode = None Mode }+ }
@@ -0,0 +1,37 @@+{ BinaryFileEntry =+ missing+ sha256:f027db2893f6f38bbe6d868a91f22de530e85407237f00b147427c87d32bf55c+ ? ./BinaryFileEntry.dhall+, DirectoryEntry =+ missing+ sha256:163a4536fdd05ce122d793ceda01d03fcffb29463817ae8b7b5601bf4a06ce6e+ ? ./DirectoryEntry.dhall+, Metadata =+ missing+ sha256:8c240a00094238a73904af63ac0924b3e6aba1655312f20a2a27f88554e2febe+ ? ./Metadata.dhall+, TextFileEntry =+ missing+ sha256:23a8cb29d96aeb623501519d9a62c5c49659e8d1c30b4ae4f2399809e3fd3a01+ ? ./TextFileEntry.dhall+, Type =+ missing+ sha256:75148ae19175750e38705e11cda8dcc775b2ac08f22518ff2ef3f33a6273ef15+ ? ./Type.dhall+, binary-file =+ missing+ sha256:bd49df43268c259e3d0bef995917c3ab517ae7b98bf1faac8f4a7e8a602e3465+ ? ./binary-file.dhall+, directory =+ missing+ sha256:0bee17310a21efa5b06f139b6731fdcee4f9e0245ef711c2b0127b8938dfed2e+ ? ./directory.dhall+, entry =+ missing+ sha256:742610b2a13e55ae6e344b54aa8a7ee1bfec8e8b313a1132eae9286309b520e6+ ? ./entry.dhall+, text-file =+ missing+ sha256:c5d76fd43216668d03df9945183fe7b3c55486aedcc77324c3372bd63e283b78+ ? ./text-file.dhall+}
@@ -0,0 +1,6 @@+let Entry =+ missing+ sha256:742610b2a13e55ae6e344b54aa8a7ee1bfec8e8b313a1132eae9286309b520e6+ ? ./entry.dhall++in Entry Text
@@ -0,0 +1,1 @@+< GroupId : Natural | GroupName : Text >
@@ -0,0 +1,6 @@+let Group =+ missing+ sha256:83e6e8846153d94abf6f879808c94f5cdba3f486cc9e392eb6124b1dc67368cf+ ? ./Type.dhall++in Group.GroupId
@@ -0,0 +1,6 @@+let Group =+ missing+ sha256:83e6e8846153d94abf6f879808c94f5cdba3f486cc9e392eb6124b1dc67368cf+ ? ./Type.dhall++in Group.GroupName
@@ -0,0 +1,13 @@+{ Type =+ missing+ sha256:83e6e8846153d94abf6f879808c94f5cdba3f486cc9e392eb6124b1dc67368cf+ ? ./Type.dhall+, id =+ missing+ sha256:2bf9e546f56a583243d419a652caba16ca4053df9ccb3c5b242506d86806944b+ ? ./id.dhall+, name =+ missing+ sha256:51ac5c407f2939ab0c80bf2896d292ee6049bd8ba10acda0af327a3777f2205d+ ? ./name.dhall+}
@@ -0,0 +1,10 @@+{-|+A complete mode with all access rights specified explicitely. For an incomplete+mode where some access rights might not be set see `Mode`.+-}+let Access/Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ../../Access/Mask/Type.dhall++in { user : Access/Mask, group : Access/Mask, other : Access/Mask }
@@ -0,0 +1,9 @@+{-|+Permissions with all flags set: rwxrwxrwx+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++in { user = rwx, group = rwx, other = rwx }
@@ -0,0 +1,17 @@+{-|+Permissions commonly used for directories: rwxr-xr-x+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++let rx =+ missing+ sha256:d9beaa853c0de6984c3e5b0e313b573942900f8024fd9aaad743d73df458dc5e+ ? ../../Access/Mask/rx.dhall++in { user = rwx, group = rx, other = rx }+ : missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall
@@ -0,0 +1,17 @@+{-|+Permissions commonly used for executable files: rwxr-xr-x+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++let rx =+ missing+ sha256:d9beaa853c0de6984c3e5b0e313b573942900f8024fd9aaad743d73df458dc5e+ ? ../../Access/Mask/rx.dhall++in { user = rwx, group = rx, other = rx }+ : missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall
@@ -0,0 +1,17 @@+{-|+Permissions commonly used for regular files: rw-r--r--+-}+let r =+ missing+ sha256:26d7fc8df6194a8051946eac88d0d7fecce690bff6819e69b3c74edf65ac027a+ ? ../../Access/Mask/r.dhall++let rw =+ missing+ sha256:c3cce19f462b841e64adafbdf2963699a0031f5fc08b041c8ad364483c544d8b+ ? ../../Access/Mask/rw.dhall++in { user = rw, group = r, other = r }+ : missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall
@@ -0,0 +1,14 @@+{-|+Permissions with group flags set: ---rwx---+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ../../Access/Mask/none.dhall++in { user = none, group = rwx, other = none }
@@ -0,0 +1,24 @@+{-|+Calculates the intersection of the access rights of two `Mask`s using+`Access/intersect`.+-}+let Mask =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall++let Access/intersect =+ missing+ sha256:7c7dab3e305f43cba556e0778b5a797cf8e9b1d1a6c6f6fe0ea311c329919663+ ? ../../Access/Mask/intersect.dhall++let intersect+ : Mask -> Mask -> Mask+ = \(m1 : Mask) ->+ \(m2 : Mask) ->+ { user = Access/intersect m1.user m2.user+ , group = Access/intersect m1.group m2.group+ , other = Access/intersect m1.other m2.other+ }++in intersect
@@ -0,0 +1,22 @@+{-|+Inverts each access right set in a `Mask` using `Access/invert`.+-}+let Mask =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall++let Access/invert =+ missing+ sha256:8807fb02f694fe2117f8a7f794e5afbb967ec36eac3405184bf9232c33cdd830+ ? ../../Access/Mask/invert.dhall++let invert+ : Mask -> Mask+ = \(m : Mask) ->+ { user = Access/invert m.user+ , group = Access/invert m.group+ , other = Access/invert m.other+ }++in invert
@@ -0,0 +1,12 @@+{-|+Permissions with no flags set: ---------+-}+let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ../../Access/Mask/none.dhall++in { user = none, group = none, other = none }+ : missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall
@@ -0,0 +1,14 @@+{-|+Permissions with other flags set: ------rwx+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ../../Access/Mask/none.dhall++in { user = none, group = none, other = rwx }
@@ -0,0 +1,41 @@+{ Type =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall+, directory =+ missing+ sha256:a43f235f0caa25c7cabd89ac5d77e466e0c0ebf3339046993c18e481930243fd+ ? ./directory.dhall+, executable =+ missing+ sha256:a43f235f0caa25c7cabd89ac5d77e466e0c0ebf3339046993c18e481930243fd+ ? ./executable.dhall+, file =+ missing+ sha256:32d34228d48a707996272d1c9681171ddcd6651f72eeb3de9727d1c26ba99df3+ ? ./file.dhall+, intersect =+ missing+ sha256:146be962523ef619d3a250699f977b69c3e5f6c24b975453f351c0e807266fc8+ ? ./intersect.dhall+, invert =+ missing+ sha256:07a13d8c233d0a9fd6b3a11475987c10619072fec882c96bc5499bfb3c01e9b2+ ? ./invert.dhall+, none =+ missing+ sha256:7cac21e2b72cadf3ee0bf10680df4902ca73b6ee070219df5eac1a24cd66ccdf+ ? ./none.dhall+, toMode =+ missing+ sha256:af2b0dab799374afa0a2f28551446760ff29f4697c200da0a8b0a8def7feee2a+ ? ./toMode.dhall+, toModeWith =+ missing+ sha256:b92327bec9141cc1a55bc3f11ae2584af0883b94fe2513376fc40f1da5ade9b2+ ? ./toModeWith.dhall+, union =+ missing+ sha256:3bb32fc6ea21f661571e46d90e450e0340b2f2b65482ba7bd1a30514e1b39fc2+ ? ./union.dhall+}
@@ -0,0 +1,28 @@+{-|+Convert a `Mask` value to a `Mode` value. For a partial conversion see+`toModeWith`.+-}+let Mode =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ../Type.dhall++let Mask =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall++let Access/toAccess =+ missing+ sha256:78fe016f0273b2551c8590da71bf204cc26d6879c6b84622d4d8ad5624328438+ ? ../../Access/Mask/toAccess.dhall++let toMode+ : Mask -> Mode+ = \(m : Mask) ->+ { user = Some (Access/toAccess m.user)+ , group = Some (Access/toAccess m.group)+ , other = Some (Access/toAccess m.other)+ }++in toMode
@@ -0,0 +1,149 @@+{-|+@toModeWith x m@ converts some fields of a `Mask` @m@ to a `Mode`: If the+respective field is set in the first `Mask` @x@, then the flag will be set to+the flags value given in @m@. Otherwise, the value set in @m@ is ignored and the+value of the flag in the result is `None`.++The function is motivated by the following use case:+Alice has her umask set to 022 and new files will have permissions set to+rw-r--r--. Bob has the umask set to 077, hence newly created files will have+rw------- permissions. Now Eve distributes Dhall code writing a file with the+following mode to the filesystem:+```dhall+let mask = ./other.dhall++let permissions = ./all.dhall++in+toModeWith mask permissions+```+The written file will have rw-r--rwx permissions for Alice and rw----rwx+permissions for Bob as the `toModeWith mask` produces a `Mode` that will only+apply the permissions for the 'other' part.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../../Access/Type.dhall++let Access/Mask =+ missing+ sha256:c0fa7626b69e117086439a7b4ee15d1a80e16e38fe2ccc13f55e6dd26030b4df+ ? ../../Access/Mask/Type.dhall++let Mode =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ../Type.dhall++let Mask =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall++let Access/equal =+ missing+ sha256:5fa90f55505780a7be942275d6bbb2b1f1fb7857364332ed732a0241c2165e53+ ? ../../Access/equal.dhall++let Access/toAccessWith =+ missing+ sha256:814ab74ad292c121620a1f468837d4a5473323423bf68c1bceca69e7b3c59077+ ? ../../Access/Mask/toAccessWith.dhall++let f+ : Access/Mask -> Access/Mask -> Optional Access+ = \(set : Access/Mask) ->+ \(m : Access/Mask) ->+ let x = Access/toAccessWith set m++ in if Access/equal+ { execute = None Bool, read = None Bool, write = None Bool }+ x+ then None Access+ else Some x++let toModeWith+ : Mask -> Mask -> Mode+ = \(set : Mask) ->+ \(m : Mask) ->+ { user = f set.user m.user+ , group = f set.group m.group+ , other = f set.other m.other+ }++let example0 =+ \(a : Mask) ->+ let none =+ missing+ sha256:7cac21e2b72cadf3ee0bf10680df4902ca73b6ee070219df5eac1a24cd66ccdf+ ? ./none.dhall++ let Mode/none =+ missing+ sha256:0ed46da7e6acbdff9e4c9e27a9f2770075a7cd6cb6bb565765c62093df1b5563+ ? ../none.dhall++ in assert : toModeWith none a === Mode/none++let example1 =+ \(a : Mask) ->+ let toMode =+ missing+ sha256:af2b0dab799374afa0a2f28551446760ff29f4697c200da0a8b0a8def7feee2a+ ? ./toMode.dhall++ let all =+ missing+ sha256:758415eca8dfee675dfef93ace9af82abb36bb3319b8e6295537ed18f9b5d3dd+ ? ./all.dhall++ in assert : toModeWith all a === toMode a++let example2 =+ let mask =+ missing+ sha256:94bf82678d8d1c4f370a96f3831d3ad4464fbee508ffb37e93a479a1d9ee25cf+ ? ./other.dhall++ let permissions =+ missing+ sha256:758415eca8dfee675dfef93ace9af82abb36bb3319b8e6295537ed18f9b5d3dd+ ? ./all.dhall++ let rwx = { read = Some True, write = Some True, execute = Some True }++ in assert+ : toModeWith mask permissions+ === { user = None Access, group = None Access, other = Some rwx }++let example3 =+ let union =+ missing+ sha256:3bb32fc6ea21f661571e46d90e450e0340b2f2b65482ba7bd1a30514e1b39fc2+ ? ./union.dhall++ let group =+ missing+ sha256:faa567630372f77bb5cd2fa4fe7cb4760d2f9f79e35df80917e6e0064decf7cf+ ? ./group.dhall++ let other =+ missing+ sha256:94bf82678d8d1c4f370a96f3831d3ad4464fbee508ffb37e93a479a1d9ee25cf+ ? ./other.dhall++ let permissions =+ missing+ sha256:758415eca8dfee675dfef93ace9af82abb36bb3319b8e6295537ed18f9b5d3dd+ ? ./all.dhall++ let mask = union group other++ let rwx = { read = Some True, write = Some True, execute = Some True }++ in assert+ : toModeWith mask permissions+ === { user = None Access, group = Some rwx, other = Some rwx }++in toModeWith
@@ -0,0 +1,24 @@+{-|+Calculates the union of the access rights set by both `Mask`s using+`Access/union`.+-}+let Mask =+ missing+ sha256:4f97762058f24053e03997565a78800a5a2586159deaa265a4ee84a3d94ad471+ ? ./Type.dhall++let Access/union =+ missing+ sha256:b40c4cbb266991e3f764af075e9db544b59c16b3d9aa680c0cf6cb7552da191f+ ? ../../Access/Mask/union.dhall++let union+ : Mask -> Mask -> Mask+ = \(m1 : Mask) ->+ \(m2 : Mask) ->+ { user = Access/union m1.user m2.user+ , group = Access/union m1.group m2.group+ , other = Access/union m1.other m2.other+ }++in union
@@ -0,0 +1,14 @@+{-|+Permissions with all user flags set: rwx------+-}+let rwx =+ missing+ sha256:cafda16b1ecc0d2f9a63f3aab229a02e18aebb054283c73e50517f1e3727cd27+ ? ../../Access/Mask/rwx.dhall++let none =+ missing+ sha256:db6c3bb734bb3288441f2664379706052943eaba35c021326a600d41ca766925+ ? ../../Access/Mask/none.dhall++in { user = rwx, group = none, other = none }
@@ -0,0 +1,10 @@+{-|+An incomplete mode where some access rights might not be set explicitely. For a+complete mode with all access rights specified explicitely see `Mask`.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../Access/Type.dhall++in { user : Optional Access, group : Optional Access, other : Optional Access }
@@ -0,0 +1,34 @@+{-|+`equal` checks if two `Mode`s are equal.+-}+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../Access/Type.dhall++let Mode =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ./Type.dhall++let Access/equal =+ missing+ sha256:5fa90f55505780a7be942275d6bbb2b1f1fb7857364332ed732a0241c2165e53+ ? ../Access/equal.dhall++let Optional/equal =+ missing+ sha256:5411888399fe9c6720f7f3b59caf5eff3e8e8c30402d09f34e46a4457649a35a+ ? ../../Optional/equal.dhall++let f+ : Optional Access -> Optional Access -> Bool+ = Optional/equal Access Access/equal++let equal+ : Mode -> Mode -> Bool+ = \(m1 : Mode) ->+ \(m2 : Mode) ->+ f m1.user m2.user && f m1.group m2.group && f m1.other m2.other++in equal
@@ -0,0 +1,9 @@+let Access =+ missing+ sha256:50689ae80f8c8dcd6e7af33fbc20ea871afb92ec87104253cdbae01f838f6c38+ ? ../Access/Type.dhall++in { user = None Access, group = None Access, other = None Access }+ : missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ./Type.dhall
@@ -0,0 +1,17 @@+{ Mask =+ missing+ sha256:ce2c7ac1b81c2184b906cdd07c79936ba0eaf0445f1e383f53fd18d688ee7044+ ? ./Mask/package.dhall+, Type =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ./Type.dhall+, equal =+ missing+ sha256:32fee2d3a56a2162d6c98fb63d47d31f98b352f22cc60c8b506011c9b5230e56+ ? ./equal.dhall+, schema =+ missing+ sha256:49f8eff9612d761c1bd424299b68317ad0f3ba325e4d22ec8acb550c2f1c0a40+ ? ./schema.dhall+}
@@ -0,0 +1,12 @@+{-|+A schema for a blank file mode.+-}+{ Type =+ missing+ sha256:f05819ec2145e7dabf4aa167338bee6d326aabd81355dcf0b078e358bd34ec60+ ? ./Type.dhall+, default =+ missing+ sha256:0ed46da7e6acbdff9e4c9e27a9f2770075a7cd6cb6bb565765c62093df1b5563+ ? ./none.dhall+}
@@ -0,0 +1,20 @@+let Directory =+ missing+ sha256:163a4536fdd05ce122d793ceda01d03fcffb29463817ae8b7b5601bf4a06ce6e+ ? ../Entry/DirectoryEntry.dhall++let BinaryFile =+ missing+ sha256:f027db2893f6f38bbe6d868a91f22de530e85407237f00b147427c87d32bf55c+ ? ../Entry/BinaryFileEntry.dhall++let TextFile =+ missing+ sha256:23a8cb29d96aeb623501519d9a62c5c49659e8d1c30b4ae4f2399809e3fd3a01+ ? ../Entry/TextFileEntry.dhall++in \(tree : Type) ->+ { directory : Directory tree -> tree+ , binary-file : BinaryFile -> tree+ , file : TextFile -> tree+ }
@@ -0,0 +1,6 @@+let Make =+ missing+ sha256:33c52c16f76b41c3635b57a38ce0286f1ad8b3163a3f07a3b41b808ac5bfeb5b+ ? ./Make.dhall++in forall (tree : Type) -> forall (make : Make tree) -> List tree
@@ -0,0 +1,32 @@+{-|+@makeTree tree make parents x@ places the tree @x@ below the directory @parent@.+@parent@ is given as a list of 'Metadata' values where each of those will be+used to create the respective level of the directory tree.+-}+let Make =+ missing+ sha256:33c52c16f76b41c3635b57a38ce0286f1ad8b3163a3f07a3b41b808ac5bfeb5b+ ? ./Make.dhall++let Metadata =+ missing+ sha256:8c240a00094238a73904af63ac0924b3e6aba1655312f20a2a27f88554e2febe+ ? ../Entry/Metadata.dhall++let makeTree+ : forall (tree : Type) -> Make tree -> List Metadata -> tree -> tree+ = \(tree : Type) ->+ \(make : Make tree) ->+ \(parents : List Metadata) ->+ \(leaf : tree) ->+ List/fold+ Metadata+ parents+ tree+ ( \(directory : Metadata) ->+ \(result : tree) ->+ make.directory (directory /\ { content = [ result ] })+ )+ leaf++in makeTree
@@ -0,0 +1,42 @@+{-|+@makeTreeFromList tree make parents xs@ places the trees @xs@ below the+directory @parent@. @parent@ is given as a non-empty list of 'Metadata' values+where each of those will be used to create the respective level of the directory+tree.+-}+let Make =+ missing+ sha256:33c52c16f76b41c3635b57a38ce0286f1ad8b3163a3f07a3b41b808ac5bfeb5b+ ? ./Make.dhall++let Metadata =+ missing+ sha256:8c240a00094238a73904af63ac0924b3e6aba1655312f20a2a27f88554e2febe+ ? ../Entry/Metadata.dhall++let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ../../NonEmpty/Type.dhall++let makeTreesFromList =+ missing+ sha256:02fce5b194da66c2f98bd05af0a3bfdccf0b57d7971f17bcafee436652d9a88e+ ? ./makeTreesFromList.dhall++let makeTreeFromList+ : forall (tree : Type) ->+ Make tree ->+ NonEmpty Metadata ->+ List tree ->+ tree+ = \(tree : Type) ->+ \(make : Make tree) ->+ \(parents : NonEmpty Metadata) ->+ \(leaves : List tree) ->+ make.directory+ ( parents.head+ /\ { content = makeTreesFromList tree make parents.tail leaves }+ )++in makeTreeFromList
@@ -0,0 +1,36 @@+{-|+@makeTreesFromList tree make parents xs@ places the trees @xs@ below the+directory @parent@. @parent@ is given as a list of 'Metadata' values where each+of those will be used to create the respective level of the directory tree.+-}+let Make =+ missing+ sha256:33c52c16f76b41c3635b57a38ce0286f1ad8b3163a3f07a3b41b808ac5bfeb5b+ ? ./Make.dhall++let Metadata =+ missing+ sha256:8c240a00094238a73904af63ac0924b3e6aba1655312f20a2a27f88554e2febe+ ? ../Entry/Metadata.dhall++let makeTreesFromList+ : forall (tree : Type) ->+ Make tree ->+ List Metadata ->+ List tree ->+ List tree+ = \(tree : Type) ->+ \(make : Make tree) ->+ \(parents : List Metadata) ->+ \(leaves : List tree) ->+ List/fold+ Metadata+ parents+ (List tree)+ ( \(directory : Metadata) ->+ \(content : List tree) ->+ [ make.directory (directory /\ { content }) ]+ )+ leaves++in makeTreesFromList
@@ -0,0 +1,21 @@+{ Make =+ missing+ sha256:33c52c16f76b41c3635b57a38ce0286f1ad8b3163a3f07a3b41b808ac5bfeb5b+ ? ./Make.dhall+, Type =+ missing+ sha256:60b4d351213c6d851d7b2163ada40290b3c492a27326a2066fdec1a3915fb33b+ ? ./Type.dhall+, makeTree =+ missing+ sha256:2c1339fa63b4947864e1a6eede3c296288b53cf91a09d0d6881ae56790342e44+ ? ./makeTree.dhall+, makeTreeFromList =+ missing+ sha256:b894c9398e123d7262320684ac6301c2efe44d9d4f5a303b99d14e9be6b3150f+ ? ./makeTreeFromList.dhall+, makeTreesFromList =+ missing+ sha256:02fce5b194da66c2f98bd05af0a3bfdccf0b57d7971f17bcafee436652d9a88e+ ? ./makeTreesFromList.dhall+}
@@ -0,0 +1,1 @@+< UserId : Natural | UserName : Text >
@@ -0,0 +1,6 @@+let User =+ missing+ sha256:8b25916612d2c9b17130d16b55c6bdb085dd118e692f72bf351a83b1d0ac8833+ ? ./Type.dhall++in User.UserId
@@ -0,0 +1,6 @@+let User =+ missing+ sha256:8b25916612d2c9b17130d16b55c6bdb085dd118e692f72bf351a83b1d0ac8833+ ? ./Type.dhall++in User.UserName
@@ -0,0 +1,13 @@+{ Type =+ missing+ sha256:8b25916612d2c9b17130d16b55c6bdb085dd118e692f72bf351a83b1d0ac8833+ ? ./Type.dhall+, id =+ missing+ sha256:b572ca9f08a04e8e472f1b6141fd71ff27cc7f22d1e72be50eba5f54798b5a6d+ ? ./id.dhall+, name =+ missing+ sha256:9cfd68599bbd626d3f32c9caa3f09b358ecc08659ef2540b24a4b17b49027015+ ? ./name.dhall+}
@@ -0,0 +1,25 @@+{ Access =+ missing+ sha256:12f2ac90297a81c6e5a548bbf568fc7c93c906a6528432aa74faab6ec859de30+ ? ./Access/package.dhall+, Entry =+ missing+ sha256:795db8b6c2bc28fdff6fbcc832c5b4cb6931c1f62ffa84674280c24d4f2eacd8+ ? ./Entry/package.dhall+, Group =+ missing+ sha256:76a0d7e4606bdb91ab001b245cbd411939333b3fc3934ecbb5d41982d1ea001f+ ? ./Group/package.dhall+, Mode =+ missing+ sha256:6687ff7703fe9abdc4af9b3404af3d1c7d21a523d10a0c0b57d102a0bd87843f+ ? ./Mode/package.dhall+, Tree =+ missing+ sha256:6a64c27fa8a0c95830a4cc836651257235da0d985b7f93d11813cdb7a72e646b+ ? ./Tree/package.dhall+, User =+ missing+ sha256:eee7762ea4769371278907a4e33b3808d88430dda32dfc0536dc9bb2bb49d46a+ ? ./User/package.dhall+}
@@ -1,4 +1,5 @@ { show =- ./show sha256:ae645813cc4d8505a265df4d7564c95482f62bb3e07fc81681959599b6cee04f- ? ./show+ missing+ sha256:ae645813cc4d8505a265df4d7564c95482f62bb3e07fc81681959599b6cee04f+ ? ./show.dhall }
@@ -1,13 +1,3 @@-{--Render a `Double` as `Text` using the same representation as Dhall source-code (i.e. a decimal floating point number with a leading `-` sign if negative)--Examples:--```-./show -3.1 = "-3.1"--./show 0.4 = "0.4"-```--}-let show : Double → Text = Double/show in show+ missing+ sha256:ae645813cc4d8505a265df4d7564c95482f62bb3e07fc81681959599b6cee04f+? ./show.dhall
@@ -0,0 +1,13 @@+{-|+Render a `Double` as `Text` using the same representation as Dhall source+code (i.e. a decimal floating point number with a leading `-` sign if negative)+-}+let show+ : Double → Text+ = Double/show++let example0 = assert : show -3.1 ≡ "-3.1"++let example1 = assert : show 0.4 ≡ "0.4"++in show
@@ -1,21 +1,3 @@-{--Compose two functions into one.--Examples:--```-./compose Natural Natural Bool (λ(n : Natural) → n + n) ../Natural/even 3-= True-```--}-let compose- : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c- = λ(A : Type)- → λ(B : Type)- → λ(C : Type)- → λ(f : A → B)- → λ(g : B → C)- → λ(x : A)- → g (f x)--in compose+ missing+ sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013+? ./compose.dhall
@@ -0,0 +1,17 @@+--| Compose two functions into one.+let compose+ : ∀(a : Type) → ∀(b : Type) → ∀(c : Type) → (a → b) → (b → c) → a → c+ = λ(a : Type) →+ λ(b : Type) →+ λ(c : Type) →+ λ(f : a → b) →+ λ(g : b → c) →+ λ(x : a) →+ g (f x)++let example0 =+ assert+ : compose Natural Natural Bool (λ(n : Natural) → n + n) Natural/even 3+ ≡ True++in compose
@@ -0,0 +1,35 @@+{-|+Composes a list of functions starting from the left.+-}+let compose =+ missing+ sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013+ ? ./compose.dhall++let identity =+ missing+ sha256:f78b96792b459cb664f41c6119bd8897dd04353a3343521d436cd82ad71cb4d4+ ? ./identity.dhall++let composeList+ : ∀(a : Type) → List (a → a) → a → a+ = λ(a : Type) →+ λ(functions : List (a → a)) →+ List/fold (a → a) functions (a → a) (compose a a a) (identity a)++let example0 =+ assert+ : composeList+ Natural+ [ λ(x : Natural) → x * 2, λ(x : Natural) → x + 1 ]+ 1+ ≡ 3++let property0 =+ λ(a : Type) →+ λ(f : a → a) →+ λ(g : a → a) →+ λ(h : a → a) →+ assert : composeList a [ f, g, h ] ≡ (λ(x : a) → h (g (f x)))++in composeList
@@ -0,0 +1,3 @@+ missing+ sha256:f78b96792b459cb664f41c6119bd8897dd04353a3343521d436cd82ad71cb4d4+? ./identity.dhall
@@ -0,0 +1,10 @@+--| The identity function simply returns its input+let identity+ : ∀(a : Type) → ∀(x : a) → a+ = λ(a : Type) → λ(x : a) → x++let example0 = assert : identity Natural 1 ≡ 1++let example1 = assert : identity Bool ≡ (λ(x : Bool) → x)++in identity
@@ -1,4 +1,13 @@ { compose =- ./compose sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013- ? ./compose+ missing+ sha256:65ad8bbea530b3d8968785a7cf4a9a7976b67059aa15e3b61fcba600a40ae013+ ? ./compose.dhall+, composeList =+ missing+ sha256:2c6931544d8b5a5b14514098c07bd1813f67b16834588d056df3c0bc2e489937+ ? ./composeList.dhall+, identity =+ missing+ sha256:f78b96792b459cb664f41c6119bd8897dd04353a3343521d436cd82ad71cb4d4+ ? ./identity.dhall }
@@ -0,0 +1,3 @@+ missing+ sha256:35212fcbe1e60cb95b033a4a9c6e45befca4a298aa9919915999d09e69ddced1+? ./abs.dhall
@@ -0,0 +1,15 @@+--| Returns the absolute value of an `Integer`, i.e. its non-negative value.+let abs+ : Integer → Natural+ = λ(n : Integer) →+ if Natural/isZero (Integer/clamp n)+ then Integer/clamp (Integer/negate n)+ else Integer/clamp n++let example0 = assert : abs +7 ≡ 7++let example2 = assert : abs +0 ≡ 0++let example3 = assert : abs -3 ≡ 3++in abs
@@ -0,0 +1,3 @@+ missing+ sha256:7da1306a0bf87c5668beead2a1db1b18861e53d7ce1f38057b2964b649f59c3b+? ./add.dhall
@@ -0,0 +1,25 @@+--| `add m n` computes `m + n`.+let Integer/subtract =+ missing+ sha256:a34d36272fa8ae4f1ec8b56222fe8dc8a2ec55ec6538b840de0cbe207b006fda+ ? ./subtract.dhall++let add+ : Integer → Integer → Integer+ = λ(m : Integer) → λ(n : Integer) → Integer/subtract (Integer/negate m) n++let example0 = assert : add +3 +5 ≡ +8++let example1 = assert : add -3 -5 ≡ -8++let example2 = assert : add -4 +4 ≡ +0++let example3 = assert : add -3 +5 ≡ +2++let example4 = assert : add +3 -5 ≡ -2++let example5 = assert : add +0 -3 ≡ -3++let example6 = assert : add +0 +3 ≡ +3++in add
@@ -0,0 +1,3 @@+ missing+ sha256:ea42096cf3e024fadfaf910e0b839005b0ea7514fff11e5a3950a77694d9c5d2+? ./clamp.dhall
@@ -0,0 +1,14 @@+{-|+Convert an `Integer` to a `Natural` number, with negative numbers becoming zero.+-}+let clamp+ : Integer → Natural+ = Integer/clamp++let example0 = assert : clamp +7 ≡ 7++let example2 = assert : clamp +0 ≡ 0++let example3 = assert : clamp -3 ≡ 0++in clamp
@@ -0,0 +1,3 @@+ missing+ sha256:2d99a205086aa77eea17ae1dab22c275f3eb007bccdc8d9895b93497ebfc39f8+? ./equal.dhall
@@ -0,0 +1,24 @@+--| `equal` checks if two Integers are equal.+let Natural/equal =+ missing+ sha256:7f108edfa35ddc7cebafb24dc073478e93a802e13b5bc3fd22f4768c9b066e60+ ? ../Natural/equal.dhall++let equal+ : Integer → Integer → Bool+ = λ(a : Integer) →+ λ(b : Integer) →+ Natural/equal (Integer/clamp a) (Integer/clamp b)+ && Natural/equal+ (Integer/clamp (Integer/negate a))+ (Integer/clamp (Integer/negate b))++let example0 = assert : equal +5 +5 ≡ True++let example1 = assert : equal +5 +6 ≡ False++let example2 = assert : equal +5 -5 ≡ False++let example3 = assert : equal -5 -5 ≡ True++in equal
@@ -0,0 +1,3 @@+ missing+ sha256:d23affd73029fc9aaf867c2c7b86510ca2802d3f0d1f3e1d1a93ffd87b7cb64b+? ./greaterThan.dhall
@@ -0,0 +1,30 @@+--| `greaterThan` checks if one Integer is greater than another.+let Bool/not =+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+ ? ../Bool/not.dhall++let lessThanEqual =+ missing+ sha256:e3cca9f3942f81fa78a2bea23c0c24519c67cfe438116c38e797e12dcd26f6bc+ ? ./lessThanEqual.dhall++let greaterThan+ : Integer → Integer → Bool+ = λ(x : Integer) → λ(y : Integer) → Bool/not (lessThanEqual x y)++let example0 = assert : greaterThan +5 +6 ≡ False++let example1 = assert : greaterThan +5 +5 ≡ False++let example2 = assert : greaterThan +5 +4 ≡ True++let example3 = assert : greaterThan -5 +8 ≡ False++let example4 = assert : greaterThan -5 -3 ≡ False++let example5 = assert : greaterThan -3 -5 ≡ True++let example6 = assert : greaterThan -3 -3 ≡ False++in greaterThan
@@ -0,0 +1,3 @@+ missing+ sha256:a9fa2dc5cd6067a23b39d7fe8d14a63109583b320429fb0e446658a5aae0a958+? ./greaterThanEqual.dhall
@@ -0,0 +1,27 @@+{-|+`greaterThanEqual` checks if one Integer is greater than or equal to another.+-}+let lessThanEqual =+ missing+ sha256:e3cca9f3942f81fa78a2bea23c0c24519c67cfe438116c38e797e12dcd26f6bc+ ? ./lessThanEqual.dhall++let greaterThanEqual+ : Integer → Integer → Bool+ = λ(x : Integer) → λ(y : Integer) → lessThanEqual y x++let example0 = assert : greaterThanEqual +5 +6 ≡ False++let example1 = assert : greaterThanEqual +5 +5 ≡ True++let example2 = assert : greaterThanEqual +5 +4 ≡ True++let example3 = assert : greaterThanEqual -5 +8 ≡ False++let example4 = assert : greaterThanEqual -5 -3 ≡ False++let example5 = assert : greaterThanEqual -3 -5 ≡ True++let example6 = assert : greaterThanEqual -3 -3 ≡ True++in greaterThanEqual
@@ -0,0 +1,3 @@+ missing+ sha256:eeaa0081d10c6c97464ef193c40f1aa5cbb12f0202972ab42f3d310c2fd6a3f0+? ./lessThan.dhall
@@ -0,0 +1,25 @@+--| `lessThan` checks if one Integer is less than another.+let greaterThan =+ missing+ sha256:d23affd73029fc9aaf867c2c7b86510ca2802d3f0d1f3e1d1a93ffd87b7cb64b+ ? ./greaterThan.dhall++let lessThan+ : Integer → Integer → Bool+ = λ(x : Integer) → λ(y : Integer) → greaterThan y x++let example0 = assert : lessThan +5 +6 ≡ True++let example1 = assert : lessThan +5 +5 ≡ False++let example2 = assert : lessThan +5 +4 ≡ False++let example3 = assert : lessThan -5 +8 ≡ True++let example4 = assert : lessThan -5 -3 ≡ True++let example5 = assert : lessThan -3 -5 ≡ False++let example6 = assert : lessThan -3 -3 ≡ False++in lessThan
@@ -0,0 +1,3 @@+ missing+ sha256:e3cca9f3942f81fa78a2bea23c0c24519c67cfe438116c38e797e12dcd26f6bc+? ./lessThanEqual.dhall
@@ -0,0 +1,47 @@+--| `lessThanEqual` checks if one Integer is less than or equal to another.+let Natural/greaterThanEqual =+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+ ? ../Natural/greaterThanEqual.dhall++let Natural/lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ../Natural/lessThanEqual.dhall++let nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall++let nonNegative =+ missing+ sha256:b463373f070df6b1c8c7082051e0810fee38b360bab35256187c8c2b6af5c663+ ? ./nonNegative.dhall++let lessThanEqual+ : Integer → Integer → Bool+ = λ(x : Integer) →+ λ(y : Integer) →+ if nonPositive x+ then nonNegative y+ || Natural/greaterThanEqual+ (Integer/clamp (Integer/negate x))+ (Integer/clamp (Integer/negate y))+ else Natural/lessThanEqual (Integer/clamp x) (Integer/clamp y)++let example0 = assert : lessThanEqual +5 +6 ≡ True++let example1 = assert : lessThanEqual +5 +5 ≡ True++let example2 = assert : lessThanEqual +5 +4 ≡ False++let example3 = assert : lessThanEqual -5 +8 ≡ True++let example4 = assert : lessThanEqual -5 -3 ≡ True++let example5 = assert : lessThanEqual -3 -5 ≡ False++let example6 = assert : lessThanEqual -3 -3 ≡ True++in lessThanEqual
@@ -0,0 +1,3 @@+ missing+ sha256:dcb1ed7c8475ece8d67db92cd249fc728541778ff82509e28c3760e341880e4d+? ./multiply.dhall
@@ -0,0 +1,40 @@+--| `multiply m n` computes `m * n`.+let nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall++let multiplyNonNegative =+ λ(x : Integer) →+ λ(y : Integer) →+ Natural/toInteger (Integer/clamp x * Integer/clamp y)++let multiply+ : Integer → Integer → Integer+ = λ(m : Integer) →+ λ(n : Integer) →+ if nonPositive m+ then if nonPositive n+ then multiplyNonNegative (Integer/negate m) (Integer/negate n)+ else Integer/negate (multiplyNonNegative (Integer/negate m) n)+ else if nonPositive n+ then Integer/negate (multiplyNonNegative m (Integer/negate n))+ else multiplyNonNegative m n++let example0 = assert : multiply +3 +5 ≡ +15++let example1 = assert : multiply -3 +5 ≡ -15++let example2 = assert : multiply -3 -5 ≡ +15++let example3 = assert : multiply +0 +5 ≡ +0++let example4 = assert : multiply +5 +0 ≡ +0++let example5 = assert : multiply +0 +0 ≡ +0++let example6 = assert : multiply +1 +5 ≡ +5++let example7 = assert : multiply +3 -1 ≡ -3++in multiply
@@ -0,0 +1,3 @@+ missing+ sha256:2373c992e1de93634bc6a8781eb073b2a92a70170133e49762a785f3a136df5d+? ./negate.dhall
@@ -0,0 +1,12 @@+--| Invert the sign of an `Integer`, with zero remaining unchanged.+let negate+ : Integer → Integer+ = Integer/negate++let example0 = assert : negate -3 ≡ +3++let example2 = assert : negate +7 ≡ -7++let example3 = assert : negate +0 ≡ +0++in negate
@@ -0,0 +1,3 @@+ missing+ sha256:23e4b3c61eea9e878a7f83bf25fd0ea2c6a6d60174890d65be885828b690a570+? ./negative.dhall
@@ -0,0 +1,21 @@+{-|+Returns `True` for any `Integer` less than `+0`.++`negative` is more efficient than `./lessThan +0` or `./lessThanEqual -1`.+-}+let positive =+ missing+ sha256:7bdbf50fcdb83d01f74c7e2a92bf5c9104eff5d8c5b4587e9337f0caefcfdbe3+ ? ./positive.dhall++let negative+ : Integer → Bool+ = λ(n : Integer) → positive (Integer/negate n)++let example0 = assert : negative +1 ≡ False++let example1 = assert : negative +0 ≡ False++let example2 = assert : negative -1 ≡ True++in negative
@@ -0,0 +1,3 @@+ missing+ sha256:b463373f070df6b1c8c7082051e0810fee38b360bab35256187c8c2b6af5c663+? ./nonNegative.dhall
@@ -0,0 +1,21 @@+{-|+Returns `True` for `+0` and any positive `Integer`.++`nonNegative` is more efficient than `./greaterThanEqual +0` or `./greaterThan -1`.+-}+let nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall++let nonNegative+ : Integer → Bool+ = λ(n : Integer) → nonPositive (Integer/negate n)++let example0 = assert : nonNegative +1 ≡ True++let example1 = assert : nonNegative +0 ≡ True++let example2 = assert : nonNegative -1 ≡ False++in nonNegative
@@ -0,0 +1,3 @@+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+? ./nonPositive.dhall
@@ -0,0 +1,16 @@+{-|+Returns `True` for `+0` and any negative `Integer`.++`nonPositive` is more efficient than `./lessThanEqual +0` or `./lessThan +1`.+-}+let nonPositive+ : Integer → Bool+ = λ(n : Integer) → Natural/isZero (Integer/clamp n)++let example0 = assert : nonPositive +1 ≡ False++let example1 = assert : nonPositive +0 ≡ True++let example2 = assert : nonPositive -1 ≡ True++in nonPositive
@@ -1,7 +1,73 @@-{ show =- ./show sha256:ecf8b0594cd5181bc45d3b7ea0d44d3ba9ad5dac6ec17bb8968beb65f4b1baa9- ? ./show+{ abs =+ missing+ sha256:35212fcbe1e60cb95b033a4a9c6e45befca4a298aa9919915999d09e69ddced1+ ? ./abs.dhall+, add =+ missing+ sha256:7da1306a0bf87c5668beead2a1db1b18861e53d7ce1f38057b2964b649f59c3b+ ? ./add.dhall+, clamp =+ missing+ sha256:ea42096cf3e024fadfaf910e0b839005b0ea7514fff11e5a3950a77694d9c5d2+ ? ./clamp.dhall+, equal =+ missing+ sha256:2d99a205086aa77eea17ae1dab22c275f3eb007bccdc8d9895b93497ebfc39f8+ ? ./equal.dhall+, greaterThan =+ missing+ sha256:d23affd73029fc9aaf867c2c7b86510ca2802d3f0d1f3e1d1a93ffd87b7cb64b+ ? ./greaterThan.dhall+, greaterThanEqual =+ missing+ sha256:a9fa2dc5cd6067a23b39d7fe8d14a63109583b320429fb0e446658a5aae0a958+ ? ./greaterThanEqual.dhall+, lessThan =+ missing+ sha256:eeaa0081d10c6c97464ef193c40f1aa5cbb12f0202972ab42f3d310c2fd6a3f0+ ? ./lessThan.dhall+, lessThanEqual =+ missing+ sha256:e3cca9f3942f81fa78a2bea23c0c24519c67cfe438116c38e797e12dcd26f6bc+ ? ./lessThanEqual.dhall+, multiply =+ missing+ sha256:dcb1ed7c8475ece8d67db92cd249fc728541778ff82509e28c3760e341880e4d+ ? ./multiply.dhall+, negate =+ missing+ sha256:2373c992e1de93634bc6a8781eb073b2a92a70170133e49762a785f3a136df5d+ ? ./negate.dhall+, negative =+ missing+ sha256:23e4b3c61eea9e878a7f83bf25fd0ea2c6a6d60174890d65be885828b690a570+ ? ./negative.dhall+, nonNegative =+ missing+ sha256:b463373f070df6b1c8c7082051e0810fee38b360bab35256187c8c2b6af5c663+ ? ./nonNegative.dhall+, nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall+, positive =+ missing+ sha256:7bdbf50fcdb83d01f74c7e2a92bf5c9104eff5d8c5b4587e9337f0caefcfdbe3+ ? ./positive.dhall+, show =+ missing+ sha256:ecf8b0594cd5181bc45d3b7ea0d44d3ba9ad5dac6ec17bb8968beb65f4b1baa9+ ? ./show.dhall+, subtract =+ missing+ sha256:a34d36272fa8ae4f1ec8b56222fe8dc8a2ec55ec6538b840de0cbe207b006fda+ ? ./subtract.dhall , toDouble =- ./toDouble sha256:77bc5d635dc4d952f37cc96f2a681d5ac503b4e8b21fc00055b1946adb5beda7- ? ./toDouble+ missing+ sha256:77bc5d635dc4d952f37cc96f2a681d5ac503b4e8b21fc00055b1946adb5beda7+ ? ./toDouble.dhall+, toNatural =+ missing+ sha256:4d128730d74e7f832e53873cb5204aa91b79758be5ce4e1aa991fe1951304a0e+ ? ./toNatural.dhall }
@@ -0,0 +1,3 @@+ missing+ sha256:7bdbf50fcdb83d01f74c7e2a92bf5c9104eff5d8c5b4587e9337f0caefcfdbe3+? ./positive.dhall
@@ -0,0 +1,26 @@+{-|+Returns `True` for any `Integer` greater than `+0`.++`positive` is more efficient than `./greaterThan +0` or `./greaterThanEqual +1`.+-}+let not =+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+ ? ../Bool/not.dhall++let nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall++let positive+ : Integer → Bool+ = λ(n : Integer) → not (nonPositive n)++let example0 = assert : positive +1 ≡ True++let example1 = assert : positive +0 ≡ False++let example2 = assert : positive -1 ≡ False++in positive
@@ -1,14 +1,3 @@-{--Render an `Integer` as `Text` using the same representation as Dhall source-code (i.e. a decimal number with a leading `-` sign if negative and a leading-`+` sign if non-negative)--Examples:--```-./show -3 = "-3"--./show +0 = "+0"-```--}-let show : Integer → Text = Integer/show in show+ missing+ sha256:ecf8b0594cd5181bc45d3b7ea0d44d3ba9ad5dac6ec17bb8968beb65f4b1baa9+? ./show.dhall
@@ -0,0 +1,14 @@+{-|+Render an `Integer` as `Text` using the same representation as Dhall source+code (i.e. a decimal number with a leading `-` sign if negative and a leading+`+` sign if non-negative)+-}+let show+ : Integer → Text+ = Integer/show++let example0 = assert : show -3 ≡ "-3"++let example1 = assert : show +0 ≡ "+0"++in show
@@ -0,0 +1,3 @@+ missing+ sha256:a34d36272fa8ae4f1ec8b56222fe8dc8a2ec55ec6538b840de0cbe207b006fda+? ./subtract.dhall
@@ -0,0 +1,54 @@+--| `subtract m n` computes `n - m`.+let nonPositive =+ missing+ sha256:e00a852eed5b84ff60487097d8aadce53c9e5301f53ff4954044bd68949fac3b+ ? ./nonPositive.dhall++let subtractNonNegative =+ λ(xi : Integer) →+ λ(yi : Integer) →+ let xn = Integer/clamp xi++ let yn = Integer/clamp yi++ let dn = Natural/subtract xn yn++ in if Natural/isZero dn+ then Integer/negate (Natural/toInteger (Natural/subtract yn xn))+ else Natural/toInteger dn++let subtract+ : Integer → Integer → Integer+ = λ(m : Integer) →+ λ(n : Integer) →+ if nonPositive m+ then if nonPositive n+ then subtractNonNegative (Integer/negate n) (Integer/negate m)+ else Natural/toInteger+ (Integer/clamp (Integer/negate m) + Integer/clamp n)+ else if nonPositive n+ then Integer/negate+ ( Natural/toInteger+ (Integer/clamp m + Integer/clamp (Integer/negate n))+ )+ else subtractNonNegative m n++let example0 = assert : subtract +3 +5 ≡ +2++let example1 = assert : subtract +4 +4 ≡ +0++let example2 = assert : subtract +5 +3 ≡ -2++let example3 = assert : subtract -3 -5 ≡ -2++let example4 = assert : subtract -4 -4 ≡ +0++let example5 = assert : subtract -5 -3 ≡ +2++let example6 = assert : subtract -3 +5 ≡ +8++let example7 = assert : subtract +3 -5 ≡ -8++let example8 = assert : subtract +0 -3 ≡ -3++in subtract
@@ -1,12 +1,3 @@-{--Convert an `Integer` to the corresponding `Double`--Examples:--```-./toDouble -3 = -3.0--./toDouble +2 = 2.0-```--}-let toDouble : Integer → Double = Integer/toDouble in toDouble+ missing+ sha256:77bc5d635dc4d952f37cc96f2a681d5ac503b4e8b21fc00055b1946adb5beda7+? ./toDouble.dhall
@@ -0,0 +1,10 @@+--| Convert an `Integer` to the corresponding `Double`+let toDouble+ : Integer → Double+ = Integer/toDouble++let example0 = assert : toDouble -3 ≡ -3.0++let example1 = assert : toDouble +2 ≡ 2.0++in toDouble
@@ -0,0 +1,3 @@+ missing+ sha256:4d128730d74e7f832e53873cb5204aa91b79758be5ce4e1aa991fe1951304a0e+? ./toNatural.dhall
@@ -0,0 +1,20 @@+{-|+Convert an `Integer` to an `Optional Natural`, with negative numbers becoming `None Natural`.+-}+let nonNegative =+ missing+ sha256:b463373f070df6b1c8c7082051e0810fee38b360bab35256187c8c2b6af5c663+ ? ./nonNegative.dhall++let toNatural+ : Integer → Optional Natural+ = λ(n : Integer) →+ if nonNegative n then Some (Integer/clamp n) else None Natural++let example0 = assert : toNatural +7 ≡ Some 7++let example2 = assert : toNatural +0 ≡ Some 0++let example3 = assert : toNatural -3 ≡ None Natural++in toNatural
@@ -0,0 +1,3 @@+ missing+ sha256:d7936b510cfc091faa994652af0eb5feb889cd44bc989edbe4f1eb8c5623caac+? ./Format.dhall
@@ -0,0 +1,7 @@+{-|+An internal type used by `./renderAs` to select the output format.++You should not need to use this type directly, simply use `./render`+or `./renderYAML` as appropriate.+-}+< YAML | JSON >
@@ -1,31 +1,3 @@-{--This type is used as part of `dhall-json`'s support for preserving alternative-names--For example, this Dhall code:--```-let Example = < Left : { foo : Natural } | Right : { bar : Bool } >--let Nesting = < Inline | Nested : Text >--in { field =- "name"- , nesting =- Nesting.Inline- , contents =- Example.Left { foo = 2 }- }-```--... generates this JSON:--```-{- "foo": 2,- "name": "Left"- }-```---}-let Nesting : Type = < Inline | Nested : Text > in Nesting+ missing+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+? ./Nesting.dhall
@@ -0,0 +1,35 @@+{-|+This type is used as part of `dhall-json`'s support for preserving alternative+names++For example, this Dhall code:++```+let Example = < Left : { foo : Natural } | Right : { bar : Bool } >++let Nesting = < Inline | Nested : Text >++in { field =+ "name"+ , nesting =+ Nesting.Inline+ , contents =+ Example.Left { foo = 2 }+ }+```++... generates this JSON:++```+{+ "foo": 2,+ "name": "Left"+}+```++-}+let Nesting+ : Type+ = < Inline | Nested : Text >++in Nesting
@@ -1,67 +1,3 @@-{--This is a convenient type-level function when using `dhall-to-json`'s support-for preserving alternative names--For example, this code:--```-let map = ../List/map--let Provisioner =- < shell :- { inline : List Text }- | file :- { source : Text, destination : Text }- >--let Tagged = ./Tagged--let Nesting = ./Nesting--let wrap- : Provisioner → Tagged Provisioner- = λ(x : Provisioner)- → { field = "type", nesting = Nesting.Nested "params", contents = x }--in { provisioners =- map- Provisioner- (Tagged Provisioner)- wrap- [ Provisioner.shell { inline = [ "echo foo" ] }- , Provisioner.file- { source = "app.tar.gz", destination = "/tmp/app.tar.gz" }- ]- }-```--... produces this JSON:--```-{- "provisioners": [- {- "params": {- "inline": [- "echo foo"- ]- },- "type": "shell"- },- {- "params": {- "destination": "/tmp/app.tar.gz",- "source": "app.tar.gz"- },- "type": "file"- }- ]-}-```---}-let Tagged- : Type → Type- = λ(a : Type) → { field : Text, nesting : ./Nesting, contents : a }--in Tagged+ missing+ sha256:21feca7d2b23f210d0696131d792e18a7d24fdcc85d41a49ba85b98670eba194+? ./Tagged.dhall
@@ -0,0 +1,74 @@+{-|+This is a convenient type-level function when using `dhall-to-json`'s support+for preserving alternative names++For example, this code:++```+let map = ../List/map++let Provisioner =+ < shell :+ { inline : List Text }+ | file :+ { source : Text, destination : Text }+ >++let Tagged = ./Tagged++let Nesting = ./Nesting++let wrap+ : Provisioner → Tagged Provisioner+ = λ(x : Provisioner) →+ { field = "type", nesting = Nesting.Nested "params", contents = x }++in { provisioners =+ map+ Provisioner+ (Tagged Provisioner)+ wrap+ [ Provisioner.shell { inline = [ "echo foo" ] }+ , Provisioner.file+ { source = "app.tar.gz", destination = "/tmp/app.tar.gz" }+ ]+ }+```++... produces this JSON:++```+{+ "provisioners": [+ {+ "params": {+ "inline": [+ "echo foo"+ ]+ },+ "type": "shell"+ },+ {+ "params": {+ "destination": "/tmp/app.tar.gz",+ "source": "app.tar.gz"+ },+ "type": "file"+ }+ ]+}+```++-}+let Tagged+ : Type → Type+ = λ(a : Type) →+ { field : Text+ , nesting :+ missing+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting.dhall+ , contents : a+ }++in Tagged
@@ -0,0 +1,3 @@+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+? ./Type.dhall
@@ -0,0 +1,63 @@+{-|+Dhall encoding of an arbitrary JSON value++For example, the following JSON value:++```+[ { "foo": null, "bar": [ 1.0, true ] } ]+```++... corresponds to the following Dhall expression:++```+λ(JSON : Type) →+λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , null : JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.object+ [ { mapKey = "foo", mapValue = json.null }+ , { mapKey = "bar"+ , mapValue = json.array [ json.double 1.0, json.bool True ]+ }+ ]+```++ You do not need to create these values directly, though. You can use+ the utilities exported by `./package.dhall` to create values of this type,+ such as:++```+let JSON = ./package.dhall++in JSON.object+ [ { mapKey = "foo", mapValue = JSON.null }+ , { mapKey = "bar"+ , mapValue = JSON.array [ JSON.double 1.0, JSON.bool True ]+ }+ ]+```++-}+let JSON/Type+ : Type+ = ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON++in JSON/Type
@@ -0,0 +1,3 @@+ missing+ sha256:fb6346a9c63638fe3c59f8108e19eebdbddc51389ec5570bab4c25f890ccccc8+? ./array.dhall
@@ -0,0 +1,41 @@+{-|+Create a JSON array from a `List` of JSON values++```+let JSON = ./package.dhall+in JSON.render (JSON.array [ JSON.double 1.0, JSON.bool True ])+= "[ 1.0, true ]"++let JSON/Type = ./Type+let JSON = ./package.dhall+in JSON.render (JSON.array ([] : List JSON/Type))+= "[ ]"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let array+ : List JSON → JSON+ = λ(x : List JSON) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.array (List/map JSON@1 JSON (λ(j : JSON@1) → j JSON json) x)++in array
@@ -0,0 +1,3 @@+ missing+ sha256:e043d9ed01e5b45899059e128243f3dae7ce65f293f0015ce816fc36d30f7f39+? ./bool.dhall
@@ -0,0 +1,35 @@+{-|+Create a JSON bool from a Dhall `Bool`++```+let JSON = ./package.dhall+in JSON.render (JSON.bool True)+= "true"++let JSON = ./package.dhall+in JSON.render (JSON.bool False)+= "false"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let bool+ : Bool → JSON+ = λ(x : Bool) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.bool x++in bool
@@ -0,0 +1,70 @@+{-|+A record of functions useful for constructing `JSON` values.++This is only a subset of what `package.dhall` exports. If you are not writing a+JSON prelude function, you should use the `package.dhall` file instead.++It is used internally by `render`, `renderYAML` and `omitNullFields` instead of+`package.dhall` to avoid import cycles.+-}+{ Type =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall+, Tagged =+ missing+ sha256:21feca7d2b23f210d0696131d792e18a7d24fdcc85d41a49ba85b98670eba194+ ? ./Tagged.dhall+, Nesting =+ missing+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting.dhall+, keyText =+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+ ? ./keyText.dhall+, keyValue =+ missing+ sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c+ ? ./keyValue.dhall+, string =+ missing+ sha256:7ddb3a3b9f3ed09ed011d621a10ad9825185cd03503be98a81d42f6afb77940e+ ? ./string.dhall+, number =+ missing+ sha256:e70162c73c4978ad0d0d99505f61c7d990f3abadfcc08b34388b29c0934a7a32+ ? ./number.dhall+, double =+ missing+ sha256:e70162c73c4978ad0d0d99505f61c7d990f3abadfcc08b34388b29c0934a7a32+ ? ./double.dhall+, integer =+ missing+ sha256:c81a417397fc6f62155ec71fdd8d2047f981f0881295b307de3dd88747bf7e40+ ? ./integer.dhall+, natural =+ missing+ sha256:a839dc6789f19f820e9cbf70c60f41f3b057c59ece1d226d04db5aca447eb0e5+ ? ./natural.dhall+, object =+ missing+ sha256:869aede785c34798be9f9fd457ece73e7f683f352ae4555f791516a365faf4ac+ ? ./object.dhall+, array =+ missing+ sha256:fb6346a9c63638fe3c59f8108e19eebdbddc51389ec5570bab4c25f890ccccc8+ ? ./array.dhall+, bool =+ missing+ sha256:e043d9ed01e5b45899059e128243f3dae7ce65f293f0015ce816fc36d30f7f39+ ? ./bool.dhall+, null =+ missing+ sha256:1eeb9aee38eb8dde0e64efbaf60f24612c8194cc00b510bfb627c2ee2e1877b8+ ? ./null.dhall+, renderInteger =+ missing+ sha256:15b8d2ae46d5002832741927af787761df49798c911e2bf85db7a7b9cb5c078c+ ? ./renderInteger.dhall+}
@@ -0,0 +1,3 @@+ missing+ sha256:e70162c73c4978ad0d0d99505f61c7d990f3abadfcc08b34388b29c0934a7a32+? ./double.dhall
@@ -0,0 +1,35 @@+{-|+Create a JSON number from a Dhall `Double`++```+let JSON = ./package.dhall+in JSON.render (JSON.double 42.0)+= "42.0"++let JSON = ./package.dhall+in JSON.render (JSON.double -1.5e-10)+= "-1.5e-10"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let double+ : Double → JSON+ = λ(x : Double) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.double x++in double
@@ -0,0 +1,3 @@+ missing+ sha256:c81a417397fc6f62155ec71fdd8d2047f981f0881295b307de3dd88747bf7e40+? ./integer.dhall
@@ -0,0 +1,35 @@+{-|+Create a JSON number from a Dhall `Integer`++```+let JSON = ./package.dhall+in JSON.render (JSON.integer -1)+= "-1"++let JSON = ./package.dhall+in JSON.render (JSON.integer +2)+= "+2"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let integer+ : Integer → JSON+ = λ(x : Integer) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.integer x++in integer
@@ -1,17 +1,3 @@-{--Builds a key-value record such that a List of them will be converted to a-homogeneous record by dhall-to-json and dhall-to-yaml.-Both key and value are fixed to Text.-Take a look at `Record/keyValue` for a polymorphic version.--Example:--```-./keyText "foo" "bar" = { mapKey = "foo", mapValue = "bar" }-```--}--let keyText =- λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }--in keyText+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+? ./keyText.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+? ../Map/keyText.dhall
@@ -1,20 +1,3 @@-{--Builds a key-value record such that a List of them will be converted to a-homogeneous record by dhall-to-json and dhall-to-yaml.--Examples:--```-./keyValue Natural "foo" 2 = { mapKey = "foo", mapValue = 2 }--./keyValue Text "bar" "baz" = { mapKey = "bar", mapValue = "baz" }-```--}--let keyValue =- λ(v : Type)- → λ(key : Text)- → λ(value : v)- → { mapKey = key, mapValue = value }--in keyValue+ missing+ sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c+? ./keyValue.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c+? ../Map/keyValue.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:a839dc6789f19f820e9cbf70c60f41f3b057c59ece1d226d04db5aca447eb0e5+? ./natural.dhall
@@ -0,0 +1,31 @@+{-|+Create a JSON number from a Dhall `Natural`++```+let JSON = ./package.dhall+in JSON.render (JSON.natural 42)+= "42"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let natural+ : Natural → JSON+ = λ(x : Natural) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.integer (Natural/toInteger x)++in natural
@@ -0,0 +1,3 @@+ missing+ sha256:1eeb9aee38eb8dde0e64efbaf60f24612c8194cc00b510bfb627c2ee2e1877b8+? ./null.dhall
@@ -0,0 +1,30 @@+{-|+Create a JSON null++```+let JSON = ./package.dhall+in JSON.render JSON.null+= "null"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let null+ : JSON+ = λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.null++in null
@@ -0,0 +1,3 @@+ missing+ sha256:e70162c73c4978ad0d0d99505f61c7d990f3abadfcc08b34388b29c0934a7a32+? ./number.dhall
@@ -0,0 +1,28 @@+{-|+Create a JSON number from a Dhall `Double`++```+let JSON = ./package.dhall+in JSON.render (JSON.number 42.0)+= "42.0"++let JSON = ./package.dhall+in JSON.render (JSON.number -1.5e-10)+= "-1.5e-10"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let double =+ missing+ sha256:e70162c73c4978ad0d0d99505f61c7d990f3abadfcc08b34388b29c0934a7a32+ ? ./double.dhall++let number+ : Double → JSON+ = double++in number
@@ -0,0 +1,3 @@+ missing+ sha256:869aede785c34798be9f9fd457ece73e7f683f352ae4555f791516a365faf4ac+? ./object.dhall
@@ -0,0 +1,55 @@+{-|+Create a JSON object from a Dhall `Map`++```+let JSON = ./package.dhall+in JSON.render+ ( JSON.object+ [ { mapKey = "foo", mapValue = JSON.double 1.0 }+ , { mapKey = "bar", mapValue = JSON.bool True }+ ]+ )+= "{ \"foo\": 1.0, \"bar\": true }"++let JSON/Type = ./Type+let JSON = ./package.dhall+in JSON.render+ (JSON.object ([] : List { mapKey : Text, mapValue : JSON/Type }))+= "{ }"+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let object+ : List { mapKey : Text, mapValue : JSON } → JSON+ = λ(x : List { mapKey : Text, mapValue : JSON }) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.object+ ( List/map+ { mapKey : Text, mapValue : JSON@1 }+ { mapKey : Text, mapValue : JSON }+ ( λ(kv : { mapKey : Text, mapValue : JSON@1 }) →+ { mapKey = kv.mapKey, mapValue = kv.mapValue JSON json }+ )+ x+ )++in object
@@ -0,0 +1,3 @@+ missing+ sha256:e6850e70094540b75edeb46f4d6038324a62def8d63544a1e9541f79739db6f0+? ./omitNullFields.dhall
@@ -0,0 +1,145 @@+{-|+This utility omits all `null` record fields, which is often the idiomatic way+for a configuration to encode absent fields+-}+let JSON =+ missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall++let List/concatMap =+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ../List/concatMap.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let omitNullFields+ : JSON.Type → JSON.Type+ = λ(old : JSON.Type) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ let result =+ old+ { value : JSON, isNull : Bool }+ { string =+ λ(x : Text) → { value = json.string x, isNull = False }+ , double =+ λ(x : Double) → { value = json.double x, isNull = False }+ , integer =+ λ(x : Integer) → { value = json.integer x, isNull = False }+ , object =+ λ ( keyValues+ : List+ { mapKey : Text+ , mapValue : { value : JSON, isNull : Bool }+ }+ ) →+ let value =+ json.object+ ( List/concatMap+ { mapKey : Text+ , mapValue : { value : JSON, isNull : Bool }+ }+ { mapKey : Text, mapValue : JSON }+ ( λ ( keyValue+ : { mapKey : Text+ , mapValue :+ { value : JSON, isNull : Bool }+ }+ ) →+ if keyValue.mapValue.isNull+ then [] : List+ { mapKey : Text+ , mapValue : JSON+ }+ else [ keyValue.{ mapKey }+ ∧ { mapValue =+ keyValue.mapValue.value+ }+ ]+ )+ keyValues+ )++ in { value, isNull = False }+ , array =+ λ(xs : List { value : JSON, isNull : Bool }) →+ let value =+ json.array+ ( List/map+ { value : JSON, isNull : Bool }+ JSON+ ( λ(x : { value : JSON, isNull : Bool }) →+ x.value+ )+ xs+ )++ in { value, isNull = False }+ , bool = λ(x : Bool) → { value = json.bool x, isNull = False }+ , null = { value = json.null, isNull = True }+ }++ in result.value++let property =+ λ(a : Text) →+ λ(b : Double) →+ λ(c : Bool) →+ assert+ : omitNullFields+ ( JSON.object+ ( toMap+ { string = JSON.string a+ , double = JSON.double b+ , bool = JSON.bool c+ , null = JSON.null+ }+ )+ )+ ≡ JSON.object+ ( toMap+ { string = JSON.string a+ , double = JSON.double b+ , bool = JSON.bool c+ }+ )++let example =+ assert+ : omitNullFields+ ( JSON.object+ ( toMap+ { array =+ JSON.array [ JSON.object (toMap { null = JSON.null }) ]+ }+ )+ )+ ≡ JSON.object+ ( toMap+ { array =+ JSON.array+ [ JSON.object+ ([] : List { mapKey : Text, mapValue : JSON.Type })+ ]+ }+ )++let example =+ assert+ : omitNullFields (JSON.array [ JSON.null ]) ≡ JSON.array [ JSON.null ]++in omitNullFields
@@ -1,7 +1,29 @@-{ keyText =- ./keyText sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc- ? ./keyText-, keyValue =- ./keyValue sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c- ? ./keyValue-}+ { render =+ missing+ sha256:36befdd8bb5a1c2b372709da245a8d074533b86429e137b894c08ad16fa34836+ ? ./render.dhall+ , renderCompact =+ missing+ sha256:e6c8809fbe193fddd430f94350d69cefd45e7aaf8bd379e51b750fde75008562+ ? ./renderCompact.dhall+ , renderYAML =+ missing+ sha256:bc71449397bbf48103c3ebbdd570cd27313115e94b2b1b96761d257d5c02d478+ ? ./renderYAML.dhall+ , omitNullFields =+ missing+ sha256:e6850e70094540b75edeb46f4d6038324a62def8d63544a1e9541f79739db6f0+ ? ./omitNullFields.dhall+ , tagInline =+ missing+ sha256:49559ac11906ba6cc9eac25753e31e7addb13bc760df108024174c55523984c4+ ? ./tagInline.dhall+ , tagNested =+ missing+ sha256:93a7415853b7677c832246efadc8e880c1b641a23589286a836a384ca311d26f+ ? ./tagNested.dhall+ }+∧ ( missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall+ )
@@ -0,0 +1,3 @@+ missing+ sha256:36befdd8bb5a1c2b372709da245a8d074533b86429e137b894c08ad16fa34836+? ./render.dhall
@@ -0,0 +1,52 @@+{-|+Render a `JSON` value as `Text`++This is useful for debugging `JSON` values or for tests. For anything+more sophisticated you should use `dhall-to-json` or `dhall-to-yaml`+-}+let JSON =+ missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall++let renderAs =+ missing+ sha256:c23be039c9601a33d6546fd99a8d72bee8dde5f46176d57cc96613b31a3bb471+ ? ./renderAs.dhall++let Format =+ missing+ sha256:d7936b510cfc091faa994652af0eb5feb889cd44bc989edbe4f1eb8c5623caac+ ? ./Format.dhall++let render+ : JSON.Type → Text+ = renderAs Format.JSON++let example0 =+ let data =+ assert+ : render+ ( JSON.array+ [ JSON.bool True+ , JSON.string "Hello"+ , JSON.object+ [ { mapKey = "foo", mapValue = JSON.null }+ , { mapKey = "bar", mapValue = JSON.double 1.0 }+ ]+ ]+ )+ ≡ ''+ [+ true,+ "Hello",+ {+ "foo": null,+ "bar": 1.0+ }+ ]+ ''++ in True++in render
@@ -0,0 +1,3 @@+ missing+ sha256:c23be039c9601a33d6546fd99a8d72bee8dde5f46176d57cc96613b31a3bb471+? ./renderAs.dhall
@@ -0,0 +1,458 @@+--| Render a `JSON` value as `Text` in either JSON or YAML format.+let JSON =+ missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall++let Function/identity =+ missing+ sha256:f78b96792b459cb664f41c6119bd8897dd04353a3343521d436cd82ad71cb4d4+ ? ../Function/identity.dhall++let Text/concatMap =+ missing+ sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f+ ? ../Text/concatMap.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ../NonEmpty/Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ../NonEmpty/toList.dhall++let NonEmpty/concat =+ missing+ sha256:6d55181938c06c6b806877028f6a241912e9c0935d9a10dd958775bf21e0f64d+ ? ../NonEmpty/concat.dhall++let NonEmpty/map =+ missing+ sha256:93d53afe874bb2eed946c21ca5ada3c9716b7d00e6d8edfaba6484cd9c5a00bd+ ? ../NonEmpty/map.dhall++let NonEmpty/singleton =+ missing+ sha256:c9197aabe97695f7ca66f7419bf172d806b2c915594a8fc0d2ff6495db496ff2+ ? ../NonEmpty/singleton.dhall++let List/uncons+ : ∀(a : Type) → List a → Optional (NonEmpty a)+ = {- This version uses the `ls` argument only once to prevent cache blowups at the price+ of performing two passes over the list:+ A first one to reverse it, a second one with `List/fold` to determine+ the head element.+ See https://github.com/dhall-lang/dhall-lang/pull/1015#issuecomment-633381024+ for some context regarding the caching issue.+ -}+ λ(a : Type) →+ λ(ls : List a) →+ List/fold+ a+ (List/reverse a ls)+ (Optional (NonEmpty a))+ ( λ(x : a) →+ λ(acc : Optional (NonEmpty a)) →+ merge+ { None = Some (NonEmpty/singleton a x)+ , Some =+ λ(ne : NonEmpty a) → Some (ne ⫽ { tail = ne.tail # [ x ] })+ }+ acc+ )+ (None (NonEmpty a))++let NonEmpty/mapHead+ : ∀(a : Type) → (a → a) → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(fn : a → a) →+ λ(ls : NonEmpty a) →+ ls ⫽ { head = fn ls.head }++let NonEmpty/mapTail+ : ∀(a : Type) → (a → a) → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(fn : a → a) →+ λ(ls : NonEmpty a) →+ ls ⫽ { tail = List/map a a fn ls.tail }++let NonEmpty/prepend+ : ∀(a : Type) → a → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(prefix : a) →+ λ(ls : NonEmpty a) →+ { head = prefix, tail = NonEmpty/toList a ls }++let NonYtpme+ : Type → Type+ = λ(a : Type) → { init : List a, last : a }++let List/unsnoc+ : ∀(a : Type) → List a → Optional (NonYtpme a)+ = λ(a : Type) →+ λ(ls : List a) →+ List/fold+ a+ ls+ (Optional (NonYtpme a))+ ( λ(x : a) →+ λ(acc : Optional (NonYtpme a)) →+ merge+ { None = Some { init = [] : List a, last = x }+ , Some =+ λ(ny : NonYtpme a) → Some (ny ⫽ { init = [ x ] # ny.init })+ }+ acc+ )+ (None (NonYtpme a))++let NonEmpty/mapLast+ : ∀(a : Type) → (a → a) → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(fn : a → a) →+ λ(ls : NonEmpty a) →+ merge+ { Some = λ(x : NonYtpme a) → ls ⫽ { tail = x.init # [ fn x.last ] }+ , None = NonEmpty/singleton a (fn ls.head)+ }+ (List/unsnoc a ls.tail)++let NonEmpty/mapLeading+ : ∀(a : Type) → (a → a) → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(fn : a → a) →+ λ(ls : NonEmpty a) →+ merge+ { Some =+ λ(x : NonYtpme a) →+ { head = fn ls.head+ , tail = List/map a a fn x.init # [ x.last ]+ }+ , None = ls+ }+ (List/unsnoc a ls.tail)++let Lines+ : Type+ = NonEmpty Text++let Block+ : Type+ = < Simple : Text | Complex : Lines >++let Block/toLines+ : Block → Lines+ = λ(block : Block) →+ merge+ { Simple = NonEmpty/singleton Text+ , Complex = Function/identity Lines+ }+ block++let manyBlocks+ : ∀(a : Type) → Text → (NonEmpty a → Lines) → List a → Block+ = λ(a : Type) →+ λ(ifEmpty : Text) →+ λ(render : NonEmpty a → Lines) →+ λ(inputs : List a) →+ merge+ { Some = λ(inputs : NonEmpty a) → Block.Complex (render inputs)+ , None = Block.Simple ifEmpty+ }+ (List/uncons a inputs)++let blockToText+ : Block → Text+ = λ(block : Block) →+ Text/concatMap+ Text+ (λ(line : Text) → line ++ "\n")+ (NonEmpty/toList Text (Block/toLines block))++let addPrefix = λ(prefix : Text) → λ(line : Text) → prefix ++ line++let addIndent = addPrefix " "++let indentTail = NonEmpty/mapTail Text addIndent++let Format =+ missing+ sha256:d7936b510cfc091faa994652af0eb5feb889cd44bc989edbe4f1eb8c5623caac+ ? ./Format.dhall++let ObjectField = { mapKey : Text, mapValue : Block }++let -- Essentially the same thing as `Text/show`, except that this does not+ -- escape `$`+ escape =+ List/fold+ (Text → Text)+ [ Text/replace "\"" "\\\""+ , Text/replace "\b" "\\b"+ , Text/replace "\f" "\\f"+ , Text/replace "\n" "\\n"+ , Text/replace "\r" "\\r"+ , Text/replace "\t" "\\t"+ , Text/replace "\\" "\\\\"+ ]+ Text+ (λ(replace : Text → Text) → λ(text : Text) → replace text)++let renderJSONStruct =+ λ(prefix : Text) →+ λ(suffix : Text) →+ λ(blocks : NonEmpty Lines) →+ let indent = List/map Text Text addIndent++ let appendComma+ : Lines → Lines+ = NonEmpty/mapLast Text (λ(line : Text) → line ++ ",")++ let blocks = NonEmpty/mapLeading Lines appendComma blocks++ let block = NonEmpty/concat Text blocks++ in merge+ { None =+ NonEmpty/singleton Text "${prefix} ${block.head} ${suffix}"+ , Some =+ λ(ny : NonYtpme Text) →+ { head = prefix+ , tail =+ indent ([ block.head ] # ny.init # [ ny.last ])+ # [ suffix ]+ }+ }+ (List/unsnoc Text block.tail)++let renderObject =+ λ(format : Format) →+ λ(fields : NonEmpty ObjectField) →+ let keystr = λ(field : ObjectField) → "\"${escape field.mapKey}\":"++ let prefixKeyOnFirst =+ λ(field : ObjectField) →+ NonEmpty/mapHead+ Text+ (addPrefix "${keystr field} ")+ (Block/toLines field.mapValue)++ let prependKeyLine =+ λ(field : ObjectField) →+ NonEmpty/prepend+ Text+ (keystr field)+ (Block/toLines field.mapValue)++ let renderYAMLField =+ λ(field : ObjectField) →+ merge+ { Simple =+ λ(line : Text) →+ NonEmpty/singleton Text "${keystr field} ${line}"+ , Complex = λ(_ : Lines) → indentTail (prependKeyLine field)+ }+ field.mapValue++ in merge+ { JSON =+ renderJSONStruct+ "{"+ "}"+ (NonEmpty/map ObjectField Lines prefixKeyOnFirst fields)+ , YAML =+ NonEmpty/concat+ Text+ (NonEmpty/map ObjectField Lines renderYAMLField fields)+ }+ format++let renderYAMLArrayField =+ λ(block : Block) →+ NonEmpty/mapHead+ Text+ (addPrefix "- ")+ (indentTail (Block/toLines block))++let renderArray =+ λ(format : Format) →+ λ(fields : NonEmpty Block) →+ merge+ { JSON =+ renderJSONStruct+ "["+ "]"+ (NonEmpty/map Block Lines Block/toLines fields)+ , YAML =+ NonEmpty/concat+ Text+ (NonEmpty/map Block Lines renderYAMLArrayField fields)+ }+ format++let renderAs+ : Format → JSON.Type → Text+ = λ(format : Format) →+ λ(json : JSON.Type) →+ blockToText+ ( json+ Block+ { string = λ(x : Text) → Block.Simple "\"${escape x}\""+ , double = λ(x : Double) → Block.Simple (Double/show x)+ , integer = λ(x : Integer) → Block.Simple (JSON.renderInteger x)+ , object = manyBlocks ObjectField "{}" (renderObject format)+ , array = manyBlocks Block "[]" (renderArray format)+ , bool =+ λ(x : Bool) → Block.Simple (if x then "true" else "false")+ , null = Block.Simple "null"+ }+ )++let example0 =+ let data =+ JSON.array+ [ JSON.bool True+ , JSON.string "Hello"+ , JSON.object+ [ { mapKey = "foo", mapValue = JSON.null }+ , { mapKey = "bar", mapValue = JSON.double 1.0 }+ ]+ ]++ let yaml =+ assert+ : renderAs Format.YAML data+ ≡ ''+ - true+ - "Hello"+ - "foo": null+ "bar": 1.0+ ''++ let json =+ assert+ : renderAs Format.JSON data+ ≡ ''+ [+ true,+ "Hello",+ {+ "foo": null,+ "bar": 1.0+ }+ ]+ ''++ in True++let example1 =+ let data =+ JSON.object+ [ { mapKey = "zero", mapValue = JSON.array ([] : List JSON.Type) }+ , { mapKey = "one", mapValue = JSON.array [ JSON.string "a" ] }+ , { mapKey = "two"+ , mapValue = JSON.array [ JSON.string "a", JSON.string "b" ]+ }+ ]++ let yaml =+ assert+ : renderAs Format.YAML data+ ≡ ''+ "zero": []+ "one":+ - "a"+ "two":+ - "a"+ - "b"+ ''++ let json =+ assert+ : renderAs Format.JSON data+ ≡ ''+ {+ "zero": [],+ "one": [ "a" ],+ "two": [+ "a",+ "b"+ ]+ }+ ''++ in True++let example2 =+ let data =+ JSON.object+ [ { mapKey = "zero"+ , mapValue =+ JSON.object+ (toMap {=} : List { mapKey : Text, mapValue : JSON.Type })+ }+ , { mapKey = "one"+ , mapValue = JSON.object (toMap { a = JSON.null })+ }+ , { mapKey = "two"+ , mapValue =+ JSON.object (toMap { a = JSON.null, b = JSON.null })+ }+ ]++ let yaml =+ assert+ : renderAs Format.YAML data+ ≡ ''+ "zero": {}+ "one":+ "a": null+ "two":+ "a": null+ "b": null+ ''++ let json =+ assert+ : renderAs Format.JSON data+ ≡ ''+ {+ "zero": {},+ "one": { "a": null },+ "two": {+ "a": null,+ "b": null+ }+ }+ ''++ in True++let example3 =+ let specialCharacters =+ ''+ "\${"\b\f"}+ ${"\r"} $''++ let data =+ JSON.object+ [ { mapKey = specialCharacters+ , mapValue = JSON.string specialCharacters+ }+ ]++ in assert+ : renderAs Format.JSON data+ ≡ ''+ { "\"\\\b\f\n\r\t$": "\"\\\b\f\n\r\t$" }+ ''++in renderAs
@@ -0,0 +1,61 @@+--| This renders JSON on a single line+let JSON =+ missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall++let Text/concatMapSep =+ missing+ sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840+ ? ../Text/concatMapSep++let renderInteger =+ missing+ sha256:15b8d2ae46d5002832741927af787761df49798c911e2bf85db7a7b9cb5c078c+ ? ./renderInteger.dhall++let renderCompact+ : JSON.Type → Text+ = λ(j : JSON.Type) →+ j+ Text+ { string = Text/show+ , double = Double/show+ , integer = renderInteger+ , object =+ λ(x : List { mapKey : Text, mapValue : Text }) →+ let body =+ Text/concatMapSep+ ","+ { mapKey : Text, mapValue : Text }+ ( λ(e : { mapKey : Text, mapValue : Text }) →+ " ${Text/show e.mapKey}: ${e.mapValue}"+ )+ x++ in "{${body} }"+ , array =+ λ(x : List Text) →+ let body = Text/concatMapSep "," Text (λ(y : Text) → " ${y}") x++ in "[${body} ]"+ , bool = λ(x : Bool) → if x then "true" else "false"+ , null = "null"+ }++let example =+ assert+ : renderCompact+ ( JSON.array+ [ JSON.bool True+ , JSON.string "Hello"+ , JSON.object+ [ { mapKey = "foo", mapValue = JSON.null }+ , { mapKey = "bar", mapValue = JSON.double 1.1 }+ , { mapKey = "baz", mapValue = JSON.integer +2 }+ ]+ ]+ )+ ≡ "[ true, \"Hello\", { \"foo\": null, \"bar\": 1.1, \"baz\": 2 } ]"++in renderCompact
@@ -0,0 +1,23 @@+{-|+Render an `Integer` value as a `JSON number`, according to the JSON standard, in+which a number may not start with a plus sign (`+`).+-}+let Integer/nonNegative =+ missing+ sha256:b463373f070df6b1c8c7082051e0810fee38b360bab35256187c8c2b6af5c663+ ? ../Integer/nonNegative.dhall++let renderInteger+ : Integer → Text+ = λ(integer : Integer) →+ if Integer/nonNegative integer+ then Natural/show (Integer/clamp integer)+ else Integer/show integer++let positive = assert : renderInteger +1 ≡ "1"++let zero = assert : renderInteger +0 ≡ "0"++let negative = assert : renderInteger -1 ≡ "-1"++in renderInteger
@@ -0,0 +1,3 @@+ missing+ sha256:bc71449397bbf48103c3ebbdd570cd27313115e94b2b1b96761d257d5c02d478+? ./renderYAML.dhall
@@ -0,0 +1,49 @@+{-|+Render a `JSON` value as `Text` in YAML format.++The generated YAML text will only contain escaped object keys and+string values and might therefore not be very human readable.++However, it is useful for debugging `JSON` values or for tests.+For anything more sophisticated you should use `dhall-to-json` or+`dhall-to-yaml`.+-}+let JSON =+ missing+ sha256:5dc1135d5481cfd6fde625aaed9fcbdb7aa7c14f2e76726aa5fdef028a5c10f5+ ? ./core.dhall++let renderAs =+ missing+ sha256:c23be039c9601a33d6546fd99a8d72bee8dde5f46176d57cc96613b31a3bb471+ ? ./renderAs.dhall++let Format =+ missing+ sha256:d7936b510cfc091faa994652af0eb5feb889cd44bc989edbe4f1eb8c5623caac+ ? ./Format.dhall++let renderYAML+ : JSON.Type → Text+ = renderAs Format.YAML++let example0 =+ assert+ : renderYAML+ ( JSON.array+ [ JSON.bool True+ , JSON.string "Hello"+ , JSON.object+ [ { mapKey = "foo", mapValue = JSON.null }+ , { mapKey = "bar", mapValue = JSON.double 1.0 }+ ]+ ]+ )+ ≡ ''+ - true+ - "Hello"+ - "foo": null+ "bar": 1.0+ ''++in renderYAML
@@ -0,0 +1,3 @@+ missing+ sha256:7ddb3a3b9f3ed09ed011d621a10ad9825185cd03503be98a81d42f6afb77940e+? ./string.dhall
@@ -0,0 +1,35 @@+{-|+Create a JSON string from Dhall `Text`++```+let JSON = ./package.dhall+in JSON.render (JSON.string "ABC $ \" 🙂")+= "\"ABC \\u0024 \\\" 🙂\""++let JSON = ./package.dhall+in JSON.render (JSON.string "")+= "\"\""+```+-}+let JSON =+ missing+ sha256:40edbc9371979426df63e064333b02689b969c4cfbbccfa481216d2d1a6e9759+ ? ./Type.dhall++let string+ : Text → JSON+ = λ(x : Text) →+ λ(JSON : Type) →+ λ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ json.string x++in string
@@ -0,0 +1,3 @@+ missing+ sha256:49559ac11906ba6cc9eac25753e31e7addb13bc760df108024174c55523984c4+? ./tagInline.dhall
@@ -0,0 +1,29 @@+--| Prepare a union value for JSON- or YAML-encoding with the inline layout+let Nesting =+ missing+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting.dhall++let Tagged =+ missing+ sha256:21feca7d2b23f210d0696131d792e18a7d24fdcc85d41a49ba85b98670eba194+ ? ./Tagged.dhall++let tagInline+ : Text → ∀(a : Type) → a → Tagged a+ = λ(tagFieldName : Text) →+ λ(a : Type) →+ λ(contents : a) →+ { nesting = Nesting.Inline, field = tagFieldName, contents }++let example0 =+ let Example = < Left : { foo : Natural } | Right : { bar : Bool } >++ in assert+ : tagInline "name" Example (Example.Left { foo = 2 })+ ≡ { field = "name"+ , nesting = Nesting.Inline+ , contents = Example.Left { foo = 2 }+ }++in tagInline
@@ -0,0 +1,3 @@+ missing+ sha256:93a7415853b7677c832246efadc8e880c1b641a23589286a836a384ca311d26f+? ./tagNested.dhall
@@ -0,0 +1,33 @@+--| Prepare a union value for JSON- or YAML-encoding with the nested layout+let Nesting =+ missing+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting.dhall++let Tagged =+ missing+ sha256:21feca7d2b23f210d0696131d792e18a7d24fdcc85d41a49ba85b98670eba194+ ? ./Tagged.dhall++let tagNested+ : Text → Text → ∀(a : Type) → a → Tagged a+ = λ(contentsFieldName : Text) →+ λ(tagFieldName : Text) →+ λ(a : Type) →+ λ(contents : a) →+ { nesting = Nesting.Nested contentsFieldName+ , field = tagFieldName+ , contents+ }++let example0 =+ let Example = < Left : { foo : Natural } | Right : { bar : Bool } >++ in assert+ : tagNested "value" "name" Example (Example.Left { foo = 2 })+ ≡ { field = "name"+ , nesting = Nesting.Nested "value"+ , contents = Example.Left { foo = 2 }+ }++in tagNested
@@ -1,20 +1,3 @@-{--Returns `True` if the supplied function returns `True` for all elements in the-`List`--Examples:--```-./all Natural Natural/even [ 2, 3, 5 ] = False--./all Natural Natural/even ([] : List Natural) = True-```--}-let all- : ∀(a : Type) → (a → Bool) → List a → Bool- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x && r) True--in all+ missing+ sha256:7ac5bb6f77e9ffe9e2356d90968d39764a9a32f75980206e6b12f815bb83dd15+? ./all.dhall
@@ -0,0 +1,16 @@+{-|+Returns `True` if the supplied function returns `True` for all elements in the+`List`+-}+let all+ : ∀(a : Type) → (a → Bool) → List a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : List a) →+ List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x && r) True++let example0 = assert : all Natural Natural/even [ 2, 3, 5 ] ≡ False++let example1 = assert : all Natural Natural/even ([] : List Natural) ≡ True++in all
@@ -1,20 +1,3 @@-{--Returns `True` if the supplied function returns `True` for any element in the-`List`--Examples:--```-./any Natural Natural/even [ 2, 3, 5 ] = True--./any Natural Natural/even ([] : List Natural) = False-```--}-let any- : ∀(a : Type) → (a → Bool) → List a → Bool- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False--in any+ missing+ sha256:b8e9e13b25e799f342a81f6eda4075906eb1a19dfdcb10a0ca25925eba4033b8+? ./any.dhall
@@ -0,0 +1,16 @@+{-|+Returns `True` if the supplied function returns `True` for any element in the+`List`+-}+let any+ : ∀(a : Type) → (a → Bool) → List a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : List a) →+ List/fold a xs Bool (λ(x : a) → λ(r : Bool) → f x || r) False++let example0 = assert : any Natural Natural/even [ 2, 3, 5 ] ≡ True++let example1 = assert : any Natural Natural/even ([] : List Natural) ≡ False++in any
@@ -1,32 +1,3 @@-{--`build` is the inverse of `fold`--Examples:--```-./build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ cons "ABC" (cons "DEF" nil)-)-= [ "ABC", "DEF" ]--./build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ nil-)-= [] : List Text-```--}-let build- : ∀(a : Type)- → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)- → List a- = List/build--in build+ missing+ sha256:8cf73fc1e115cfcb79bb9cd490bfcbd45c824e93c57a0e64c86c0c72e9ebbe42+? ./build.dhall
@@ -0,0 +1,30 @@+--| `build` is the inverse of `fold`+let build+ : ∀(a : Type) →+ (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list) →+ List a+ = List/build++let example0 =+ assert+ : build+ Text+ ( λ(list : Type) →+ λ(cons : Text → list → list) →+ λ(nil : list) →+ cons "ABC" (cons "DEF" nil)+ )+ ≡ [ "ABC", "DEF" ]++let example1 =+ assert+ : build+ Text+ ( λ(list : Type) →+ λ(cons : Text → list → list) →+ λ(nil : list) →+ nil+ )+ ≡ ([] : List Text)++in build
@@ -1,42 +1,3 @@-{--Concatenate a `List` of `List`s into a single `List`--Examples:--```-./concat Natural-[ [0, 1, 2]-, [3, 4]-, [5, 6, 7, 8]-]-= [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]--./concat Natural-( [ [] : List Natural- , [] : List Natural- , [] : List Natural- ]-)-= [] : List Natural--./concat Natural ([] : List (List Natural)) = [] : List Natural-```--}-let concat- : ∀(a : Type) → List (List a) → List a- = λ(a : Type)- → λ(xss : List (List a))- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → λ(nil : list)- → List/fold- (List a)- xss- list- (λ(xs : List a) → λ(ys : list) → List/fold a xs list cons ys)- nil- )--in concat+ missing+ sha256:54e43278be13276e03bd1afa89e562e94a0a006377ebea7db14c7562b0de292b+? ./concat.dhall
@@ -0,0 +1,34 @@+--| Concatenate a `List` of `List`s into a single `List`+let concat+ : ∀(a : Type) → List (List a) → List a+ = λ(a : Type) →+ λ(xss : List (List a)) →+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ λ(nil : list) →+ List/fold+ (List a)+ xss+ list+ (λ(xs : List a) → λ(ys : list) → List/fold a xs list cons ys)+ nil+ )++let example0 =+ assert+ : concat Natural [ [ 0, 1, 2 ], [ 3, 4 ], [ 5, 6, 7, 8 ] ]+ ≡ [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]++let example1 =+ assert+ : concat+ Natural+ [ [] : List Natural, [] : List Natural, [] : List Natural ]+ ≡ ([] : List Natural)++let example2 =+ assert : concat Natural ([] : List (List Natural)) ≡ ([] : List Natural)++in concat
@@ -1,28 +1,3 @@-{--Transform a list by applying a function to each element and flattening the-results--Examples:--```-./concatMap Natural Natural (λ(n : Natural) → [n, n]) [2, 3, 5]-= [ 2, 2, 3, 3, 5, 5 ]--./concatMap Natural Natural (λ(n : Natural) → [n, n]) ([] : List Natural)-= [] : List Natural-```--}-let concatMap- : ∀(a : Type) → ∀(b : Type) → (a → List b) → List a → List b- = λ(a : Type)- → λ(b : Type)- → λ(f : a → List b)- → λ(xs : List a)- → List/build- b- ( λ(list : Type)- → λ(cons : b → list → list)- → List/fold a xs list (λ(x : a) → List/fold b (f x) list cons)- )--in concatMap+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+? ./concatMap.dhall
@@ -0,0 +1,32 @@+{-|+Transform a list by applying a function to each element and flattening the+results+-}+let concatMap+ : ∀(a : Type) → ∀(b : Type) → (a → List b) → List a → List b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → List b) →+ λ(xs : List a) →+ List/build+ b+ ( λ(list : Type) →+ λ(cons : b → list → list) →+ List/fold a xs list (λ(x : a) → List/fold b (f x) list cons)+ )++let example0 =+ assert+ : concatMap Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]+ ≡ [ 2, 2, 3, 3, 5, 5 ]++let example1 =+ assert+ : concatMap+ Natural+ Natural+ (λ(n : Natural) → [ n, n ])+ ([] : List Natural)+ ≡ ([] : List Natural)++in concatMap
@@ -0,0 +1,3 @@+ missing+ sha256:fd77809e497227403f42848ffcda05a3efab442d961027c34f3e31d5d24e6379+? ./default.dhall
@@ -0,0 +1,15 @@+{-|+Unpack an `Optional` containing a `List`, defaulting to an empty list when the+`Optional` is `None`+-}+let default+ : ∀(a : Type) → Optional (List a) → List a+ = λ(a : Type) →+ λ(o : Optional (List a)) →+ merge { Some = λ(l : List a) → l, None = [] : List a } o++let example0 = assert : default Bool (None (List Bool)) ≡ ([] : List Bool)++let example1 = assert : default Bool (Some [ True ]) ≡ [ True ]++in default
@@ -0,0 +1,3 @@+ missing+ sha256:af983ba3ead494dd72beed05c0f3a17c36a4244adedf7ced502c6512196ed0cf+? ./drop.dhall
@@ -0,0 +1,28 @@+--| Remove first `n` elements of a list+let Natural/greaterThanEqual =+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+ ? ../Natural/greaterThanEqual.dhall++let drop+ : ∀(n : Natural) → ∀(a : Type) → List a → List a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(xs : List a) →+ List/fold+ { index : Natural, value : a }+ (List/indexed a xs)+ (List a)+ ( λ(x : { index : Natural, value : a }) →+ λ(xs : List a) →+ if Natural/greaterThanEqual x.index n+ then [ x.value ] # xs+ else xs+ )+ ([] : List a)++let example = assert : drop 2 Natural [ 2, 3, 5 ] ≡ [ 5 ]++let example = assert : drop 5 Natural [ 2, 3, 5 ] ≡ ([] : List Natural)++in drop
@@ -0,0 +1,3 @@+ missing+ sha256:b2f561f35098c457353723c93a22bd5de28d26ecc5370814bef9dfda421e0147+? ./empty.dhall
@@ -0,0 +1,8 @@+--| An empty list of the given type+let empty+ : ∀(a : Type) → List a+ = λ(a : Type) → [] : List a++let example0 = assert : empty Bool ≡ ([] : List Bool)++in empty
@@ -1,30 +1,3 @@-{--Only keep elements of the list where the supplied function returns `True`--Examples:--```-./filter Natural Natural/even [ 2, 3, 5 ]-= [ 2 ]--./filter Natural Natural/odd [ 2, 3, 5 ]-= [ 3, 5 ]-```--}-let filter- : ∀(a : Type) → (a → Bool) → List a → List a- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : List a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- a- xs- list- (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)- )--in filter+ missing+ sha256:8ebfede5bbfe09675f246c33eb83964880ac615c4b1be8d856076fdbc4b26ba6+? ./filter.dhall
@@ -0,0 +1,22 @@+--| Only keep elements of the list where the supplied function returns `True`+let filter+ : ∀(a : Type) → (a → Bool) → List a → List a+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : List a) →+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ List/fold+ a+ xs+ list+ (λ(x : a) → λ(xs : list) → if f x then cons x xs else xs)+ )++let example0 = assert : filter Natural Natural/even [ 2, 3, 5 ] ≡ [ 2 ]++let example1 = assert : filter Natural Natural/odd [ 2, 3, 5 ] ≡ [ 3, 5 ]++in filter
@@ -0,0 +1,45 @@+--| Transform a list by applying a function to each element and omitting None results.+let List/concatMap =+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ./concatMap.dhall++let Optional/toList =+ missing+ sha256:d78f160c619119ef12389e48a629ce293d69f7624c8d016b7a4767ab400344c4+ ? ../Optional/toList.dhall++let filterMap+ : ∀(a : Type) → ∀(b : Type) → (a → Optional b) → List a → List b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ List/concatMap a b (λ(x : a) → Optional/toList b (f x))++let example0 =+ assert+ : filterMap+ (List Natural)+ Natural+ (List/head Natural)+ [ [ 1 ], [] : List Natural, [ 3, 4 ] ]+ ≡ [ 1, 3 ]++let example1 =+ let Example = < Left : Bool | Right : Natural >++ in assert+ : filterMap+ Example+ Natural+ ( λ(x : Example) →+ merge+ { Left = λ(_ : Bool) → None Natural+ , Right = λ(n : Natural) → Some n+ }+ x+ )+ [ Example.Left False, Example.Right 2, Example.Left True ]+ ≡ [ 2 ]++in filterMap
@@ -1,46 +1,3 @@-{--`fold` is the primitive function for consuming `List`s--If you treat the list `[ x, y, z ]` as `cons x (cons y (cons z nil))`, then a-`fold` just replaces each `cons` and `nil` with something else--Examples:--```- ./fold- Natural- [ 2, 3, 5 ]- Natural- (λ(x : Natural) → λ(y : Natural) → x + y)- 0-= 10-- λ(nil : Natural)-→ ./fold- Natural- [ 2, 3, 5 ]- Natural- (λ(x : Natural) → λ(y : Natural) → x + y)- nil-= λ(nil : Natural) → 2 + (3 + (5 + nil))-- λ(list : Type)-→ λ(cons : Natural → list → list)-→ λ(nil : list)-→ ./fold Natural [ 2, 3, 5 ] list cons nil-= λ(list : Type)-→ λ(cons : Natural → list → list)-→ λ(nil : list)-→ cons 2 (cons 3 (cons 5 nil))-```--}-let fold- : ∀(a : Type)- → List a- → ∀(list : Type)- → ∀(cons : a → list → list)- → ∀(nil : list)- → list- = List/fold--in fold+ missing+ sha256:10bb945c25ab3943bd9df5a32e633cbfae112b7d3af38591784687e436a8d814+? ./fold.dhall
@@ -0,0 +1,43 @@+{-|+`fold` is the primitive function for consuming `List`s++If you treat the list `[ x, y, z ]` as `cons x (cons y (cons z nil))`, then a+`fold` just replaces each `cons` and `nil` with something else+-}+let fold+ : ∀(a : Type) →+ List a →+ ∀(list : Type) →+ ∀(cons : a → list → list) →+ ∀(nil : list) →+ list+ = List/fold++let example0 =+ assert+ : fold+ Natural+ [ 2, 3, 5 ]+ Text+ (λ(x : Natural) → λ(y : Text) → Natural/show x ++ y)+ "0"+ ≡ "2350"++let example1 =+ λ(nil : Text) →+ assert+ : fold+ Natural+ [ 2, 3, 5 ]+ Text+ (λ(x : Natural) → λ(y : Text) → Natural/show x ++ y)+ nil+ ≡ "2" ++ ("3" ++ ("5" ++ nil))++let example2 =+ λ(cons : Natural → Text → Text) →+ λ(nil : Text) →+ assert+ : fold Natural [ 2, 3, 5 ] Text cons nil ≡ cons 2 (cons 3 (cons 5 nil))++in fold
@@ -0,0 +1,60 @@+{-|+`foldLeft` is like `List/fold` except that the accumulation starts from the left++If you treat the list `[ x, y, z ]` as `cons (cons (cons nil x) y) z`, then+`foldLeft` just replaces each `cons` and `nil` with something else+-}+let foldLeft+ : ∀(a : Type) →+ List a →+ ∀(list : Type) →+ ∀(cons : list → a → list) →+ ∀(nil : list) →+ list+ = λ(a : Type) →+ λ(xs : List a) →+ λ(list : Type) →+ λ(cons : list → a → list) →+ λ(nil : list) →+ List/fold+ a+ xs+ (list → list)+ (λ(x : a) → λ(f : list → list) → λ(l : list) → f (cons l x))+ (λ(l : list) → l)+ nil++let example0 =+ assert+ : foldLeft+ Natural+ [ 2, 3, 5 ]+ Text+ (λ(x : Text) → λ(y : Natural) → x ++ Natural/show y)+ "0"+ ≡ "0235"++let example1 =+ assert+ : ( λ(nil : Text) →+ foldLeft+ Natural+ [ 2, 3, 5 ]+ Text+ (λ(x : Text) → λ(y : Natural) → x ++ Natural/show y)+ nil+ )+ ≡ (λ(nil : Text) → nil ++ "2" ++ "3" ++ "5")++let example2 =+ assert+ : ( λ(cons : Text → Natural → Text) →+ λ(nil : Text) →+ foldLeft Natural [ 2, 3, 5 ] Text cons nil+ )+ ≡ ( λ(cons : Text → Natural → Text) →+ λ(nil : Text) →+ cons (cons (cons nil 2) 3) 5+ )++in foldLeft
@@ -1,38 +1,3 @@-{--Build a list by calling the supplied function on all `Natural` numbers from `0`-up to but not including the supplied `Natural` number--Examples:--```-./generate 5 Bool Natural/even = [ True, False, True, False, True ]--./generate 0 Bool Natural/even = [] : List Bool-```--}-let generate- : Natural → ∀(a : Type) → (Natural → a) → List a- = λ(n : Natural)- → λ(a : Type)- → λ(f : Natural → a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- { index : Natural, value : {} }- ( List/indexed- {}- ( List/build- {}- ( λ(list : Type)- → λ(cons : {} → list → list)- → Natural/fold n list (cons {=})- )- )- )- list- (λ(x : { index : Natural, value : {} }) → cons (f x.index))- )--in generate+ missing+ sha256:78ff1ad96c08b88a8263eea7bc8381c078225cfcb759c496f792edb5a5e0b1a4+? ./generate.dhall
@@ -0,0 +1,35 @@+{-|+Build a list by calling the supplied function on all `Natural` numbers from `0`+up to but not including the supplied `Natural` number+-}+let generate+ : Natural → ∀(a : Type) → (Natural → a) → List a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(f : Natural → a) →+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ List/fold+ { index : Natural, value : {} }+ ( List/indexed+ {}+ ( List/build+ {}+ ( λ(list : Type) →+ λ(cons : {} → list → list) →+ Natural/fold n list (cons {=})+ )+ )+ )+ list+ (λ(x : { index : Natural, value : {} }) → cons (f x.index))+ )++let example0 =+ assert : generate 5 Bool Natural/even ≡ [ True, False, True, False, True ]++let example1 = assert : generate 0 Bool Natural/even ≡ ([] : List Bool)++in generate
@@ -1,12 +1,3 @@-{--Retrieve the first element of the list--Examples:--```-./head Natural [ 0, 1, 2 ] = Some 0--./head Natural ([] : List Natural) = None Natural-```--}-let head : ∀(a : Type) → List a → Optional a = List/head in head+ missing+ sha256:0d2e65ba0aea908377e46d22020dc3ad970284f4ee4eb8e6b8c51e53038c0026+? ./head.dhall
@@ -0,0 +1,10 @@+--| Retrieve the first element of the list+let head+ : ∀(a : Type) → List a → Optional a+ = List/head++let example0 = assert : head Natural [ 0, 1, 2 ] ≡ Some 0++let example1 = assert : head Natural ([] : List Natural) ≡ None Natural++in head
@@ -0,0 +1,3 @@+ missing+ sha256:e657b55ecae4d899465c3032cb1a64c6aa6dc2aa3034204f3c15ce5c96c03e63+? ./index.dhall
@@ -0,0 +1,18 @@+--| Retrieve an element from a `List` using its 0-based index+let drop =+ missing+ sha256:af983ba3ead494dd72beed05c0f3a17c36a4244adedf7ced502c6512196ed0cf+ ? ./drop.dhall++let index+ : Natural → ∀(a : Type) → List a → Optional a+ = λ(n : Natural) → λ(a : Type) → λ(xs : List a) → List/head a (drop n a xs)++let property =+ λ(n : Natural) → λ(a : Type) → assert : index n a ([] : List a) ≡ None a++let example0 = assert : index 1 Natural [ 2, 3, 5 ] ≡ Some 3++let example1 = assert : index 1 Natural ([] : List Natural) ≡ None Natural++in index
@@ -1,21 +1,3 @@-{--Tag each element of the list with its index--Examples:--```-./indexed Bool [ True, False, True ]-= [ { index = 0, value = True }- , { index = 1, value = False }- , { index = 2, value = True }- ] : List { index : Natural, value : Bool }--./indexed Bool ([] : List Bool)-= [] : List { index : Natural, value : Bool }-```--}-let indexed- : ∀(a : Type) → List a → List { index : Natural, value : a }- = List/indexed--in indexed+ missing+ sha256:58bb44457fa81adf26f5123c1b2e8bef0c5aa22dac5fa5ebdfb7da84563b027f+? ./indexed.dhall
@@ -0,0 +1,19 @@+--| Tag each element of the list with its index+let indexed+ : ∀(a : Type) → List a → List { index : Natural, value : a }+ = List/indexed++let example0 =+ assert+ : indexed Bool [ True, False, True ]+ ≡ [ { index = 0, value = True }+ , { index = 1, value = False }+ , { index = 2, value = True }+ ]++let example1 =+ assert+ : indexed Bool ([] : List Bool)+ ≡ ([] : List { index : Natural, value : Bool })++in indexed
@@ -1,43 +1,3 @@-{--Generate a list of the specified length given a seed value and transition-function--Examples:--```-./iterate 10 Natural (λ(x : Natural) → x * 2) 1-= [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]--./iterate 0 Natural (λ(x : Natural) → x * 2) 1-= [] : List Natural-```--}-let iterate- : Natural → ∀(a : Type) → (a → a) → a → List a- = λ(n : Natural)- → λ(a : Type)- → λ(f : a → a)- → λ(x : a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- { index : Natural, value : {} }- ( List/indexed- {}- ( List/build- {}- ( λ(list : Type)- → λ(cons : {} → list → list)- → Natural/fold n list (cons {=})- )- )- )- list- ( λ(y : { index : Natural, value : {} })- → cons (Natural/fold y.index a f x)- )- )--in iterate+ missing+ sha256:e4999ccce190a2e2a6ab9cb188e3af6c40df474087827153005293f11bfe1d26+? ./iterate.dhall
@@ -0,0 +1,42 @@+{-|+Generate a list of the specified length given a seed value and transition+function+-}+let iterate+ : Natural → ∀(a : Type) → (a → a) → a → List a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(f : a → a) →+ λ(x : a) →+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ List/fold+ { index : Natural, value : {} }+ ( List/indexed+ {}+ ( List/build+ {}+ ( λ(list : Type) →+ λ(cons : {} → list → list) →+ Natural/fold n list (cons {=})+ )+ )+ )+ list+ ( λ(y : { index : Natural, value : {} }) →+ cons (Natural/fold y.index a f x)+ )+ )++let example0 =+ assert+ : iterate 10 Natural (λ(x : Natural) → x * 2) 1+ ≡ [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]++let example1 =+ assert+ : iterate 0 Natural (λ(x : Natural) → x * 2) 1 ≡ ([] : List Natural)++in iterate
@@ -1,12 +1,3 @@-{--Retrieve the last element of the list--Examples:--```-./last Natural [ 0, 1, 2 ] = Some 2--./last Natural ([] : List Natural) = None Natural-```--}-let last : ∀(a : Type) → List a → Optional a = List/last in last+ missing+ sha256:741226b741af152a1638491cdff7f3aa74baf080ada2e63429483f3d195a984d+? ./last.dhall
@@ -0,0 +1,10 @@+--| Retrieve the last element of the list+let last+ : ∀(a : Type) → List a → Optional a+ = List/last++let example0 = assert : last Natural [ 0, 1, 2 ] ≡ Some 2++let example1 = assert : last Natural ([] : List Natural) ≡ None Natural++in last
@@ -1,12 +1,3 @@-{--Returns the number of elements in a list--Examples:--```-./length Natural [ 0, 1, 2 ] = 3--./length Natural ([] : List Natural) = 0-```--}-let length : ∀(a : Type) → List a → Natural = List/length in length+ missing+ sha256:42c6812c7a9e3c6e6fad88f77c5b3849503964e071cb784e22c38c888a401461+? ./length.dhall
@@ -0,0 +1,10 @@+--| Returns the number of elements in a list+let length+ : ∀(a : Type) → List a → Natural+ = List/length++let example0 = assert : length Natural [ 0, 1, 2 ] ≡ 3++let example1 = assert : length Natural ([] : List Natural) ≡ 0++in length
@@ -1,27 +1,3 @@-{--Transform a list by applying a function to each element--Examples:--```-./map Natural Bool Natural/even [ 2, 3, 5 ]-= [ True, False, False ]--./map Natural Bool Natural/even ([] : List Natural)-= [] : List Bool-```--}-let map- : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b- = λ(a : Type)- → λ(b : Type)- → λ(f : a → b)- → λ(xs : List a)- → List/build- b- ( λ(list : Type)- → λ(cons : b → list → list)- → List/fold a xs list (λ(x : a) → cons (f x))- )--in map+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+? ./map.dhall
@@ -0,0 +1,23 @@+--| Transform a list by applying a function to each element+let map+ : ∀(a : Type) → ∀(b : Type) → (a → b) → List a → List b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → b) →+ λ(xs : List a) →+ List/build+ b+ ( λ(list : Type) →+ λ(cons : b → list → list) →+ List/fold a xs list (λ(x : a) → cons (f x))+ )++let example0 =+ assert+ : map Natural Bool Natural/even [ 2, 3, 5 ] ≡ [ True, False, False ]++let example1 =+ assert+ : map Natural Bool Natural/even ([] : List Natural) ≡ ([] : List Bool)++in map
@@ -0,0 +1,37 @@+--| Apply a function across a list, keeping only the `Some` results.+let List/unpackOptionals =+ missing+ sha256:0cbaa920f429cf7fc3907f8a9143203fe948883913560e6e1043223e6b3d05e4+ ? ./unpackOptionals.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ./map.dhall++let mapMaybe+ : ∀(a : Type) → ∀(b : Type) → (a → Optional b) → List a → List b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ λ(xs : List a) →+ List/unpackOptionals b (List/map a (Optional b) f xs)++let property =+ λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ assert : mapMaybe a b f ([] : List a) ≡ ([] : List b)++let example0 =+ assert+ : mapMaybe+ Natural+ Text+ ( λ(n : Natural) →+ if Natural/isZero n then None Text else Some (Natural/show n)+ )+ [ 0, 1, 2, 3 ]+ ≡ [ "1", "2", "3" ]++in mapMaybe
@@ -0,0 +1,41 @@+--| Transform a list by applying a function to each element with its index+let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ./map.dhall++let List/mapWithIndex+ : ∀(a : Type) → ∀(b : Type) → (Natural → a → b) → List a → List b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : Natural → a → b) →+ λ(xs : List a) →+ List/map+ { index : Natural, value : a }+ b+ (λ(i : { index : Natural, value : a }) → f i.index i.value)+ (List/indexed a xs)++let List/empty =+ missing+ sha256:b2f561f35098c457353723c93a22bd5de28d26ecc5370814bef9dfda421e0147+ ? ./empty.dhall++let List/replicate =+ missing+ sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347+ ? ./replicate.dhall++let example0 =+ assert+ : List/mapWithIndex+ Text+ (List Text)+ ( λ(index : Natural) →+ λ(value : Text) →+ List/replicate index Text value+ )+ [ "A", "B", "C" ]+ ≡ [ List/empty Text, [ "B" ], [ "C", "C" ] ]++in List/mapWithIndex
@@ -1,16 +1,3 @@-{--Returns `True` if the `List` is empty and `False` otherwise--Examples:--```-./null Natural [ 0, 1, 2 ] = False--./null Natural ([] : List Natural) = True-```--}-let null- : ∀(a : Type) → List a → Bool- = λ(a : Type) → λ(xs : List a) → Natural/isZero (List/length a xs)--in null+ missing+ sha256:2338e39637e9a50d66ae1482c0ed559bbcc11e9442bfca8f8c176bbcd9c4fc80+? ./null.dhall
@@ -0,0 +1,10 @@+--| Returns `True` if the `List` is empty and `False` otherwise+let null+ : ∀(a : Type) → List a → Bool+ = λ(a : Type) → λ(xs : List a) → Natural/isZero (List/length a xs)++let example0 = assert : null Natural [ 0, 1, 2 ] ≡ False++let example1 = assert : null Natural ([] : List Natural) ≡ True++in null
@@ -1,58 +1,125 @@ { all =- ./all sha256:7ac5bb6f77e9ffe9e2356d90968d39764a9a32f75980206e6b12f815bb83dd15- ? ./all+ missing+ sha256:7ac5bb6f77e9ffe9e2356d90968d39764a9a32f75980206e6b12f815bb83dd15+ ? ./all.dhall , any =- ./any sha256:b8e9e13b25e799f342a81f6eda4075906eb1a19dfdcb10a0ca25925eba4033b8- ? ./any+ missing+ sha256:b8e9e13b25e799f342a81f6eda4075906eb1a19dfdcb10a0ca25925eba4033b8+ ? ./any.dhall , build =- ./build sha256:8cf73fc1e115cfcb79bb9cd490bfcbd45c824e93c57a0e64c86c0c72e9ebbe42- ? ./build+ missing+ sha256:8cf73fc1e115cfcb79bb9cd490bfcbd45c824e93c57a0e64c86c0c72e9ebbe42+ ? ./build.dhall , concat =- ./concat sha256:54e43278be13276e03bd1afa89e562e94a0a006377ebea7db14c7562b0de292b- ? ./concat+ missing+ sha256:54e43278be13276e03bd1afa89e562e94a0a006377ebea7db14c7562b0de292b+ ? ./concat.dhall , concatMap =- ./concatMap sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64- ? ./concatMap+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ./concatMap.dhall+, default =+ missing+ sha256:fd77809e497227403f42848ffcda05a3efab442d961027c34f3e31d5d24e6379+ ? ./default.dhall+, drop =+ missing+ sha256:af983ba3ead494dd72beed05c0f3a17c36a4244adedf7ced502c6512196ed0cf+ ? ./drop.dhall+, empty =+ missing+ sha256:b2f561f35098c457353723c93a22bd5de28d26ecc5370814bef9dfda421e0147+ ? ./empty.dhall , filter =- ./filter sha256:8ebfede5bbfe09675f246c33eb83964880ac615c4b1be8d856076fdbc4b26ba6- ? ./filter+ missing+ sha256:8ebfede5bbfe09675f246c33eb83964880ac615c4b1be8d856076fdbc4b26ba6+ ? ./filter.dhall+, filterMap =+ missing+ sha256:94b7ed4204d1c79aaf55527ef51024e7085b8dd2896952cffbd12d8f95e16f46+ ? ./filterMap.dhall , fold =- ./fold sha256:10bb945c25ab3943bd9df5a32e633cbfae112b7d3af38591784687e436a8d814- ? ./fold+ missing+ sha256:10bb945c25ab3943bd9df5a32e633cbfae112b7d3af38591784687e436a8d814+ ? ./fold.dhall+, foldLeft =+ missing+ sha256:3c6ab57950fe644906b7bbdef0b9523440b6ee17773ebb8cbd41ffacb8bfab61+ ? ./foldLeft.dhall , generate =- ./generate sha256:78ff1ad96c08b88a8263eea7bc8381c078225cfcb759c496f792edb5a5e0b1a4- ? ./generate+ missing+ sha256:78ff1ad96c08b88a8263eea7bc8381c078225cfcb759c496f792edb5a5e0b1a4+ ? ./generate.dhall , head =- ./head sha256:0d2e65ba0aea908377e46d22020dc3ad970284f4ee4eb8e6b8c51e53038c0026- ? ./head+ missing+ sha256:0d2e65ba0aea908377e46d22020dc3ad970284f4ee4eb8e6b8c51e53038c0026+ ? ./head.dhall+, index =+ missing+ sha256:e657b55ecae4d899465c3032cb1a64c6aa6dc2aa3034204f3c15ce5c96c03e63+ ? ./index.dhall , indexed =- ./indexed sha256:58bb44457fa81adf26f5123c1b2e8bef0c5aa22dac5fa5ebdfb7da84563b027f- ? ./indexed+ missing+ sha256:58bb44457fa81adf26f5123c1b2e8bef0c5aa22dac5fa5ebdfb7da84563b027f+ ? ./indexed.dhall , iterate =- ./iterate sha256:e4999ccce190a2e2a6ab9cb188e3af6c40df474087827153005293f11bfe1d26- ? ./iterate+ missing+ sha256:e4999ccce190a2e2a6ab9cb188e3af6c40df474087827153005293f11bfe1d26+ ? ./iterate.dhall , last =- ./last sha256:741226b741af152a1638491cdff7f3aa74baf080ada2e63429483f3d195a984d- ? ./last+ missing+ sha256:741226b741af152a1638491cdff7f3aa74baf080ada2e63429483f3d195a984d+ ? ./last.dhall , length =- ./length sha256:42c6812c7a9e3c6e6fad88f77c5b3849503964e071cb784e22c38c888a401461- ? ./length+ missing+ sha256:42c6812c7a9e3c6e6fad88f77c5b3849503964e071cb784e22c38c888a401461+ ? ./length.dhall , map =- ./map sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680- ? ./map+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ./map.dhall+, mapMaybe =+ missing+ sha256:6f3c4f8c94577b46e7d30f8df7e82a269b0ad0a7e18c0f0370f243fd1127e77f+ ? ./mapMaybe.dhall+, mapWithIndex =+ missing+ sha256:98599e0b55c5d3ae75264ba90657c6f68c7ce32834bd12b215acaea711eed6eb+ ? ./mapWithIndex.dhall , null =- ./null sha256:2338e39637e9a50d66ae1482c0ed559bbcc11e9442bfca8f8c176bbcd9c4fc80- ? ./null+ missing+ sha256:2338e39637e9a50d66ae1482c0ed559bbcc11e9442bfca8f8c176bbcd9c4fc80+ ? ./null.dhall+, partition =+ missing+ sha256:38147ac6d750a6492736dd90cc967bf09aa405c499de943c64fab7b86ae02f03+ ? ./partition.dhall , replicate =- ./replicate sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347- ? ./replicate+ missing+ sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347+ ? ./replicate.dhall , reverse =- ./reverse sha256:ad99d224d61852de6696da5a7d04c98dbe676fe67d5e4ef4f19e9aaa27006e9d- ? ./reverse+ missing+ sha256:ad99d224d61852de6696da5a7d04c98dbe676fe67d5e4ef4f19e9aaa27006e9d+ ? ./reverse.dhall , shifted =- ./shifted sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe- ? ./shifted+ missing+ sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe+ ? ./shifted.dhall+, take =+ missing+ sha256:b3e08ee8c3a5bf3d8ccee6b2b2008fbb8e51e7373aef6f1af67ad10078c9fbfa+ ? ./take.dhall+, unpackOptionals =+ missing+ sha256:0cbaa920f429cf7fc3907f8a9143203fe948883913560e6e1043223e6b3d05e4+ ? ./unpackOptionals.dhall , unzip =- ./unzip sha256:4d6003e9e683a289fe33f4c90f958eb1e08ea0bbb474210fcd90d1885c9660e9- ? ./unzip+ missing+ sha256:4d6003e9e683a289fe33f4c90f958eb1e08ea0bbb474210fcd90d1885c9660e9+ ? ./unzip.dhall+, zip =+ missing+ sha256:85ed955eabf3998767f4ad2a28e57d40cd4c68a95519d79e9b622f1d26d979da+ ? ./zip.dhall }
@@ -0,0 +1,3 @@+ missing+ sha256:38147ac6d750a6492736dd90cc967bf09aa405c499de943c64fab7b86ae02f03+? ./partition.dhall
@@ -0,0 +1,31 @@+{-|+`partition` divides a `List` of elements into those that satisfy a predicate+and those that do not+-}+let Partition+ : Type → Type+ = λ(a : Type) → { true : List a, false : List a }++let partition+ : ∀(a : Type) → (a → Bool) → List a → Partition a+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : List a) →+ List/fold+ a+ xs+ (Partition a)+ ( λ(x : a) →+ λ(p : Partition a) →+ if f x+ then { true = [ x ] # p.true, false = p.false }+ else { true = p.true, false = [ x ] # p.false }+ )+ { true = [] : List a, false = [] : List a }++let example0 =+ assert+ : partition Natural Natural/even [ 0, 1, 2, 3 ]+ ≡ { true = [ 0, 2 ], false = [ 1, 3 ] }++in partition
@@ -1,24 +1,3 @@-{--Build a list by copying the given element the specified number of times--Examples:--```-./replicate 9 Natural 1 = [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]--./replicate 0 Natural 1 = [] : List Natural-```--}-let replicate- : Natural → ∀(a : Type) → a → List a- = λ(n : Natural)- → λ(a : Type)- → λ(x : a)- → List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → Natural/fold n list (cons x)- )--in replicate+ missing+ sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347+? ./replicate.dhall
@@ -0,0 +1,18 @@+--| Build a list by copying the given element the specified number of times+let replicate+ : Natural → ∀(a : Type) → a → List a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(x : a) →+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ Natural/fold n list (cons x)+ )++let example0 = assert : replicate 9 Natural 1 ≡ [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]++let example1 = assert : replicate 0 Natural 1 ≡ ([] : List Natural)++in replicate
@@ -1,12 +1,3 @@-{--Reverse a list--Examples:--```-./reverse Natural [ 0, 1, 2 ] = [ 2, 1, 0 ] : List Natural--./reverse Natural ([] : List Natural) = [] : List Natural-```--}-let reverse : ∀(a : Type) → List a → List a = List/reverse in reverse+ missing+ sha256:ad99d224d61852de6696da5a7d04c98dbe676fe67d5e4ef4f19e9aaa27006e9d+? ./reverse.dhall
@@ -0,0 +1,11 @@+--| Reverse a list+let reverse+ : ∀(a : Type) → List a → List a+ = List/reverse++let example0 = assert : reverse Natural [ 0, 1, 2 ] ≡ [ 2, 1, 0 ]++let example1 =+ assert : reverse Natural ([] : List Natural) ≡ ([] : List Natural)++in reverse
@@ -1,86 +1,3 @@-{--Combine a `List` of `List`s, offsetting the `index` of each element by the-number of elements in preceding lists--Examples:--```-./shifted-Bool-[ [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = True }- ]-, [ { index = 0, value = False }- , { index = 1, value = False }- ]-, [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = True }- , { index = 3, value = True }- ]-]-= [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = True }- , { index = 3, value = False }- , { index = 4, value = False }- , { index = 5, value = True }- , { index = 6, value = True }- , { index = 7, value = True }- , { index = 8, value = True }- ]--./shifted Bool ([] : List (List { index : Natural, value : Bool }))-= [] : List { index : Natural, value : Bool }-```--}-let shifted- : ∀(a : Type)- → List (List { index : Natural, value : a })- → List { index : Natural, value : a }- = λ(a : Type)- → λ(kvss : List (List { index : Natural, value : a }))- → List/build- { index : Natural, value : a }- ( λ(list : Type)- → λ(cons : { index : Natural, value : a } → list → list)- → λ(nil : list)- → let result =- List/fold- (List { index : Natural, value : a })- kvss- { count : Natural, diff : Natural → list }- ( λ(kvs : List { index : Natural, value : a })- → λ(y : { count : Natural, diff : Natural → list })- → let length =- List/length { index : Natural, value : a } kvs- - in { count =- y.count + length- , diff =- λ(n : Natural)- → List/fold- { index : Natural, value : a }- kvs- list- ( λ(kvOld : { index : Natural, value : a })- → λ(z : list)- → let kvNew =- { index =- kvOld.index + n- , value =- kvOld.value- }- - in cons kvNew z- )- (y.diff (n + length))- }- )- { count = 0, diff = λ(_ : Natural) → nil }- - in result.diff 0- )--in shifted+ missing+ sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe+? ./shifted.dhall
@@ -0,0 +1,83 @@+{-|+Combine a `List` of `List`s, offsetting the `index` of each element by the+number of elements in preceding lists+-}+let shifted+ : ∀(a : Type) →+ List (List { index : Natural, value : a }) →+ List { index : Natural, value : a }+ = λ(a : Type) →+ λ(kvss : List (List { index : Natural, value : a })) →+ List/build+ { index : Natural, value : a }+ ( λ(list : Type) →+ λ(cons : { index : Natural, value : a } → list → list) →+ λ(nil : list) →+ let result =+ List/fold+ (List { index : Natural, value : a })+ kvss+ { count : Natural, diff : Natural → list }+ ( λ(kvs : List { index : Natural, value : a }) →+ λ(y : { count : Natural, diff : Natural → list }) →+ let length =+ List/length { index : Natural, value : a } kvs++ in { count = y.count + length+ , diff =+ λ(n : Natural) →+ List/fold+ { index : Natural, value : a }+ kvs+ list+ ( λ ( kvOld+ : { index : Natural, value : a }+ ) →+ λ(z : list) →+ let kvNew =+ { index = kvOld.index + n+ , value = kvOld.value+ }++ in cons kvNew z+ )+ (y.diff (n + length))+ }+ )+ { count = 0, diff = λ(_ : Natural) → nil }++ in result.diff 0+ )++let example0 =+ assert+ : shifted+ Bool+ [ [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = True }+ ]+ , [ { index = 0, value = False }, { index = 1, value = False } ]+ , [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = True }+ ]+ ]+ ≡ [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = False }+ , { index = 4, value = False }+ , { index = 5, value = True }+ , { index = 6, value = True }+ , { index = 7, value = True }+ , { index = 8, value = True }+ ]++let example1 =+ assert+ : shifted Bool ([] : List (List { index : Natural, value : Bool }))+ ≡ ([] : List { index : Natural, value : Bool })++in shifted
@@ -0,0 +1,3 @@+ missing+ sha256:b3e08ee8c3a5bf3d8ccee6b2b2008fbb8e51e7373aef6f1af67ad10078c9fbfa+? ./take.dhall
@@ -0,0 +1,26 @@+--| Truncate a list to the first `n` elements+let Natural/lessThan =+ missing+ sha256:3381b66749290769badf8855d8a3f4af62e8de52d1364d838a9d1e20c94fa70c+ ? ../Natural/lessThan.dhall++let take+ : ∀(n : Natural) → ∀(a : Type) → List a → List a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(xs : List a) →+ List/fold+ { index : Natural, value : a }+ (List/indexed a xs)+ (List a)+ ( λ(x : { index : Natural, value : a }) →+ λ(xs : List a) →+ if Natural/lessThan x.index n then [ x.value ] # xs else xs+ )+ ([] : List a)++let example = assert : take 2 Natural [ 2, 3, 5 ] ≡ [ 2, 3 ]++let example = assert : take 5 Natural [ 2, 3, 5 ] ≡ [ 2, 3, 5 ]++in take
@@ -0,0 +1,3 @@+ missing+ sha256:0cbaa920f429cf7fc3907f8a9143203fe948883913560e6e1043223e6b3d05e4+? ./unpackOptionals.dhall
@@ -0,0 +1,31 @@+--| Unpack Optionals in a List, omitting None items.+let List/filterMap =+ missing+ sha256:94b7ed4204d1c79aaf55527ef51024e7085b8dd2896952cffbd12d8f95e16f46+ ? ./filterMap.dhall++let unpackOptionals+ : ∀(a : Type) → ∀(l : List (Optional a)) → List a+ = λ(a : Type) → List/filterMap (Optional a) a (λ(x : Optional a) → x)++let property1 =+ λ(a : Type) → λ(x : a) → assert : unpackOptionals a [ Some x ] ≡ [ x ]++let property2 =+ λ(a : Type) → assert : unpackOptionals a [ None a ] ≡ ([] : List a)++let example0 =+ assert+ : unpackOptionals Natural [ Some 1, None Natural, Some 3 ] ≡ [ 1, 3 ]++let example1 =+ assert+ : unpackOptionals Natural ([] : List (Optional Natural))+ ≡ ([] : List Natural)++let example2 =+ assert+ : unpackOptionals Natural [ None Natural, None Natural ]+ ≡ ([] : List Natural)++in unpackOptionals
@@ -1,55 +1,3 @@-{--Unzip a `List` into two separate `List`s--Examples:--```-./unzip-Text-Bool-( [ { _1 = "ABC", _2 = True }- , { _1 = "DEF", _2 = False }- , { _1 = "GHI", _2 = True }- ]-)-= { _1 = [ "ABC", "DEF", "GHI" ]- , _2 = [ True, False, True ]- }--./unzip Text Bool ([] : List { _1 : Text, _2 : Bool })-= { _1 = [] : List Text, _2 = [] : List Bool }-```--}-let unzip- : ∀(a : Type)- → ∀(b : Type)- → List { _1 : a, _2 : b }- → { _1 : List a, _2 : List b }- = λ(a : Type)- → λ(b : Type)- → λ(xs : List { _1 : a, _2 : b })- → { _1 =- List/build- a- ( λ(list : Type)- → λ(cons : a → list → list)- → List/fold- { _1 : a, _2 : b }- xs- list- (λ(x : { _1 : a, _2 : b }) → cons x._1)- )- , _2 =- List/build- b- ( λ(list : Type)- → λ(cons : b → list → list)- → List/fold- { _1 : a, _2 : b }- xs- list- (λ(x : { _1 : a, _2 : b }) → cons x._2)- )- }--in unzip+ missing+ sha256:4d6003e9e683a289fe33f4c90f958eb1e08ea0bbb474210fcd90d1885c9660e9+? ./unzip.dhall
@@ -0,0 +1,50 @@+--| Unzip a `List` into two separate `List`s+let unzip+ : ∀(a : Type) →+ ∀(b : Type) →+ List { _1 : a, _2 : b } →+ { _1 : List a, _2 : List b }+ = λ(a : Type) →+ λ(b : Type) →+ λ(xs : List { _1 : a, _2 : b }) →+ { _1 =+ List/build+ a+ ( λ(list : Type) →+ λ(cons : a → list → list) →+ List/fold+ { _1 : a, _2 : b }+ xs+ list+ (λ(x : { _1 : a, _2 : b }) → cons x._1)+ )+ , _2 =+ List/build+ b+ ( λ(list : Type) →+ λ(cons : b → list → list) →+ List/fold+ { _1 : a, _2 : b }+ xs+ list+ (λ(x : { _1 : a, _2 : b }) → cons x._2)+ )+ }++let example0 =+ assert+ : unzip+ Text+ Bool+ [ { _1 = "ABC", _2 = True }+ , { _1 = "DEF", _2 = False }+ , { _1 = "GHI", _2 = True }+ ]+ ≡ { _1 = [ "ABC", "DEF", "GHI" ], _2 = [ True, False, True ] }++let example1 =+ assert+ : unzip Text Bool ([] : List { _1 : Text, _2 : Bool })+ ≡ { _1 = [] : List Text, _2 = [] : List Bool }++in unzip
@@ -0,0 +1,3 @@+ missing+ sha256:85ed955eabf3998767f4ad2a28e57d40cd4c68a95519d79e9b622f1d26d979da+? ./zip.dhall
@@ -0,0 +1,58 @@+{-|+Zip two `List` into a single `List`++The resulting `List` will have the length of the shortest of its arguments.+-}+let List/index =+ missing+ sha256:e657b55ecae4d899465c3032cb1a64c6aa6dc2aa3034204f3c15ce5c96c03e63+ ? ./index.dhall++let zip+ : ∀(a : Type) → List a → ∀(b : Type) → List b → List { _1 : a, _2 : b }+ = λ(a : Type) →+ λ(xs : List a) →+ λ(b : Type) →+ λ(ys : List b) →+ let ixs = List/indexed a xs++ in List/build+ { _1 : a, _2 : b }+ ( λ(list : Type) →+ λ(cons : { _1 : a, _2 : b } → list → list) →+ λ(nil : list) →+ List/fold+ { index : Natural, value : a }+ ixs+ list+ ( λ(ix : { index : Natural, value : a }) →+ λ(rest : list) →+ merge+ { None = rest+ , Some =+ λ(y : b) → cons { _1 = ix.value, _2 = y } rest+ }+ (List/index ix.index b ys)+ )+ nil+ )++let example0 =+ assert+ : zip Text [ "ABC", "DEF", "GHI" ] Natural [ 1, 2, 3 ]+ ≡ [ { _1 = "ABC", _2 = 1 }+ , { _1 = "DEF", _2 = 2 }+ , { _1 = "GHI", _2 = 3 }+ ]++let example1 =+ assert+ : zip Text [ "ABC" ] Bool ([] : List Bool)+ ≡ ([] : List { _1 : Text, _2 : Bool })++let example2 =+ assert+ : zip Text [ "ABC", "DEF", "GHI" ] Natural [ 1 ]+ ≡ [ { _1 = "ABC", _2 = 1 } ]++in zip
@@ -0,0 +1,3 @@+ missing+ sha256:613ebb491aeef4ff06368058b4f0e6e3bb8a58d8c145131fc0b947aac045a529+? ./Type.dhall
@@ -0,0 +1,15 @@+--| This is the union type returned when you import something `as Location`+let Location+ : Type+ = < Environment : Text | Local : Text | Missing | Remote : Text >++let example0 =+ assert+ : missing as Location+ ≡ < Environment : Text+ | Local : Text+ | Missing+ | Remote : Text+ >.Missing++in Location
@@ -0,0 +1,5 @@+{ Type =+ missing+ sha256:613ebb491aeef4ff06368058b4f0e6e3bb8a58d8c145131fc0b947aac045a529+ ? ./Type.dhall+}
@@ -0,0 +1,3 @@+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+? ./Entry.dhall
@@ -0,0 +1,6 @@+--| The type of each key-value pair in a `Map`+let Entry+ : Type → Type → Type+ = λ(k : Type) → λ(v : Type) → { mapKey : k, mapValue : v }++in Entry
@@ -0,0 +1,3 @@+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+? ./Type.dhall
@@ -0,0 +1,25 @@+{-|+This is the canonical way to encode a dynamic list of key-value pairs.++Tools (such as `dhall-to-json`/`dhall-to-yaml` will recognize values of this+type and convert them to maps/dictionaries/hashes in the target language++For example, `dhall-to-json` converts a Dhall value like this:++```+[ { mapKey = "foo", mapValue = 1 }+, { mapKey = "bar", mapValue = 2 }+] : ./Map Text Natural+```++... to a JSON value like this:++```+{ "foo": 1, "bar", 2 }+```+-}+let Map+ : Type → Type → Type+ = λ(k : Type) → λ(v : Type) → List { mapKey : k, mapValue : v }++in Map
@@ -0,0 +1,3 @@+ missing+ sha256:4c612558b8bbe8f955550ed3fb295d57b1b864c85cd52615b52d0ee0e9682e52+? ./empty.dhall
@@ -0,0 +1,14 @@+--| An empty `Map` of the given key and value types+let Map =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let empty+ : ∀(k : Type) → ∀(v : Type) → Map k v+ = λ(k : Type) → λ(v : Type) → [] : Map k v++let example0 =+ assert : empty Text Bool ≡ ([] : List { mapKey : Text, mapValue : Bool })++in empty
@@ -0,0 +1,3 @@+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+? ./keyText.dhall
@@ -0,0 +1,15 @@+{-|+Builds a key-value record such that a `List` of them will be converted to a+homogeneous record by dhall-to-json and dhall-to-yaml.++Both key and value are fixed to `Text`.++Take a look at `./keyValue` for a polymorphic version.+-}+let keyText =+ λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }++let example0 =+ assert : keyText "foo" "bar" ≡ { mapKey = "foo", mapValue = "bar" }++in keyText
@@ -0,0 +1,3 @@+ missing+ sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c+? ./keyValue.dhall
@@ -0,0 +1,17 @@+{-|+Builds a key-value record such that a List of them will be converted to a+homogeneous record by dhall-to-json and dhall-to-yaml.+-}+let keyValue =+ λ(v : Type) →+ λ(key : Text) →+ λ(value : v) →+ { mapKey = key, mapValue = value }++let example0 =+ assert : keyValue Natural "foo" 2 ≡ { mapKey = "foo", mapValue = 2 }++let example1 =+ assert : keyValue Text "bar" "baz" ≡ { mapKey = "bar", mapValue = "baz" }++in keyValue
@@ -0,0 +1,3 @@+ missing+ sha256:d13ec34e6acf7c349d82272ef09a37c7bdf37f0dab489e9df47a1ff215d9f5e7+? ./keys.dhall
@@ -0,0 +1,39 @@+--| Get all of the keys of a `Map` as a `List`+let Map =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let Entry =+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+ ? ./Entry.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map++let keys+ : ∀(k : Type) → ∀(v : Type) → Map k v → List k+ = λ(k : Type) →+ λ(v : Type) →+ List/map (Entry k v) k (λ(x : Entry k v) → x.mapKey)++let example0 =+ assert+ : keys+ Text+ Natural+ [ { mapKey = "A", mapValue = 2 }+ , { mapKey = "B", mapValue = 3 }+ , { mapKey = "C", mapValue = 5 }+ ]+ ≡ [ "A", "B", "C" ]++let example1 =+ assert+ : keys Text Natural ([] : List { mapKey : Text, mapValue : Natural })+ ≡ ([] : List Text)++in keys
@@ -0,0 +1,3 @@+ missing+ sha256:23e09b0b9f08649797dfe1ca39755d5e1c7cad2d0944bdd36c7a0bf804bde8d0+? ./map.dhall
@@ -0,0 +1,58 @@+--| Transform a `Map` by applying a function to each value+let Map =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let Entry =+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+ ? ./Entry.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let map+ : ∀(k : Type) → ∀(a : Type) → ∀(b : Type) → (a → b) → Map k a → Map k b+ = λ(k : Type) →+ λ(a : Type) →+ λ(b : Type) →+ λ(f : a → b) →+ λ(m : Map k a) →+ List/map+ (Entry k a)+ (Entry k b)+ ( λ(before : Entry k a) →+ { mapKey = before.mapKey, mapValue = f before.mapValue }+ )+ m++let example0 =+ assert+ : map+ Text+ Natural+ Bool+ Natural/even+ [ { mapKey = "A", mapValue = 2 }+ , { mapKey = "B", mapValue = 3 }+ , { mapKey = "C", mapValue = 5 }+ ]+ ≡ [ { mapKey = "A", mapValue = True }+ , { mapKey = "B", mapValue = False }+ , { mapKey = "C", mapValue = False }+ ]++let example1 =+ assert+ : map+ Text+ Natural+ Bool+ Natural/even+ ([] : List { mapKey : Text, mapValue : Natural })+ ≡ ([] : List { mapKey : Text, mapValue : Bool })++in map
@@ -0,0 +1,56 @@+--| Apply a function across the values of a `Map k v`, dropping+-- entries whose values return `None`.+let Map/empty =+ missing+ sha256:4c612558b8bbe8f955550ed3fb295d57b1b864c85cd52615b52d0ee0e9682e52+ ? ./empty.dhall++let Map/unpackOptionals =+ missing+ sha256:66c3e6f6f81418cf99342e1dba739617c01af4b27c1ca5e2e1d7bce64a522e22+ ? ./unpackOptionals.dhall++let Map/map =+ missing+ sha256:23e09b0b9f08649797dfe1ca39755d5e1c7cad2d0944bdd36c7a0bf804bde8d0+ ? ./map.dhall++let Map/Type =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let mapMaybe+ : ∀(k : Type) →+ ∀(a : Type) →+ ∀(b : Type) →+ (a → Optional b) →+ Map/Type k a →+ Map/Type k b+ = λ(k : Type) →+ λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ λ(m : Map/Type k a) →+ Map/unpackOptionals k b (Map/map k a (Optional b) f m)++let property =+ λ(k : Type) →+ λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ assert : mapMaybe k a b f (Map/empty k a) ≡ Map/empty k b++let example0 =+ assert+ : mapMaybe+ Text+ Natural+ Text+ ( λ(n : Natural) →+ if Natural/isZero n then None Text else Some (Natural/show n)+ )+ (toMap { foo = 2, bar = 0 })+ ≡ toMap { foo = "2" }++in mapMaybe
@@ -0,0 +1,41 @@+{ Type =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type+, Entry =+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+ ? ./Entry+, empty =+ missing+ sha256:4c612558b8bbe8f955550ed3fb295d57b1b864c85cd52615b52d0ee0e9682e52+ ? ./empty+, keyText =+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+ ? ./keyText+, keyValue =+ missing+ sha256:a0a97199d280c4cce72ffcbbf93b7ceda0a569cf4d173ac98e0aaaa78034b98c+ ? ./keyValue+, keys =+ missing+ sha256:d13ec34e6acf7c349d82272ef09a37c7bdf37f0dab489e9df47a1ff215d9f5e7+ ? ./keys+, map =+ missing+ sha256:23e09b0b9f08649797dfe1ca39755d5e1c7cad2d0944bdd36c7a0bf804bde8d0+ ? ./map+, mapMaybe =+ missing+ sha256:4ea58b720d7af38cef3ef07bef36e476caeed21032cd4a9dc733868a74d9a521+ ? ./mapMaybe.dhall+, unpackOptionals =+ missing+ sha256:66c3e6f6f81418cf99342e1dba739617c01af4b27c1ca5e2e1d7bce64a522e22+ ? ./unpackOptionals.dhall+, values =+ missing+ sha256:ae02cfb06a9307cbecc06130e84fd0c7b96b7f1f11648961e1b030ec00940be8+ ? ./values+}
@@ -0,0 +1,41 @@+--| Turn a `Map k (Optional v)` into a `Map k v` by dropping all+-- entries with value `None`.+let List/concatMap =+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ../List/concatMap.dhall++let Map/Entry =+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+ ? ./Entry.dhall++let Map/Type =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let unpackOptionals+ : ∀(k : Type) → ∀(v : Type) → Map/Type k (Optional v) → Map/Type k v+ = λ(k : Type) →+ λ(v : Type) →+ List/concatMap+ (Map/Entry k (Optional v))+ (Map/Entry k v)+ ( λ(e : Map/Entry k (Optional v)) →+ merge+ { None = [] : Map/Type k v+ , Some = λ(v : v) → [ { mapKey = e.mapKey, mapValue = v } ]+ }+ e.mapValue+ )++let example0 =+ assert+ : unpackOptionals+ Text+ Text+ (toMap { foo = Some "bar", baz = None Text })+ ≡ toMap { foo = "bar" }++in unpackOptionals
@@ -0,0 +1,3 @@+ missing+ sha256:ae02cfb06a9307cbecc06130e84fd0c7b96b7f1f11648961e1b030ec00940be8+? ./values.dhall
@@ -0,0 +1,39 @@+--| Get all of the values of a `Map` as a `List`+let Map =+ missing+ sha256:210c7a9eba71efbb0f7a66b3dcf8b9d3976ffc2bc0e907aadfb6aa29c333e8ed+ ? ./Type.dhall++let Entry =+ missing+ sha256:f334283bdd9cd88e6ea510ca914bc221fc2dab5fb424d24514b2e0df600d5346+ ? ./Entry.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let values+ : ∀(k : Type) → ∀(v : Type) → Map k v → List v+ = λ(k : Type) →+ λ(v : Type) →+ List/map (Entry k v) v (λ(x : Entry k v) → x.mapValue)++let example0 =+ assert+ : values+ Text+ Natural+ [ { mapKey = "A", mapValue = 2 }+ , { mapKey = "B", mapValue = 3 }+ , { mapKey = "C", mapValue = 5 }+ ]+ ≡ [ 2, 3, 5 ]++let example1 =+ assert+ : values Text Natural ([] : List { mapKey : Text, mapValue : Natural })+ ≡ ([] : List Natural)++in values
@@ -1,39 +1,3 @@-{--Any function `f` that is a `Monoid` must satisfy the following law:--```-t : Type-f : ./Monoid t-xs : List (List t)--f (./List/concat t xs) = f (./map (List t) t f xs)-```--Examples:--```-./Bool/and- : ./Monoid Bool-./Bool/or- : ./Monoid Bool-./Bool/even- : ./Monoid Bool-./Bool/odd- : ./Monoid Bool-./List/concat- : ∀(a : Type) → ./Monoid (List a)-./List/shifted- : ∀(a : Type) → ./Monoid (List { index : Natural, value : a })-./Natural/sum- : ./Monoid Natural-./Natural/product- : ./Monoid Natural-./Optional/head- : ∀(a : Type) → ./Monoid (Optional a)-./Optional/last- : ∀(a : Type) → ./Monoid (Optional a)-./Text/concat- : ./Monoid Text-```--}-let Monoid : ∀(m : Type) → Type = λ(m : Type) → List m → m in Monoid+ missing+ sha256:26fafa098600ef7a54ef9dba5ada416bbbdd21df1af306c052420c61553ad4af+? ./Monoid.dhall
@@ -0,0 +1,43 @@+{-|+Any function `f` that is a `Monoid` must satisfy the following law:++```+t : Type+f : ./Monoid t+xs : List (List t)++f (./List/concat t xs) = f (./map (List t) t f xs)+```++Examples:++```+./Bool/and+ : ./Monoid Bool+./Bool/or+ : ./Monoid Bool+./Bool/even+ : ./Monoid Bool+./Bool/odd+ : ./Monoid Bool+./List/concat+ : ∀(a : Type) → ./Monoid (List a)+./List/shifted+ : ∀(a : Type) → ./Monoid (List { index : Natural, value : a })+./Natural/sum+ : ./Monoid Natural+./Natural/product+ : ./Monoid Natural+./Optional/head+ : ∀(a : Type) → ./Monoid (Optional a)+./Optional/last+ : ∀(a : Type) → ./Monoid (Optional a)+./Text/concat+ : ./Monoid Text+```+-}+let Monoid+ : ∀(m : Type) → Type+ = λ(m : Type) → List m → m++in Monoid
@@ -1,33 +1,3 @@-{--`build` is the inverse of `fold`--Examples:--```-./build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ succ (succ (succ zero))-)-= 3--./build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ zero-)-= 0-```--}-let build- : ( ∀(natural : Type)- → ∀(succ : natural → natural)- → ∀(zero : natural)- → natural- )- → Natural- = Natural/build--in build+ missing+ sha256:e7e25e6c4f1d8e573606ed1bef725396ac2de5c68f7c5d329ffc5822085b984c+? ./build.dhall
@@ -0,0 +1,31 @@+--| `build` is the inverse of `fold`+let build+ : ( ∀(natural : Type) →+ ∀(succ : natural → natural) →+ ∀(zero : natural) →+ natural+ ) →+ Natural+ = Natural/build++let example0 =+ assert+ : build+ ( λ(natural : Type) →+ λ(succ : natural → natural) →+ λ(zero : natural) →+ succ (succ (succ zero))+ )+ ≡ 3++let example1 =+ assert+ : build+ ( λ(natural : Type) →+ λ(succ : natural → natural) →+ λ(zero : natural) →+ zero+ )+ ≡ 0++in build
@@ -1,36 +1,3 @@-{--Generate a list of numbers from `0` up to but not including the specified-number--Examples:--```-./enumerate 10 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]--./enumerate 0 = [] : List Natural-```--}-let enumerate- : Natural → List Natural- = λ(n : Natural)- → List/build- Natural- ( λ(list : Type)- → λ(cons : Natural → list → list)- → List/fold- { index : Natural, value : {} }- ( List/indexed- {}- ( List/build- {}- ( λ(list : Type)- → λ(cons : {} → list → list)- → Natural/fold n list (cons {=})- )- )- )- list- (λ(x : { index : Natural, value : {} }) → cons x.index)- )--in enumerate+ missing+ sha256:0cf083980a752b21ce0df9fc2222a4c139f50909e2353576e26a191002aa1ce3+? ./enumerate.dhall
@@ -0,0 +1,32 @@+{-|+Generate a list of numbers from `0` up to but not including the specified+number+-}+let enumerate+ : Natural → List Natural+ = λ(n : Natural) →+ List/build+ Natural+ ( λ(list : Type) →+ λ(cons : Natural → list → list) →+ List/fold+ { index : Natural, value : {} }+ ( List/indexed+ {}+ ( List/build+ {}+ ( λ(list : Type) →+ λ(cons : {} → list → list) →+ Natural/fold n list (cons {=})+ )+ )+ )+ list+ (λ(x : { index : Natural, value : {} }) → cons x.index)+ )++let example0 = assert : enumerate 10 ≡ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]++let example1 = assert : enumerate 0 ≡ ([] : List Natural)++in enumerate
@@ -0,0 +1,3 @@+ missing+ sha256:7f108edfa35ddc7cebafb24dc073478e93a802e13b5bc3fd22f4768c9b066e60+? ./equal.dhall
@@ -0,0 +1,17 @@+--| `equal` checks if two Naturals are equal.+let lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ./lessThanEqual.dhall++let equal+ : Natural → Natural → Bool+ = λ(a : Natural) → λ(b : Natural) → lessThanEqual a b && lessThanEqual b a++let example0 = assert : equal 5 5 ≡ True++let example1 = assert : equal 5 6 ≡ False++let property0 = λ(n : Natural) → assert : equal n n ≡ True++in equal
@@ -1,12 +1,3 @@-{--Returns `True` if a number if even and returns `False` otherwise--Examples:--```-./even 3 = False--./even 0 = True-```--}-let even : Natural → Bool = Natural/even in even+ missing+ sha256:b85b8b56892dfef881e1c0e79eade0b949528f792aac0ea42432b315ede4ee66+? ./even.dhall
@@ -0,0 +1,10 @@+--| Returns `True` if a number if even and returns `False` otherwise+let even+ : Natural → Bool+ = Natural/even++let example0 = assert : even 3 ≡ False++let example1 = assert : even 0 ≡ True++in even
@@ -1,33 +1,3 @@-{--`fold` is the primitive function for consuming `Natural` numbers--If you treat the number `3` as `succ (succ (succ zero))` then a `fold` just-replaces each `succ` and `zero` with something else--Examples:--```-./fold 3 Natural (λ(x : Natural) → 5 * x) 1 = 125--λ(zero : Natural) → ./fold 3 Natural (λ(x : Natural) → 5 * x) zero-= λ(zero : Natural) → 5 * (5 * (5 * zero))-- λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ ./fold 3 natural succ zero-= λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ succ (succ (succ zero))-```--}-let fold- : Natural- → ∀(natural : Type)- → ∀(succ : natural → natural)- → ∀(zero : natural)- → natural- = Natural/fold--in fold+ missing+ sha256:fd01c931e585a8f5fd049af7b076b862ea164f1813b34800c7616a49e549ee06+? ./fold.dhall
@@ -0,0 +1,28 @@+{-|+`fold` is the primitive function for consuming `Natural` numbers++If you treat the number `3` as `succ (succ (succ zero))` then a `fold` just+replaces each `succ` and `zero` with something else+-}+let fold+ : Natural →+ ∀(natural : Type) →+ ∀(succ : natural → natural) →+ ∀(zero : natural) →+ natural+ = Natural/fold++let example0 = assert : fold 3 Text (λ(x : Text) → "A" ++ x) "B" ≡ "AAAB"++let example1 =+ λ(zero : Text) →+ assert+ : fold 3 Text (λ(x : Text) → "A" ++ x) zero+ ≡ "A" ++ ("A" ++ ("A" ++ zero))++let example2 =+ λ(succ : Text → Text) →+ λ(zero : Text) →+ assert : fold 3 Text succ zero ≡ succ (succ (succ zero))++in fold
@@ -0,0 +1,3 @@+ missing+ sha256:f702abcdfcd7ad73619b9285d7e41c3a1d017fb6b8d037cf40bd93bf30c09b2c+? ./greaterThan.dhall
@@ -0,0 +1,21 @@+--| `greaterThan` checks if one Natural is strictly greater than another.+let lessThan =+ missing+ sha256:3381b66749290769badf8855d8a3f4af62e8de52d1364d838a9d1e20c94fa70c+ ? ./lessThan.dhall++let greaterThan+ : Natural → Natural → Bool+ = λ(x : Natural) → λ(y : Natural) → lessThan y x++let example0 = assert : greaterThan 5 6 ≡ False++let example1 = assert : greaterThan 5 5 ≡ False++let example2 = assert : greaterThan 5 4 ≡ True++let property0 = λ(n : Natural) → assert : greaterThan 0 n ≡ False++let property1 = λ(n : Natural) → assert : greaterThan n n ≡ False++in greaterThan
@@ -0,0 +1,3 @@+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+? ./greaterThanEqual.dhall
@@ -0,0 +1,23 @@+{-|+`greaterThanEqual` checks if one Natural is greater than or equal to another.+-}+let lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ./lessThanEqual.dhall++let greaterThanEqual+ : Natural → Natural → Bool+ = λ(x : Natural) → λ(y : Natural) → lessThanEqual y x++let example0 = assert : greaterThanEqual 5 6 ≡ False++let example1 = assert : greaterThanEqual 5 5 ≡ True++let example2 = assert : greaterThanEqual 5 4 ≡ True++let property0 = λ(n : Natural) → assert : greaterThanEqual n 0 ≡ True++let property1 = λ(n : Natural) → assert : greaterThanEqual n n ≡ True++in greaterThanEqual
@@ -1,12 +1,3 @@-{--Returns `True` if a number is `0` and returns `False` otherwise--Examples:--```-./isZero 2 = False--./isZero 0 = True-```--}-let isZero : Natural → Bool = Natural/isZero in isZero+ missing+ sha256:1be98236800ed2d5cff44f16ca02b34b0c37dfa239d9e0d63d9d2c6eeae3d1d1+? ./isZero.dhall
@@ -0,0 +1,10 @@+--| Returns `True` if a number is `0` and returns `False` otherwise+let isZero+ : Natural → Bool+ = Natural/isZero++let example0 = assert : isZero 2 ≡ False++let example1 = assert : isZero 0 ≡ True++in isZero
@@ -0,0 +1,3 @@+ missing+ sha256:3381b66749290769badf8855d8a3f4af62e8de52d1364d838a9d1e20c94fa70c+? ./lessThan.dhall
@@ -0,0 +1,26 @@+--| `lessThan` checks if one Natural is strictly less than another.+let greaterThanEqual =+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+ ? ./greaterThanEqual.dhall++let Bool/not =+ missing+ sha256:723df402df24377d8a853afed08d9d69a0a6d86e2e5b2bac8960b0d4756c7dc4+ ? ../Bool/not.dhall++let lessThan+ : Natural → Natural → Bool+ = λ(x : Natural) → λ(y : Natural) → Bool/not (greaterThanEqual x y)++let example0 = assert : lessThan 5 6 ≡ True++let example1 = assert : lessThan 5 5 ≡ False++let example2 = assert : lessThan 5 4 ≡ False++let property0 = λ(n : Natural) → assert : lessThan n 0 ≡ False++let property1 = λ(n : Natural) → assert : lessThan n n ≡ False++in lessThan
@@ -0,0 +1,3 @@+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+? ./lessThanEqual.dhall
@@ -0,0 +1,16 @@+--| `lessThanEqual` checks if one Natural is less than or equal to another.+let lessThanEqual+ : Natural → Natural → Bool+ = λ(x : Natural) → λ(y : Natural) → Natural/isZero (Natural/subtract y x)++let example0 = assert : lessThanEqual 5 6 ≡ True++let example1 = assert : lessThanEqual 5 5 ≡ True++let example2 = assert : lessThanEqual 5 4 ≡ False++let property0 = λ(n : Natural) → assert : lessThanEqual 0 n ≡ True++let property1 = λ(n : Natural) → assert : lessThanEqual n n ≡ True++in lessThanEqual
@@ -0,0 +1,3 @@+ missing+ sha256:20906ffcc9970f740106d4516cb7868b43d75ff8c9f00ff8a9680ae68c48a472+? ./listMax.dhall
@@ -0,0 +1,30 @@+{-|+`listMax` returns the largest element of a `List` or `None Natural` if the+`List` is empty+-}+let max =+ missing+ sha256:1f3b18da330223ab039fad11693da72c7e68d516f50502c73f41a89a097b62f7+ ? ./max.dhall++let Optional/map =+ missing+ sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa+ ? ../Optional/map.dhall++let listMax+ : List Natural → Optional Natural+ = λ(xs : List Natural) →+ Optional/map+ Natural+ Natural+ (λ(n : Natural) → List/fold Natural xs Natural max n)+ (List/head Natural xs)++let example0 = assert : listMax [ 1, 2 ] ≡ Some 2++let example1 = assert : listMax ([] : List Natural) ≡ None Natural++let property0 = λ(n : Natural) → assert : listMax [ n ] ≡ Some n++in listMax
@@ -0,0 +1,3 @@+ missing+ sha256:ee70b0d010bbca6012162e8ae1f6e9d9bd10a152675509b0f23145b98b5d43c6+? ./listMin.dhall
@@ -0,0 +1,34 @@+{-|+`listMin` returns the smallest element of a `List` or `None Natural` if the+`List` is empty+-}+let min =+ missing+ sha256:f25f9c462e4dbf0eb15f9ff6ac840c6e9c82255a7f4f2ab408bdab338e028710+ ? ./min.dhall++let Optional/map =+ missing+ sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa+ ? ../Optional/map.dhall++let listMin+ : List Natural → Optional Natural+ = λ(xs : List Natural) →+ Optional/map+ Natural+ Natural+ ( λ(n : Natural) →+ if Natural/isZero n then n else List/fold Natural xs Natural min n+ )+ (List/head Natural xs)++let example0 = assert : listMin [ 0, 1 ] ≡ Some 0++let example1 = assert : listMin ([] : List Natural) ≡ None Natural++let example2 = assert : listMin [ 3, 2, 1 ] ≡ Some 1++let property0 = λ(n : Natural) → assert : listMin [ n ] ≡ Some n++in listMin
@@ -0,0 +1,3 @@+ missing+ sha256:1f3b18da330223ab039fad11693da72c7e68d516f50502c73f41a89a097b62f7+? ./max.dhall
@@ -0,0 +1,19 @@+--| `max a b` returns the larger of `a` or `b`+let lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ./lessThanEqual.dhall++let max+ : Natural → Natural → Natural+ = λ(a : Natural) → λ(b : Natural) → if lessThanEqual a b then b else a++let example0 = assert : max 1 2 ≡ 2++let example1 = assert : max 2 1 ≡ 2++let property0 = λ(n : Natural) → assert : max n n ≡ n++let property1 = λ(n : Natural) → assert : max 0 n ≡ n++in max
@@ -0,0 +1,3 @@+ missing+ sha256:f25f9c462e4dbf0eb15f9ff6ac840c6e9c82255a7f4f2ab408bdab338e028710+? ./min.dhall
@@ -0,0 +1,17 @@+--| `min a b` returns the smaller of `a` or `b`+let lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ./lessThanEqual.dhall++let min+ : Natural → Natural → Natural+ = λ(a : Natural) → λ(b : Natural) → if lessThanEqual a b then a else b++let example0 = assert : min 1 2 ≡ 1++let example1 = assert : min 2 1 ≡ 1++let property0 = λ(n : Natural) → assert : min n n ≡ n++in min
@@ -1,12 +1,3 @@-{--Returns `True` if a number is odd and returns `False` otherwise--Examples:--```-./odd 3 = True--./odd 0 = False-```--}-let odd : Natural → Bool = Natural/odd in odd+ missing+ sha256:ab3c729262c642ec1cdb72a81e910fcfaf2aea13e3961d0bf1bec83efea5aac5+? ./odd.dhall
@@ -0,0 +1,10 @@+--| Returns `True` if a number is odd and returns `False` otherwise+let odd+ : Natural → Bool+ = Natural/odd++let example0 = assert : odd 3 ≡ True++let example1 = assert : odd 0 ≡ False++in odd
@@ -1,34 +1,89 @@ { build =- ./build sha256:e7e25e6c4f1d8e573606ed1bef725396ac2de5c68f7c5d329ffc5822085b984c- ? ./build+ missing+ sha256:e7e25e6c4f1d8e573606ed1bef725396ac2de5c68f7c5d329ffc5822085b984c+ ? ./build.dhall , enumerate =- ./enumerate sha256:0cf083980a752b21ce0df9fc2222a4c139f50909e2353576e26a191002aa1ce3- ? ./enumerate+ missing+ sha256:0cf083980a752b21ce0df9fc2222a4c139f50909e2353576e26a191002aa1ce3+ ? ./enumerate.dhall , even =- ./even sha256:b85b8b56892dfef881e1c0e79eade0b949528f792aac0ea42432b315ede4ee66- ? ./even+ missing+ sha256:b85b8b56892dfef881e1c0e79eade0b949528f792aac0ea42432b315ede4ee66+ ? ./even.dhall , fold =- ./fold sha256:fd01c931e585a8f5fd049af7b076b862ea164f1813b34800c7616a49e549ee06- ? ./fold+ missing+ sha256:fd01c931e585a8f5fd049af7b076b862ea164f1813b34800c7616a49e549ee06+ ? ./fold.dhall , isZero =- ./isZero sha256:1be98236800ed2d5cff44f16ca02b34b0c37dfa239d9e0d63d9d2c6eeae3d1d1- ? ./isZero+ missing+ sha256:1be98236800ed2d5cff44f16ca02b34b0c37dfa239d9e0d63d9d2c6eeae3d1d1+ ? ./isZero.dhall , odd =- ./odd sha256:ab3c729262c642ec1cdb72a81e910fcfaf2aea13e3961d0bf1bec83efea5aac5- ? ./odd+ missing+ sha256:ab3c729262c642ec1cdb72a81e910fcfaf2aea13e3961d0bf1bec83efea5aac5+ ? ./odd.dhall , product =- ./product sha256:e3e6fd76207875b81d39f79fdbc90b5e640444c04fb3d84c2c9326748f0b26e6- ? ./product+ missing+ sha256:e3e6fd76207875b81d39f79fdbc90b5e640444c04fb3d84c2c9326748f0b26e6+ ? ./product.dhall , sum =- ./sum sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037- ? ./sum+ missing+ sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037+ ? ./sum.dhall , show =- ./show sha256:684ed560ad86f438efdea229eca122c29e8e14f397ed32ec97148d578ca5aa21- ? ./show+ missing+ sha256:684ed560ad86f438efdea229eca122c29e8e14f397ed32ec97148d578ca5aa21+ ? ./show.dhall , toDouble =- ./toDouble sha256:d5eb52143dcd35b46a6f0cdb2d3cbf31a14b6daeba56e29066f8e344c9fb6e81- ? ./toDouble+ missing+ sha256:d5eb52143dcd35b46a6f0cdb2d3cbf31a14b6daeba56e29066f8e344c9fb6e81+ ? ./toDouble.dhall , toInteger =- ./toInteger sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f- ? ./toInteger+ missing+ sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f+ ? ./toInteger.dhall+, lessThan =+ missing+ sha256:3381b66749290769badf8855d8a3f4af62e8de52d1364d838a9d1e20c94fa70c+ ? ./lessThan.dhall+, lessThanEqual =+ missing+ sha256:1a5caa2b80a42b9f58fff58e47ac0d9a9946d0b2d36c54034b8ddfe3cb0f3c99+ ? ./lessThanEqual.dhall+, equal =+ missing+ sha256:7f108edfa35ddc7cebafb24dc073478e93a802e13b5bc3fd22f4768c9b066e60+ ? ./equal.dhall+, greaterThanEqual =+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+ ? ./greaterThanEqual.dhall+, greaterThan =+ missing+ sha256:f702abcdfcd7ad73619b9285d7e41c3a1d017fb6b8d037cf40bd93bf30c09b2c+ ? ./greaterThan.dhall+, min =+ missing+ sha256:f25f9c462e4dbf0eb15f9ff6ac840c6e9c82255a7f4f2ab408bdab338e028710+ ? ./min.dhall+, max =+ missing+ sha256:1f3b18da330223ab039fad11693da72c7e68d516f50502c73f41a89a097b62f7+ ? ./max.dhall+, listMin =+ missing+ sha256:ee70b0d010bbca6012162e8ae1f6e9d9bd10a152675509b0f23145b98b5d43c6+ ? ./listMin.dhall+, listMax =+ missing+ sha256:20906ffcc9970f740106d4516cb7868b43d75ff8c9f00ff8a9680ae68c48a472+ ? ./listMax.dhall+, sort =+ missing+ sha256:36ce8b3e5538454763987ca904d8d7c5ba34c2147434a19eddd51f684432b260+ ? ./sort.dhall+, subtract =+ missing+ sha256:b9277ac637d09142a3a3ac79137ef5955c42f8b33b6746d59db2c9d75ccdd745+ ? ./subtract.dhall }
@@ -1,17 +1,3 @@-{--Multiply all the numbers in a `List`--Examples:--```-./product [ 2, 3, 5 ] = 30--./product ([] : List Natural) = 1-```--}-let product- : List Natural → Natural- = λ(xs : List Natural)- → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l * r) 1--in product+ missing+ sha256:e3e6fd76207875b81d39f79fdbc90b5e640444c04fb3d84c2c9326748f0b26e6+? ./product.dhall
@@ -0,0 +1,11 @@+--| Multiply all the numbers in a `List`+let product+ : List Natural → Natural+ = λ(xs : List Natural) →+ List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l * r) 1++let example0 = assert : product [ 2, 3, 5 ] ≡ 30++let example1 = assert : product ([] : List Natural) ≡ 1++in product
@@ -1,13 +1,3 @@-{--Render a `Natural` number as `Text` using the same representation as Dhall-source code (i.e. a decimal number)--Examples:--```-./show 3 = "3"--./show 0 = "0"-```--}-let show : Natural → Text = Natural/show in show+ missing+ sha256:684ed560ad86f438efdea229eca122c29e8e14f397ed32ec97148d578ca5aa21+? ./show.dhall
@@ -0,0 +1,13 @@+{-|+Render a `Natural` number as `Text` using the same representation as Dhall+source code (i.e. a decimal number)+-}+let show+ : Natural → Text+ = Natural/show++let example0 = assert : show 3 ≡ "3"++let example1 = assert : show 0 ≡ "0"++in show
@@ -0,0 +1,3 @@+ missing+ sha256:36ce8b3e5538454763987ca904d8d7c5ba34c2147434a19eddd51f684432b260+? ./sort.dhall
@@ -0,0 +1,61 @@+--| `sort` sorts a `List` of `Natural`s in ascending order+let greaterThanEqual =+ missing+ sha256:30ebfab0febd7aa0ccccfdf3dc36ee6d50f0117f35dd4a9b034750b7e885a1a4+ ? ./greaterThanEqual.dhall++let listMin =+ missing+ sha256:ee70b0d010bbca6012162e8ae1f6e9d9bd10a152675509b0f23145b98b5d43c6+ ? ./listMin.dhall++let List/partition =+ missing+ sha256:38147ac6d750a6492736dd90cc967bf09aa405c499de943c64fab7b86ae02f03+ ? ../List/partition.dhall++let Accumulator = { sorted : List Natural, rest : List Natural }++let partitionMinima =+ λ(xs : List Natural) →+ merge+ { Some =+ λ(m : Natural) → List/partition Natural (greaterThanEqual m) xs+ , None = { true = [] : List Natural, false = [] : List Natural }+ }+ (listMin xs)++let test0 =+ assert+ : partitionMinima [ 2, 1, 1, 3 ] ≡ { true = [ 1, 1 ], false = [ 2, 3 ] }++let step =+ λ(x : Accumulator) →+ let p = partitionMinima x.rest++ in { sorted = x.sorted # p.true, rest = p.false }++let test1 =+ assert+ : step { sorted = [ 1, 1 ], rest = [ 2, 3 ] }+ ≡ { sorted = [ 1, 1, 2 ], rest = [ 3 ] }++let sort+ : List Natural → List Natural+ = λ(xs : List Natural) →+ let x =+ Natural/fold+ (List/length Natural xs)+ Accumulator+ step+ { sorted = [] : List Natural, rest = xs }++ in x.sorted++let example0 = assert : sort ([] : List Natural) ≡ ([] : List Natural)++let example1 = assert : sort [ 1 ] ≡ [ 1 ]++let example2 = assert : sort [ 3, 2, 1, 3, 2, 1 ] ≡ [ 1, 1, 2, 2, 3, 3 ]++in sort
@@ -0,0 +1,3 @@+ missing+ sha256:b9277ac637d09142a3a3ac79137ef5955c42f8b33b6746d59db2c9d75ccdd745+? ./subtract.dhall
@@ -0,0 +1,18 @@+--| `subtract m n` computes `n - m`, truncating to `0` if `m > n`+let subtract+ : Natural → Natural → Natural+ = Natural/subtract++let example0 = assert : subtract 1 2 ≡ 1++let example1 = assert : subtract 1 1 ≡ 0++let example2 = assert : subtract 2 1 ≡ 0++let property0 = λ(n : Natural) → assert : subtract 0 n ≡ n++let property1 = λ(n : Natural) → assert : subtract n 0 ≡ 0++let property2 = λ(n : Natural) → assert : subtract n n ≡ 0++in subtract
@@ -1,17 +1,3 @@-{--Add all the numbers in a `List`--Examples:--```-./sum [ 2, 3, 5 ] = 10--./sum ([] : List Natural) = 0-```--}-let sum- : List Natural → Natural- = λ(xs : List Natural)- → List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l + r) 0--in sum+ missing+ sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037+? ./sum.dhall
@@ -0,0 +1,11 @@+--| Add all the numbers in a `List`+let sum+ : List Natural → Natural+ = λ(xs : List Natural) →+ List/fold Natural xs Natural (λ(l : Natural) → λ(r : Natural) → l + r) 0++let example = assert : sum [ 2, 3, 5 ] ≡ 10++let example = assert : sum ([] : List Natural) ≡ 0++in sum
@@ -1,16 +1,3 @@-{--Convert a `Natural` number to the corresponding `Double`--Examples:--```-./toDouble 3 = 3.0--./toDouble 0 = 0.0-```--}-let toDouble- : Natural → Double- = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)--in toDouble+ missing+ sha256:d5eb52143dcd35b46a6f0cdb2d3cbf31a14b6daeba56e29066f8e344c9fb6e81+? ./toDouble.dhall
@@ -0,0 +1,10 @@+--| Convert a `Natural` number to the corresponding `Double`+let toDouble+ : Natural → Double+ = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)++let example0 = assert : toDouble 3 ≡ 3.0++let example1 = assert : toDouble 0 ≡ 0.0++in toDouble
@@ -1,12 +1,3 @@-{--Convert a `Natural` number to the corresponding `Integer`--Examples:--```-./toInteger 3 = +3--./toInteger 0 = +0-```--}-let toInteger : Natural → Integer = Natural/toInteger in toInteger+ missing+ sha256:160d2d278619f3da34a1f4f02e739a447e4f2aa5a2978c45b710515b41491e1f+? ./toInteger.dhall
@@ -0,0 +1,10 @@+--| Convert a `Natural` number to the corresponding `Integer`+let toInteger+ : Natural → Integer+ = Natural/toInteger++let example0 = assert : toInteger 3 ≡ +3++let example1 = assert : toInteger 0 ≡ +0++in toInteger
@@ -0,0 +1,9 @@+{-|+A `NonEmpty` list has at least one element and supports many of the same+operations as `List`s+-}+let NonEmpty+ : Type → Type+ = λ(a : Type) → { head : a, tail : List a }++in NonEmpty
@@ -0,0 +1,34 @@+{-|+Returns `True` if the supplied function returns `True` for all elements in the+`NonEmpty` list+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall++let all+ : ∀(a : Type) → (a → Bool) → NonEmpty a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : NonEmpty a) →+ List/fold+ a+ (NonEmpty/toList a xs)+ Bool+ (λ(x : a) → λ(r : Bool) → f x && r)+ True++let example0 =+ assert : all Natural Natural/even { head = 2, tail = [ 3, 5 ] } ≡ False++let example1 =+ assert+ : all Natural Natural/even { head = 2, tail = [] : List Natural } ≡ True++in all
@@ -0,0 +1,34 @@+{-|+Returns `True` if the supplied function returns `True` for any element in the+`NonEmpty` list+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall++let any+ : ∀(a : Type) → (a → Bool) → NonEmpty a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : NonEmpty a) →+ List/fold+ a+ (NonEmpty/toList a xs)+ Bool+ (λ(x : a) → λ(r : Bool) → f x || r)+ False++let example0 =+ assert : any Natural Natural/even { head = 2, tail = [ 3, 5 ] } ≡ True++let example1 =+ assert+ : any Natural Natural/even { head = 3, tail = [] : List Natural } ≡ False++in any
@@ -0,0 +1,61 @@+{-|+Concatenate a `NonEmpty` list of `NonEmpty` lists into a single `NonEmpty`+list+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall++let List/concatMap =+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ../List/concatMap.dhall++let concat+ : ∀(a : Type) → NonEmpty (NonEmpty a) → NonEmpty a+ = λ(a : Type) →+ λ(xss : NonEmpty (NonEmpty a)) →+ { head = xss.head.head+ , tail =+ xss.head.tail+ # List/concatMap (NonEmpty a) a (NonEmpty/toList a) xss.tail+ }++let example0 =+ assert+ : concat+ Natural+ { head = { head = 0, tail = [ 1, 2 ] }+ , tail =+ [ { head = 3, tail = [ 4 ] }, { head = 5, tail = [ 6, 7, 8 ] } ]+ }+ ≡ { head = 0, tail = [ 1, 2, 3, 4, 5, 6, 7, 8 ] }++let example1 =+ assert+ : concat+ Natural+ { head = { head = 0, tail = [] : List Natural }+ , tail =+ [ { head = 1, tail = [] : List Natural }+ , { head = 2, tail = [] : List Natural }+ ]+ }+ ≡ { head = 0, tail = [ 1, 2 ] : List Natural }++let example2 =+ assert+ : concat+ Natural+ { head = { head = 0, tail = [] : List Natural }+ , tail = [] : List (NonEmpty Natural)+ }+ ≡ { head = 0, tail = [] : List Natural }++in concat
@@ -0,0 +1,56 @@+{-|+Transform a `NonEmpty` list by applying a function to each element and+flattening the results+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall++let List/concatMap =+ missing+ sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64+ ? ../List/concatMap.dhall++let concatMap+ : ∀(a : Type) → ∀(b : Type) → (a → NonEmpty b) → NonEmpty a → NonEmpty b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → NonEmpty b) →+ λ(xs : NonEmpty a) →+ let ys = f xs.head++ in { head = ys.head+ , tail =+ ys.tail+ # List/concatMap+ a+ b+ (λ(x : a) → NonEmpty/toList b (f x))+ xs.tail+ }++let example0 =+ assert+ : concatMap+ Natural+ Natural+ (λ(n : Natural) → { head = n, tail = [ n ] })+ { head = 2, tail = [ 3, 5 ] }+ ≡ { head = 2, tail = [ 2, 3, 3, 5, 5 ] }++let example1 =+ assert+ : concatMap+ Natural+ Natural+ (λ(n : Natural) → { head = n, tail = [ n ] })+ { head = 2, tail = [] : List Natural }+ ≡ { head = 2, tail = [ 2 ] }++in concatMap
@@ -0,0 +1,13 @@+--| Retrieve the first element of the `NonEmpty` list+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let head+ : ∀(a : Type) → NonEmpty a → a+ = λ(a : Type) → λ(xs : NonEmpty a) → xs.head++let example = assert : head Natural { head = 0, tail = [ 1, 2 ] } ≡ 0++in head
@@ -0,0 +1,33 @@+--| Retrieve an element from a `NonEmpty` list using its 0-based index+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let List/index =+ missing+ sha256:e657b55ecae4d899465c3032cb1a64c6aa6dc2aa3034204f3c15ce5c96c03e63+ ? ../List/index.dhall++let index+ : Natural → ∀(a : Type) → NonEmpty a → Optional a+ = λ(n : Natural) →+ λ(a : Type) →+ λ(xs : NonEmpty a) →+ if Natural/isZero n+ then Some xs.head+ else List/index (Natural/subtract 1 n) a xs.tail++let property =+ λ(n : Natural) →+ λ(a : Type) →+ λ(xs : NonEmpty a) →+ assert : index 0 a xs ≡ Some xs.head++let example0 = assert : index 1 Natural { head = 2, tail = [ 3, 5 ] } ≡ Some 3++let example1 =+ assert+ : index 1 Natural { head = 2, tail = [] : List Natural } ≡ None Natural++in index
@@ -0,0 +1,41 @@+--| Tag each element of the `NonEmpty` list with its index+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let indexed+ : ∀(a : Type) → NonEmpty a → NonEmpty { index : Natural, value : a }+ = λ(a : Type) →+ λ(xs : NonEmpty a) →+ { head = { index = 0, value = xs.head }+ , tail =+ List/map+ { index : Natural, value : a }+ { index : Natural, value : a }+ ( λ(ix : { index : Natural, value : a }) →+ { index = ix.index + 1, value = ix.value }+ )+ (List/indexed a xs.tail)+ }++let example0 =+ assert+ : indexed Bool { head = True, tail = [ False, True ] }+ ≡ { head = { index = 0, value = True }+ , tail = [ { index = 1, value = False }, { index = 2, value = True } ]+ }++let example1 =+ assert+ : indexed Bool { head = True, tail = [] : List Bool }+ ≡ { head = { index = 0, value = True }+ , tail = [] : List { index : Natural, value : Bool }+ }++in indexed
@@ -0,0 +1,17 @@+--| Retrieve the last element of the `NonEmpty` list+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let last+ : ∀(a : Type) → NonEmpty a → a+ = λ(a : Type) →+ λ(xs : NonEmpty a) →+ merge { Some = λ(x : a) → x, None = xs.head } (List/last a xs.tail)++let example0 = assert : last Natural { head = 0, tail = [ 1, 2 ] } ≡ 2++let example1 = assert : last Natural { head = 0, tail = [] : List Natural } ≡ 0++in last
@@ -0,0 +1,16 @@+--| Returns the number of elements in a `NonEmpty` list+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let length+ : ∀(a : Type) → NonEmpty a → Natural+ = λ(a : Type) → λ(xs : NonEmpty a) → List/length a xs.tail + 1++let example0 = assert : length Natural { head = 0, tail = [ 1, 2 ] } ≡ 3++let example1 =+ assert : length Natural { head = 0, tail = [] : List Natural } ≡ 1++in length
@@ -0,0 +1,18 @@+{-|+Create a `NonEmpty` list using a function instead of a record++This might come in handy if you want to decouple the `NonEmpty` list+construction from the specific names of the fields.+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let make+ : ∀(a : Type) → ∀(head : a) → ∀(tail : List a) → NonEmpty a+ = λ(a : Type) → λ(head : a) → λ(tail : List a) → { head, tail }++let example = assert : make Natural 1 [ 2, 3 ] ≡ { head = 1, tail = [ 2, 3 ] }++in make
@@ -0,0 +1,30 @@+--| Transform a `NonEmpty` list by applying a function to each element+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let map+ : ∀(a : Type) → ∀(b : Type) → (a → b) → NonEmpty a → NonEmpty b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → b) →+ λ(xs : NonEmpty a) →+ { head = f xs.head, tail = List/map a b f xs.tail }++let example0 =+ assert+ : map Natural Bool Natural/even { head = 2, tail = [ 3, 5 ] }+ ≡ { head = True, tail = [ False, False ] }++let example1 =+ assert+ : map Natural Bool Natural/even { head = 2, tail = [] : List Natural }+ ≡ { head = True, tail = [] : List Bool }++in map
@@ -0,0 +1,73 @@+{ Type =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall+, all =+ missing+ sha256:f2f9389d94f4deb5b918b2e50c1093b57e00b37ddd3ab2b43959993b1cb519b6+ ? ./all.dhall+, any =+ missing+ sha256:7662b665840e41b12a28190eec3aaab9201fcb90c00a8ec3666d549e1020992f+ ? ./any.dhall+, concat =+ missing+ sha256:6d55181938c06c6b806877028f6a241912e9c0935d9a10dd958775bf21e0f64d+ ? ./concat.dhall+, concatMap =+ missing+ sha256:fc33fa9449dc8f74dd8c8be379b7b7c4b0433e2b65650370d81d9a7111a590e2+ ? ./concatMap.dhall+, head =+ missing+ sha256:6b9551c97b89fe666d2e03392a4af5e87abfdbdb0aa0e29fc4b3aa1b318474e7+ ? ./head.dhall+, index =+ missing+ sha256:0ba2fcc9227fab10676cd61b47a18d779818a19c16727c7cc4b4c78e114fd663+ ? ./index.dhall+, indexed =+ missing+ sha256:9dae2c1fecd142df837e98769b5bbdd0bfe25c35a93af1064b4e62f9c780ae6b+ ? ./indexed.dhall+, last =+ missing+ sha256:f83115492b6e408d0b662a68440620f7f3df07b56e7ed66dab77a6e65b121250+ ? ./last.dhall+, length =+ missing+ sha256:eef3b857a164487cfdb960e3298c4731970b7a430011289cba35a9ad722ac989+ ? ./length.dhall+, make =+ missing+ sha256:549de393673c4773c80a50ea578ea50d7f2c4c2eda31956e73fabc4e486f3b1e+ ? ./make.dhall+, map =+ missing+ sha256:93d53afe874bb2eed946c21ca5ada3c9716b7d00e6d8edfaba6484cd9c5a00bd+ ? ./map.dhall+, reverse =+ missing+ sha256:a6d810cdd3badffd4e7ca82091609a855cffac900c82d7ff3724463fbc2d5ff2+ ? ./reverse.dhall+, shifted =+ missing+ sha256:36156973d6916aed10cfd8c59be7c019516bf0a2c47b499a17a8ef0611e1c189+ ? ./shifted.dhall+, singleton =+ missing+ sha256:c9197aabe97695f7ca66f7419bf172d806b2c915594a8fc0d2ff6495db496ff2+ ? ./singleton.dhall+, toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall+, unzip =+ missing+ sha256:d0b925bea32a29aad5cb48a84e8ef8cff750308afe1dd20b24eca19e4e999abc+ ? ./unzip.dhall+, zip =+ missing+ sha256:073f8b4808b6d1db84964f772f6291e6ea193602163438db43fa282c560c01e4+ ? ./zip.dhall+}
@@ -0,0 +1,35 @@+--| Reverse a `NonEmpty` list+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let List/drop =+ missing+ sha256:af983ba3ead494dd72beed05c0f3a17c36a4244adedf7ced502c6512196ed0cf+ ? ../List/drop.dhall++let reverse+ : ∀(a : Type) → NonEmpty a → NonEmpty a+ = λ(a : Type) →+ λ(xs : NonEmpty a) →+ let ys = List/reverse a xs.tail++ in merge+ { Some =+ λ(y : a) → { head = y, tail = List/drop 1 a ys # [ xs.head ] }+ , None = { head = xs.head, tail = [] : List a }+ }+ (List/head a ys)++let example =+ assert+ : reverse Natural { head = 0, tail = [ 1, 2 ] }+ ≡ { head = 2, tail = [ 1, 0 ] }++let example1 =+ assert+ : reverse Natural { head = 0, tail = [] : List Natural }+ ≡ { head = 0, tail = [] : List Natural }++in reverse
@@ -0,0 +1,101 @@+{-|+Combine a `NonEmpty` list of `NonEmpty` lists, offsetting the `index` of each+element by the number of elements in preceding lists+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/toList =+ missing+ sha256:0977fe14b77232a4451dcf409c43df4589c4b3cdde7b613aab8df183be1b53f5+ ? ./toList.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let List/shifted =+ missing+ sha256:54fb22c7e952ebce1cfc0fcdd33ce4cfa817bff9d6564af268dea6685f8b5dfe+ ? ../List/shifted.dhall++let shifted+ : ∀(a : Type) →+ NonEmpty (NonEmpty { index : Natural, value : a }) →+ NonEmpty { index : Natural, value : a }+ = λ(a : Type) →+ λ(kvss : NonEmpty (NonEmpty { index : Natural, value : a })) →+ { head = kvss.head.head+ , tail =+ List/shifted+ a+ ( [ kvss.head.tail ]+ # List/map+ (NonEmpty { index : Natural, value : a })+ (List { index : Natural, value : a })+ ( λ(kvs : NonEmpty { index : Natural, value : a }) →+ List/map+ { index : Natural, value : a }+ { index : Natural, value : a }+ ( λ(kv : { index : Natural, value : a }) →+ { index = kv.index + 1, value = kv.value }+ )+ (NonEmpty/toList { index : Natural, value : a } kvs)+ )+ kvss.tail+ )+ }++let example0 =+ assert+ : shifted+ Bool+ { head =+ { head = { index = 0, value = True }+ , tail =+ [ { index = 1, value = True }, { index = 2, value = True } ]+ }+ , tail =+ [ { head = { index = 0, value = False }+ , tail = [ { index = 1, value = False } ]+ }+ , { head = { index = 0, value = True }+ , tail =+ [ { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = True }+ ]+ }+ ]+ }+ ≡ { head = { index = 0, value = True }+ , tail =+ [ { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = False }+ , { index = 4, value = False }+ , { index = 5, value = True }+ , { index = 6, value = True }+ , { index = 7, value = True }+ , { index = 8, value = True }+ ]+ }++let example1 =+ assert+ : shifted+ Bool+ { head =+ { head = { index = 0, value = True }+ , tail = [] : List { index : Natural, value : Bool }+ }+ , tail = [] : List (NonEmpty { index : Natural, value : Bool })+ }+ ≡ { head = { index = 0, value = True }+ , tail = [] : List { index : Natural, value : Bool }+ }++in shifted
@@ -0,0 +1,14 @@+--| Create a `NonEmpty` list with just one element+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let singleton+ : ∀(a : Type) → a → NonEmpty a+ = λ(a : Type) → λ(x : a) → { head = x, tail = [] : List a }++let example =+ assert : singleton Natural 2 ≡ { head = 2, tail = [] : List Natural }++in singleton
@@ -0,0 +1,17 @@+--| Convert a `NonEmpty` list into the equivalent `List`+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let toList+ : ∀(a : Type) → NonEmpty a → List a+ = λ(a : Type) → λ(xs : NonEmpty a) → [ xs.head ] # xs.tail++let example0 =+ assert : toList Natural { head = 2, tail = [ 3, 5 ] } ≡ [ 2, 3, 5 ]++let example1 =+ assert : toList Natural { head = 2, tail = [] : List Natural } ≡ [ 2 ]++in toList
@@ -0,0 +1,58 @@+--| Unzip a `NonEmpty` list into two separate `NonEmpty` lists+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let NonEmpty/map =+ missing+ sha256:93d53afe874bb2eed946c21ca5ada3c9716b7d00e6d8edfaba6484cd9c5a00bd+ ? ./map.dhall++let unzip+ : ∀(a : Type) →+ ∀(b : Type) →+ NonEmpty { _1 : a, _2 : b } →+ { _1 : NonEmpty a, _2 : NonEmpty b }+ = λ(a : Type) →+ λ(b : Type) →+ λ(xs : NonEmpty { _1 : a, _2 : b }) →+ { _1 =+ NonEmpty/map+ { _1 : a, _2 : b }+ a+ (λ(x : { _1 : a, _2 : b }) → x._1)+ xs+ , _2 =+ NonEmpty/map+ { _1 : a, _2 : b }+ b+ (λ(x : { _1 : a, _2 : b }) → x._2)+ xs+ }++let example0 =+ assert+ : unzip+ Text+ Bool+ { head = { _1 = "ABC", _2 = True }+ , tail = [ { _1 = "DEF", _2 = False }, { _1 = "GHI", _2 = True } ]+ }+ ≡ { _1 = { head = "ABC", tail = [ "DEF", "GHI" ] }+ , _2 = { head = True, tail = [ False, True ] }+ }++let example1 =+ assert+ : unzip+ Text+ Bool+ { head = { _1 = "ABC", _2 = True }+ , tail = [] : List { _1 : Text, _2 : Bool }+ }+ ≡ { _1 = { head = "ABC", tail = [] : List Text }+ , _2 = { head = True, tail = [] : List Bool }+ }++in unzip
@@ -0,0 +1,63 @@+{-|+Zip two `NonEmpty` lists into a single `NonEmpty`++The resulting `NonEmpty` will have the length of the shortest of its arguments.+-}+let NonEmpty =+ missing+ sha256:e2e247455a858317e470e0e4affca8ac07f9f130570ece9cb7ac1f4ea3deb87f+ ? ./Type.dhall++let List/zip =+ missing+ sha256:85ed955eabf3998767f4ad2a28e57d40cd4c68a95519d79e9b622f1d26d979da+ ? ../List/zip.dhall++let zip+ : ∀(a : Type) →+ NonEmpty a →+ ∀(b : Type) →+ NonEmpty b →+ NonEmpty { _1 : a, _2 : b }+ = λ(a : Type) →+ λ(xs : NonEmpty a) →+ λ(b : Type) →+ λ(ys : NonEmpty b) →+ { head = { _1 = xs.head, _2 = ys.head }+ , tail = List/zip a xs.tail b ys.tail+ }++let example0 =+ assert+ : zip+ Text+ { head = "ABC", tail = [ "DEF", "GHI" ] }+ Natural+ { head = 1, tail = [ 2, 3 ] }+ ≡ { head = { _1 = "ABC", _2 = 1 }+ , tail = [ { _1 = "DEF", _2 = 2 }, { _1 = "GHI", _2 = 3 } ]+ }++let example1 =+ assert+ : zip+ Text+ { head = "ABC", tail = [ "DEF" ] }+ Bool+ { head = True, tail = [] : List Bool }+ ≡ { head = { _1 = "ABC", _2 = True }+ , tail = [] : List { _1 : Text, _2 : Bool }+ }++let example2 =+ assert+ : zip+ Text+ { head = "ABC", tail = [] : List Text }+ Natural+ { head = 1, tail = [ 2 ] }+ ≡ { head = { _1 = "ABC", _2 = 1 }+ , tail = [] : List { _1 : Text, _2 : Natural }+ }++in zip
@@ -0,0 +1,85 @@+{-+Note: This package does not use one file per function because the operator+names contain symbols such as `*` that may cause problems.+-}+let {-+ `+` m n++ computes `m + n`+ -} `+`+ : Natural → Natural → Natural+ = λ(m : Natural) → λ(n : Natural) → m + n++let example1 = assert : `+` 2 1 ≡ 3++let {-+ `*` m n++ computes `m * n`+ -} `*`+ : Natural → Natural → Natural+ = λ(m : Natural) → λ(n : Natural) → m * n++let example2 = assert : `*` 21 2 ≡ 42++let {-+ `++` m n++ computes `m ++ n`+ -} `++`+ : Text → Text → Text+ = λ(m : Text) → λ(n : Text) → m ++ n++let example3 = assert : `++` "Hello" "Dhall" ≡ "HelloDhall"++let {-+ `#` Type m n++ computes `m # n`+ -} `#`+ : ∀(type : Type) → List type → List type → List type+ = λ(type : Type) → λ(m : List type) → λ(n : List type) → m # n++let example4 = assert : `#` Natural [ 1, 2 ] [ 3 ] ≡ [ 1, 2, 3 ]++let {-+ `==` m n++ computes `m == n`+ -} `==`+ : Bool → Bool → Bool+ = λ(m : Bool) → λ(n : Bool) → m == n++let example5 = assert : `==` True False ≡ False++let {-+ `!=` m n++ computes `m != n`+ -} `!=`+ : Bool → Bool → Bool+ = λ(m : Bool) → λ(n : Bool) → m != n++let example6 = assert : `!=` True False ≡ True++let {-+ `&&` m n++ computes `m && n`+ -} `&&`+ : Bool → Bool → Bool+ = λ(m : Bool) → λ(n : Bool) → m && n++let example7 = assert : `&&` False True ≡ False++let {-+ `||` m n++ computes `m || n`+ -} `||`+ : Bool → Bool → Bool+ = λ(m : Bool) → λ(n : Bool) → m || n++let example8 = assert : `||` False True ≡ True++in { `+`, `*`, `++`, `#`, `==`, `!=`, `&&`, `||` }
@@ -1,20 +1,3 @@-{--Returns `False` if the supplied function returns `False` for a present element-and `True` otherwise:--Examples:--```-./all Natural Natural/even (Some 3) = False--./all Natural Natural/even (None Natural) = True-```--}-let all- : ∀(a : Type) → (a → Bool) → Optional a → Bool- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : Optional a)- → Optional/fold a xs Bool f True--in all+ missing+ sha256:a303004b6def0a2a05bf5f0a8d54e84dd45d8bef581789186ac04924956a1695+? ./all.dhall
@@ -0,0 +1,16 @@+{-|+Returns `False` if the supplied function returns `False` for a present element+and `True` otherwise:+-}+let all+ : ∀(a : Type) → (a → Bool) → Optional a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : Optional a) →+ merge { Some = f, None = True } xs++let example0 = assert : all Natural Natural/even (Some 3) ≡ False++let example1 = assert : all Natural Natural/even (None Natural) ≡ True++in all
@@ -1,20 +1,3 @@-{--Returns `True` if the supplied function returns `True` for a present element and-`False` otherwise--Examples:--```-./any Natural Natural/even (Some 2) = True--./any Natural Natural/even (None Natural) = False-```--}-let any- : ∀(a : Type) → (a → Bool) → Optional a → Bool- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : Optional a)- → Optional/fold a xs Bool f False--in any+ missing+ sha256:96a5cf4f31b3c598b09161dd3082f0a09f4328a4cefda6a7e09894b37b17b435+? ./any.dhall
@@ -0,0 +1,16 @@+{-|+Returns `True` if the supplied function returns `True` for a present element and+`False` otherwise+-}+let any+ : ∀(a : Type) → (a → Bool) → Optional a → Bool+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : Optional a) →+ merge { Some = f, None = False } xs++let example0 = assert : any Natural Natural/even (Some 2) ≡ True++let example1 = assert : any Natural Natural/even (None Natural) ≡ False++in any
@@ -1,36 +1,3 @@-{--`build` is the inverse of `fold`--Examples:--```-./build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ some 1-)-= Some 1--./build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ none-)-= None Natural-```--}-let build- : ∀(a : Type)- → ( ∀(optional : Type)- → ∀(some : a → optional)- → ∀(none : optional)- → optional- )- → Optional a- = Optional/build--in build+ missing+ sha256:28e61294bf2dd59dc57cf74f719d1568e60b5ba46c28eac586bc937eff4a2af1+? ./build.dhall
@@ -0,0 +1,41 @@+--| `build` is the inverse of `fold`+let build+ : ∀(a : Type) →+ ( ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ ) →+ Optional a+ = λ(a : Type) →+ λ ( build+ : ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ ) →+ build (Optional a) (λ(x : a) → Some x) (None a)++let example0 =+ assert+ : build+ Natural+ ( λ(optional : Type) →+ λ(some : Natural → optional) →+ λ(none : optional) →+ some 1+ )+ ≡ Some 1++let example1 =+ assert+ : build+ Natural+ ( λ(optional : Type) →+ λ(some : Natural → optional) →+ λ(none : optional) →+ none+ )+ ≡ None Natural++in build
@@ -1,28 +1,3 @@-{--Flatten two `Optional` layers into a single `Optional` layer--Examples:--```-./concat Natural (Some (Some 1))-= Some 1--./concat Natural (Some (None Natural))-= None Natural--./concat Natural (None (Optional Natural))-= None Natural-```--}-let concat- : ∀(a : Type) → Optional (Optional a) → Optional a- = λ(a : Type)- → λ(x : Optional (Optional a))- → Optional/fold- (Optional a)- x- (Optional a)- (λ(y : Optional a) → y)- (None a)--in concat+ missing+ sha256:b7736bd3ebeab14c3912dfb534d0c970a025b001d06c2d5461d4b0e289e3cb7a+? ./concat.dhall
@@ -0,0 +1,14 @@+--| Flatten two `Optional` layers into a single `Optional` layer+let concat+ : ∀(a : Type) → Optional (Optional a) → Optional a+ = λ(a : Type) →+ λ(x : Optional (Optional a)) →+ merge { Some = λ(y : Optional a) → y, None = None a } x++let example0 = assert : concat Natural (Some (Some 1)) ≡ Some 1++let example1 = assert : concat Natural (Some (None Natural)) ≡ None Natural++let example2 = assert : concat Natural (None (Optional Natural)) ≡ None Natural++in concat
@@ -0,0 +1,23 @@+--| Transform the value with a function and flatten the resulting `Optional`+let concatMap+ : ∀(a : Type) → ∀(b : Type) → (a → Optional b) → Optional a → Optional b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → Optional b) →+ λ(o : Optional a) →+ merge { Some = f, None = None b } o++let exampleFun+ : Natural → Optional Natural+ = λ(n : Natural) → if Natural/even n then Some (n + 1) else None Natural++let example0 =+ assert : concatMap Natural Natural exampleFun (Some 1) ≡ None Natural++let example1 = assert : concatMap Natural Natural exampleFun (Some 2) ≡ Some 3++let example2 =+ assert+ : concatMap Natural Natural exampleFun (None Natural) ≡ None Natural++in concatMap
@@ -0,0 +1,3 @@+ missing+ sha256:5bd665b0d6605c374b3c4a7e2e2bd3b9c1e39323d41441149ed5e30d86e889ad+? ./default.dhall
@@ -0,0 +1,13 @@+--| Unpack an `Optional`, returning the default when it's `None`.+let default+ : ∀(a : Type) → a → Optional a → a+ = λ(a : Type) →+ λ(default : a) →+ λ(o : Optional a) →+ merge { Some = λ(x : a) → x, None = default } o++let example0 = assert : default Bool False (None Bool) ≡ False++let example1 = assert : default Bool False (Some True) ≡ True++in default
@@ -0,0 +1,24 @@+let Optional/fold =+ missing+ sha256:c5b9d72f6f62bdaa0e196ac1c742cc175cd67a717b880fb8aec1333a5a4132cf+ ? ./fold.dhall++let Optional/null =+ missing+ sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc+ ? ./null.dhall++let equal+ : forall (a : Type) -> (a -> a -> Bool) -> Optional a -> Optional a -> Bool+ = \(a : Type) ->+ \(compare : a -> a -> Bool) ->+ \(ox : Optional a) ->+ \(oy : Optional a) ->+ Optional/fold+ a+ ox+ Bool+ (\(x : a) -> Optional/fold a oy Bool (compare x) False)+ (Optional/null a oy)++in equal
@@ -1,32 +1,3 @@-{--Only keep an `Optional` element if the supplied function returns `True`--Examples:--```-./filter Natural Natural/even (Some 2)-= Some 2--./filter Natural Natural/odd (Some 2)-= None Natural-```--}-let filter- : ∀(a : Type) → (a → Bool) → Optional a → Optional a- = λ(a : Type)- → λ(f : a → Bool)- → λ(xs : Optional a)- → Optional/build- a- ( λ(optional : Type)- → λ(some : a → optional)- → λ(none : optional)- → Optional/fold- a- xs- optional- (λ(x : a) → if f x then some x else none)- none- )--in filter+ missing+ sha256:54f0a487d578801819613fe000050c038c632edf1f9ccc57677e98ae0ef56b83+? ./filter.dhall
@@ -0,0 +1,29 @@+--| Only keep an `Optional` element if the supplied function returns `True`+let filter+ : ∀(a : Type) → (a → Bool) → Optional a → Optional a+ = λ(a : Type) →+ λ(f : a → Bool) →+ λ(xs : Optional a) →+ ( λ(a : Type) →+ λ ( build+ : ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ ) →+ build (Optional a) (λ(x : a) → Some x) (None a)+ )+ a+ ( λ(optional : Type) →+ λ(some : a → optional) →+ λ(none : optional) →+ merge+ { Some = λ(x : a) → if f x then some x else none, None = none }+ xs+ )++let example0 = assert : filter Natural Natural/even (Some 2) ≡ Some 2++let example1 = assert : filter Natural Natural/odd (Some 2) ≡ None Natural++in filter
@@ -1,21 +1,3 @@-{--`fold` is the primitive function for consuming `Optional` values--Examples:--```-./fold Natural (Some 2) Natural (λ(x : Natural) → x) 0 = 2--./fold Natural (None Natural) Natural (λ(x : Natural) → x) 0 = 0-```--}-let fold- : ∀(a : Type)- → Optional a- → ∀(optional : Type)- → ∀(some : a → optional)- → ∀(none : optional)- → optional- = Optional/fold--in fold+ missing+ sha256:c5b9d72f6f62bdaa0e196ac1c742cc175cd67a717b880fb8aec1333a5a4132cf+? ./fold.dhall
@@ -0,0 +1,20 @@+--| `fold` is the primitive function for consuming `Optional` values+let fold+ : ∀(a : Type) →+ Optional a →+ ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ = λ(a : Type) →+ λ(o : Optional a) →+ λ(optional : Type) →+ λ(some : a → optional) →+ λ(none : optional) →+ merge { Some = some, None = none } o++let example0 = assert : fold Natural (Some 2) Text Natural/show "0" ≡ "2"++let example1 = assert : fold Natural (None Natural) Text Natural/show "0" ≡ "0"++in fold
@@ -1,28 +1,3 @@-{--Returns the first non-empty `Optional` value in a `List`--Examples:--```-./head Natural [ None Natural, Some 1, Some 2 ] = Some 1--./head Natural [ None Natural, None Natural ] = None Natural--./head Natural ([] : List (Optional Natural)) = None Natural-```--}-let head- : ∀(a : Type) → List (Optional a) → Optional a- = λ(a : Type)- → λ(xs : List (Optional a))- → List/fold- (Optional a)- xs- (Optional a)- ( λ(l : Optional a)- → λ(r : Optional a)- → Optional/fold a l (Optional a) (λ(x : a) → Some x) r- )- (None a)--in head+ missing+ sha256:4f256c9338b60a1933f41f2a8fafd861930a1e41770a644cdbac0622676fa34c+? ./head.dhall
@@ -0,0 +1,24 @@+--| Returns the first non-empty `Optional` value in a `List`+let head+ : ∀(a : Type) → List (Optional a) → Optional a+ = λ(a : Type) →+ λ(xs : List (Optional a)) →+ List/fold+ (Optional a)+ xs+ (Optional a)+ ( λ(l : Optional a) →+ λ(r : Optional a) →+ merge { Some = λ(x : a) → Some x, None = r } l+ )+ (None a)++let example0 = assert : head Natural [ None Natural, Some 1, Some 2 ] ≡ Some 1++let example1 =+ assert : head Natural [ None Natural, None Natural ] ≡ None Natural++let example2 =+ assert : head Natural ([] : List (Optional Natural)) ≡ None Natural++in head
@@ -1,28 +1,3 @@-{--Returns the last non-empty `Optional` value in a `List`--Examples:--```-./last Natural [ None Natural, Some 1, Some 2 ] = Some 2--./last Natural [ None Natural, None Natural ] = None Natural--./last Natural ([] : List (Optional Natural)) = None Natural-```--}-let last- : ∀(a : Type) → List (Optional a) → Optional a- = λ(a : Type)- → λ(xs : List (Optional a))- → List/fold- (Optional a)- xs- (Optional a)- ( λ(l : Optional a)- → λ(r : Optional a)- → Optional/fold a r (Optional a) (λ(x : a) → Some x) l- )- (None a)--in last+ missing+ sha256:50400771ae19e9b75efa6581feec318ae1ade0b6a60e215df428c66c4b052707+? ./last.dhall
@@ -0,0 +1,24 @@+--| Returns the last non-empty `Optional` value in a `List`+let last+ : ∀(a : Type) → List (Optional a) → Optional a+ = λ(a : Type) →+ λ(xs : List (Optional a)) →+ List/fold+ (Optional a)+ xs+ (Optional a)+ ( λ(l : Optional a) →+ λ(r : Optional a) →+ merge { Some = λ(x : a) → Some x, None = l } r+ )+ (None a)++let example0 = assert : last Natural [ None Natural, Some 1, Some 2 ] ≡ Some 2++let example1 =+ assert : last Natural [ None Natural, None Natural ] ≡ None Natural++let example2 =+ assert : last Natural ([] : List (Optional Natural)) ≡ None Natural++in last
@@ -1,18 +1,3 @@-{--Returns `1` if the `Optional` value is present and `0` if the value is absent--Examples:--```-./length Natural (Some 2) = 1--./length Natural (None Natural) = 0-```--}-let length- : ∀(a : Type) → Optional a → Natural- = λ(a : Type)- → λ(xs : Optional a)- → Optional/fold a xs Natural (λ(_ : a) → 1) 0--in length+ missing+ sha256:f168337c5244ded68c05ecf32ce068b6b87158881d07e87b8cb6853fc6982a85+? ./length.dhall
@@ -0,0 +1,14 @@+{-|+Returns `1` if the `Optional` value is present and `0` if the value is absent+-}+let length+ : ∀(a : Type) → Optional a → Natural+ = λ(a : Type) →+ λ(xs : Optional a) →+ merge { Some = λ(_ : a) → 1, None = 0 } xs++let example0 = assert : length Natural (Some 2) ≡ 1++let example1 = assert : length Natural (None Natural) ≡ 0++in length
@@ -1,20 +1,3 @@-{--Transform an `Optional` value with a function--Examples:--```-./map Natural Bool Natural/even (Some 3) = Some False--./map Natural Bool Natural/even (None Natural) = None Bool-```--}-let map- : ∀(a : Type) → ∀(b : Type) → (a → b) → Optional a → Optional b- = λ(a : Type)- → λ(b : Type)- → λ(f : a → b)- → λ(o : Optional a)- → Optional/fold a o (Optional b) (λ(x : a) → Some (f x)) (None b)--in map+ missing+ sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa+? ./map.dhall
@@ -0,0 +1,14 @@+--| Transform an `Optional` value with a function+let map+ : ∀(a : Type) → ∀(b : Type) → (a → b) → Optional a → Optional b+ = λ(a : Type) →+ λ(b : Type) →+ λ(f : a → b) →+ λ(o : Optional a) →+ merge { Some = λ(x : a) → Some (f x), None = None b } o++let example0 = assert : map Natural Bool Natural/even (Some 3) ≡ Some False++let example1 = assert : map Natural Bool Natural/even (None Natural) ≡ None Bool++in map
@@ -1,18 +1,3 @@-{--Returns `True` if the `Optional` value is absent and `False` if present--Examples:--```-./null Natural (Some 2) = False--./null Natural (None Natural) = True-```--}-let null- : ∀(a : Type) → Optional a → Bool- = λ(a : Type)- → λ(xs : Optional a)- → Optional/fold a xs Bool (λ(_ : a) → False) True--in null+ missing+ sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc+? ./null.dhall
@@ -0,0 +1,12 @@+--| Returns `True` if the `Optional` value is absent and `False` if present+let null+ : ∀(a : Type) → Optional a → Bool+ = λ(a : Type) →+ λ(xs : Optional a) →+ merge { Some = λ(_ : a) → False, None = True } xs++let example0 = assert : null Natural (Some 2) ≡ False++let example1 = assert : null Natural (None Natural) ≡ True++in null
@@ -1,40 +1,65 @@ { all =- ./all sha256:b9b015fe8be14da940901aa1510ee1d5e205df37ee651c32ac975a799782c410- ? ./all+ missing+ sha256:a303004b6def0a2a05bf5f0a8d54e84dd45d8bef581789186ac04924956a1695+ ? ./all.dhall , any =- ./any sha256:0a637c0f2cc7d30b8f0bca021d2ee1ad1213fb9d9712c669b29feab66a590eaf- ? ./any+ missing+ sha256:96a5cf4f31b3c598b09161dd3082f0a09f4328a4cefda6a7e09894b37b17b435+ ? ./any.dhall , build =- ./build sha256:f331299d1279cfb88dd25a5acfdd64130900991b6154239ad343a2883f6eb50c- ? ./build+ missing+ sha256:28e61294bf2dd59dc57cf74f719d1568e60b5ba46c28eac586bc937eff4a2af1+ ? ./build.dhall , concat =- ./concat sha256:b49a3b7dc49eb83d150977caa5ae347be1cbbe14e3b6d0e07349bd2e5f707d69- ? ./concat+ missing+ sha256:b7736bd3ebeab14c3912dfb534d0c970a025b001d06c2d5461d4b0e289e3cb7a+ ? ./concat.dhall+, concatMap =+ missing+ sha256:c06ae93e900a99299c9b4ec4912ca5395a0103ea88292205b08dd7e345632818+ ? ./concatMap.dhall+, default =+ missing+ sha256:5bd665b0d6605c374b3c4a7e2e2bd3b9c1e39323d41441149ed5e30d86e889ad+ ? ./default.dhall+, equal =+ missing+ sha256:5411888399fe9c6720f7f3b59caf5eff3e8e8c30402d09f34e46a4457649a35a+ ? ./equal.dhall , filter =- ./filter sha256:b3d5e19a6cec592a76c12167a9e5e1e76649e776229d70a11c77b76cd29f617e- ? ./filter+ missing+ sha256:54f0a487d578801819613fe000050c038c632edf1f9ccc57677e98ae0ef56b83+ ? ./filter.dhall , fold =- ./fold sha256:62139ff410ca84302acebe763a8a1794420dd472d907384c7fb80df2a2180302- ? ./fold+ missing+ sha256:c5b9d72f6f62bdaa0e196ac1c742cc175cd67a717b880fb8aec1333a5a4132cf+ ? ./fold.dhall , head =- ./head sha256:b0b5d257294515f1de35f24fa83e54d7f1d5ebca9c3c1fc903a80ab40e19b3a6- ? ./head+ missing+ sha256:4f256c9338b60a1933f41f2a8fafd861930a1e41770a644cdbac0622676fa34c+ ? ./head.dhall , last =- ./last sha256:f839221a8a04adae6c501458eb264e7f4e375a1facb294cb80caacfd012a6765- ? ./last+ missing+ sha256:50400771ae19e9b75efa6581feec318ae1ade0b6a60e215df428c66c4b052707+ ? ./last.dhall , length =- ./length sha256:722a3754a411c053f006a32c506a6d1b14869c2ab799169df9cdac346edf07d3- ? ./length+ missing+ sha256:f168337c5244ded68c05ecf32ce068b6b87158881d07e87b8cb6853fc6982a85+ ? ./length.dhall , map =- ./map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d- ? ./map+ missing+ sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa+ ? ./map.dhall , null =- ./null sha256:efc43103e49b56c5bf089db8e0365bbfc455b8a2f0dc6ee5727a3586f85969fd- ? ./null+ missing+ sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc+ ? ./null.dhall , toList =- ./toList sha256:390fe99619e9a25e71a253a2b33011f9e5fa26a7d990795205543d1edd72ce5b- ? ./toList+ missing+ sha256:d78f160c619119ef12389e48a629ce293d69f7624c8d016b7a4767ab400344c4+ ? ./toList.dhall , unzip =- ./unzip sha256:7b517bc2a8a4dbec044c6bea5e059cafde5a0cb1d3a5e7d13d346c9327a00f30- ? ./unzip+ missing+ sha256:d016c01ba91657a2f35609aa29087963d0f506bab0f41d5e8b7cd289dff39708+ ? ./unzip.dhall }
@@ -1,18 +1,3 @@-{--Convert an `Optional` value into the equivalent `List`--Examples:--```-./toList Natural (Some 1) = [ 1 ]--./toList Natural (None Natural) = [] : List Natural-```--}-let toList- : ∀(a : Type) → Optional a → List a- = λ(a : Type)- → λ(o : Optional a)- → Optional/fold a o (List a) (λ(x : a) → [ x ] : List a) ([] : List a)--in toList+ missing+ sha256:d78f160c619119ef12389e48a629ce293d69f7624c8d016b7a4767ab400344c4+? ./toList.dhall
@@ -0,0 +1,12 @@+--| Convert an `Optional` value into the equivalent `List`+let toList+ : ∀(a : Type) → Optional a → List a+ = λ(a : Type) →+ λ(o : Optional a) →+ merge { Some = λ(x : a) → [ x ] : List a, None = [] : List a } o++let example0 = assert : toList Natural (Some 1) ≡ [ 1 ]++let example1 = assert : toList Natural (None Natural) ≡ ([] : List Natural)++in toList
@@ -1,38 +1,3 @@-{--Unzip an `Optional` value into two separate `Optional` values--Examples:--```-./unzip Text Bool (Some { _1 = "ABC", _2 = True })-= { _1 = Some "ABC", _2 = Some True }--./unzip Text Bool (None { _1 : Text, _2 : Bool })-= { _1 = None Text, _2 = None Bool }-```--}-let unzip- : ∀(a : Type)- → ∀(b : Type)- → Optional { _1 : a, _2 : b }- → { _1 : Optional a, _2 : Optional b }- = λ(a : Type)- → λ(b : Type)- → λ(xs : Optional { _1 : a, _2 : b })- → { _1 =- Optional/fold- { _1 : a, _2 : b }- xs- (Optional a)- (λ(x : { _1 : a, _2 : b }) → Some x._1)- (None a)- , _2 =- Optional/fold- { _1 : a, _2 : b }- xs- (Optional b)- (λ(x : { _1 : a, _2 : b }) → Some x._2)- (None b)- }--in unzip+ missing+ sha256:d016c01ba91657a2f35609aa29087963d0f506bab0f41d5e8b7cd289dff39708+? ./unzip.dhall
@@ -0,0 +1,30 @@+--| Unzip an `Optional` value into two separate `Optional` values+let unzip+ : ∀(a : Type) →+ ∀(b : Type) →+ Optional { _1 : a, _2 : b } →+ { _1 : Optional a, _2 : Optional b }+ = λ(a : Type) →+ λ(b : Type) →+ λ(xs : Optional { _1 : a, _2 : b }) →+ { _1 =+ merge+ { Some = λ(x : { _1 : a, _2 : b }) → Some x._1, None = None a }+ xs+ , _2 =+ merge+ { Some = λ(x : { _1 : a, _2 : b }) → Some x._2, None = None b }+ xs+ }++let example0 =+ assert+ : unzip Text Bool (Some { _1 = "ABC", _2 = True })+ ≡ { _1 = Some "ABC", _2 = Some True }++let example1 =+ assert+ : unzip Text Bool (None { _1 : Text, _2 : Bool })+ ≡ { _1 = None Text, _2 = None Bool }++in unzip
@@ -1,17 +1,3 @@-{--Concatenate all the `Text` values in a `List`--Examples:--```-./concat [ "ABC", "DEF", "GHI" ] = "ABCDEFGHI"--./concat ([] : List Text) = ""-```--}-let concat- : List Text → Text- = λ(xs : List Text)- → List/fold Text xs Text (λ(x : Text) → λ(y : Text) → x ++ y) ""--in concat+ missing+ sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0+? ./concat.dhall
@@ -0,0 +1,11 @@+--| Concatenate all the `Text` values in a `List`+let concat+ : List Text → Text+ = λ(xs : List Text) →+ List/fold Text xs Text (λ(x : Text) → λ(y : Text) → x ++ y) ""++let example0 = assert : concat [ "ABC", "DEF", "GHI" ] ≡ "ABCDEFGHI"++let example1 = assert : concat ([] : List Text) ≡ ""++in concat
@@ -1,21 +1,3 @@-{--Transform each value in a `List` into `Text` and concatenate the result--Examples:--```-./concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]-= "0 1 2 "--./concatMap Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)-= ""-```--}-let concatMap- : ∀(a : Type) → (a → Text) → List a → Text- = λ(a : Type)- → λ(f : a → Text)- → λ(xs : List a)- → List/fold a xs Text (λ(x : a) → λ(y : Text) → f x ++ y) ""--in concatMap+ missing+ sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f+? ./concatMap.dhall
@@ -0,0 +1,22 @@+--| Transform each value in a `List` into `Text` and concatenate the result+let concatMap+ : ∀(a : Type) → (a → Text) → List a → Text+ = λ(a : Type) →+ λ(f : a → Text) →+ λ(xs : List a) →+ List/fold a xs Text (λ(x : a) → λ(y : Text) → f x ++ y) ""++let example0 =+ assert+ : concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]+ ≡ "0 1 2 "++let example1 =+ assert+ : concatMap+ Natural+ (λ(n : Natural) → "${Natural/show n} ")+ ([] : List Natural)+ ≡ ""++in concatMap
@@ -1,41 +1,3 @@-{--Transform each value in a `List` to `Text` and then concatenate them with a-separator in between each value--Examples:--```-./concatMapSep ", " Natural Natural/show [ 0, 1, 2 ] = "0, 1, 2"--./concatMapSep ", " Natural Natural/show ([] : List Natural) = ""-```--}-let Status = < Empty | NonEmpty : Text >--let concatMapSep- : ∀(separator : Text) → ∀(a : Type) → (a → Text) → List a → Text- = λ(separator : Text)- → λ(a : Type)- → λ(f : a → Text)- → λ(elements : List a)- → let status =- List/fold- a- elements- Status- ( λ(x : a)- → λ(status : Status)- → merge- { Empty =- Status.NonEmpty (f x)- , NonEmpty =- λ(result : Text)- → Status.NonEmpty (f x ++ separator ++ result)- }- status- )- Status.Empty- - in merge { Empty = "", NonEmpty = λ(result : Text) → result } status--in concatMapSep+ missing+ sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840+? ./concatMapSep.dhall
@@ -0,0 +1,38 @@+{-|+Transform each value in a `List` to `Text` and then concatenate them with a+separator in between each value+-}+let Status = < Empty | NonEmpty : Text >++let concatMapSep+ : ∀(separator : Text) → ∀(a : Type) → (a → Text) → List a → Text+ = λ(separator : Text) →+ λ(a : Type) →+ λ(f : a → Text) →+ λ(elements : List a) →+ let status =+ List/fold+ a+ elements+ Status+ ( λ(x : a) →+ λ(status : Status) →+ merge+ { Empty = Status.NonEmpty (f x)+ , NonEmpty =+ λ(result : Text) →+ Status.NonEmpty (f x ++ separator ++ result)+ }+ status+ )+ Status.Empty++ in merge { Empty = "", NonEmpty = λ(result : Text) → result } status++let example0 =+ assert : concatMapSep ", " Natural Natural/show [ 0, 1, 2 ] ≡ "0, 1, 2"++let example1 =+ assert : concatMapSep ", " Natural Natural/show ([] : List Natural) ≡ ""++in concatMapSep
@@ -1,38 +1,3 @@-{--Concatenate a `List` of `Text` values with a separator in between each value--Examples:--```-./concatSep ", " [ "ABC", "DEF", "GHI" ] = "ABC, DEF, GHI"--./concatSep ", " ([] : List Text) = ""-```--}-let Status = < Empty | NonEmpty : Text >--let concatSep- : ∀(separator : Text) → ∀(elements : List Text) → Text- = λ(separator : Text)- → λ(elements : List Text)- → let status =- List/fold- Text- elements- Status- ( λ(element : Text)- → λ(status : Status)- → merge- { Empty =- Status.NonEmpty element- , NonEmpty =- λ(result : Text)- → Status.NonEmpty (element ++ separator ++ result)- }- status- )- Status.Empty- - in merge { Empty = "", NonEmpty = λ(result : Text) → result } status--in concatSep+ missing+ sha256:e4401d69918c61b92a4c0288f7d60a6560ca99726138ed8ebc58dca2cd205e58+? ./concatSep.dhall
@@ -0,0 +1,31 @@+--| Concatenate a `List` of `Text` values with a separator in between each value+let Status = < Empty | NonEmpty : Text >++let concatSep+ : ∀(separator : Text) → ∀(elements : List Text) → Text+ = λ(separator : Text) →+ λ(elements : List Text) →+ let status =+ List/fold+ Text+ elements+ Status+ ( λ(element : Text) →+ λ(status : Status) →+ merge+ { Empty = Status.NonEmpty element+ , NonEmpty =+ λ(result : Text) →+ Status.NonEmpty (element ++ separator ++ result)+ }+ status+ )+ Status.Empty++ in merge { Empty = "", NonEmpty = λ(result : Text) → result } status++let example0 = assert : concatSep ", " [ "ABC", "DEF", "GHI" ] ≡ "ABC, DEF, GHI"++let example1 = assert : concatSep ", " ([] : List Text) ≡ ""++in concatSep
@@ -0,0 +1,3 @@+ missing+ sha256:f532c8891b1e427d90a6cc07cf7e793a4c84b0765e1bfe69f186ee2ec91c1edf+? ./default.dhall
@@ -0,0 +1,10 @@+--| Unwrap an `Optional` `Text` value, defaulting `None` to `""`+let default+ : Optional Text → Text+ = λ(o : Optional Text) → merge { Some = λ(t : Text) → t, None = "" } o++let example0 = assert : default (Some "ABC") ≡ "ABC"++let example1 = assert : default (None Text) ≡ ""++in default
@@ -0,0 +1,3 @@+ missing+ sha256:3a3fa1264f6198800c27483cb144de2c5366484876d60b9c739a710ce0288588+? ./defaultMap.dhall
@@ -0,0 +1,13 @@+--| Transform the value in an `Optional` into `Text`, defaulting `None` to `""`+let defaultMap+ : ∀(a : Type) → (a → Text) → Optional a → Text+ = λ(a : Type) →+ λ(f : a → Text) →+ λ(o : Optional a) →+ merge { Some = f, None = "" } o++let example0 = assert : defaultMap Natural Natural/show (Some 0) ≡ "0"++let example1 = assert : defaultMap Natural Natural/show (None Natural) ≡ ""++in defaultMap
@@ -0,0 +1,56 @@+{-|+Lowercase all ASCII characters++Note that this will also lowercase decomposed Unicode characters that contain+codepoints in the ASCII range+-}+let lowerASCII+ : Text → Text+ = List/fold+ (Text → Text)+ [ Text/replace "A" "a"+ , Text/replace "B" "b"+ , Text/replace "C" "c"+ , Text/replace "D" "d"+ , Text/replace "E" "e"+ , Text/replace "F" "f"+ , Text/replace "G" "g"+ , Text/replace "H" "h"+ , Text/replace "I" "i"+ , Text/replace "J" "j"+ , Text/replace "K" "k"+ , Text/replace "L" "l"+ , Text/replace "M" "m"+ , Text/replace "N" "n"+ , Text/replace "O" "o"+ , Text/replace "P" "p"+ , Text/replace "Q" "q"+ , Text/replace "R" "r"+ , Text/replace "S" "s"+ , Text/replace "T" "t"+ , Text/replace "U" "u"+ , Text/replace "V" "v"+ , Text/replace "W" "w"+ , Text/replace "X" "x"+ , Text/replace "Y" "y"+ , Text/replace "Z" "z"+ ]+ Text+ (λ(replacement : Text → Text) → replacement)++let example0 = assert : lowerASCII "ABCdef" ≡ "abcdef"++let -- This does not lowercase precomposed Unicode characters+ --+ -- • The `Á` in the following example is U+00C1+ example1 =+ assert : lowerASCII "Á" ≡ "Á"++let -- … but this does lowercase decomposed Unicode characters+ --+ -- • The `Á` in the following example is U+0041 U+0301+ -- • The `á` in the following example is U+0061 U+0301+ example1 =+ assert : lowerASCII "Á" ≡ "á"++in lowerASCII
@@ -1,16 +1,53 @@ { concat =- ./concat sha256:35e20d9403fbadb1a0061edb84e076ed56313709fa4bc8124d86ff54896f20ac- ? ./concat+ missing+ sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0+ ? ./concat.dhall , concatMap =- ./concatMap sha256:175d893ad7f2b2c05fff9e32f0d9cbadc7f5fce57945071508cf3603f8aa298e- ? ./concatMap+ missing+ sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f+ ? ./concatMap.dhall , concatMapSep =- ./concatMapSep sha256:46b81a9e211fb8278bf2793e75e8175fef79e0e3e478ef1016e3233ecc2ddfe6- ? ./concatMapSep+ missing+ sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840+ ? ./concatMapSep.dhall , concatSep =- ./concatSep sha256:d28e61f5057a240e857e09dba1b040fa3477bddb9659c5606c760852a9165890- ? ./concatSep+ missing+ sha256:e4401d69918c61b92a4c0288f7d60a6560ca99726138ed8ebc58dca2cd205e58+ ? ./concatSep.dhall+, default =+ missing+ sha256:f532c8891b1e427d90a6cc07cf7e793a4c84b0765e1bfe69f186ee2ec91c1edf+ ? ./default.dhall+, defaultMap =+ missing+ sha256:3a3fa1264f6198800c27483cb144de2c5366484876d60b9c739a710ce0288588+ ? ./defaultMap.dhall+, lowerASCII =+ missing+ sha256:26b076651120b907e869396bd3dc16271f2e12433062b2f26f296968a69515e7+ ? ./lowerASCII.dhall+, replace =+ missing+ sha256:7d132df0e091a43817bba8afa06d1bb487ee51c091430404ad6f8c78bc0328a6+ ? ./replace.dhall+, replicate =+ missing+ sha256:1b398b1d464b3a6c7264a690ac3cacb443b5683b43348c859d68e7c2cb925c4f+ ? ./replicate.dhall+, shell-escape =+ missing+ sha256:d53521b3f478cb18a7d63730bc0e3153c2124b70d6ac9a1f610ce7db67cfc7a2+ ? ./shell-escape.dhall , show =- ./show sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784- ? ./show+ missing+ sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784+ ? ./show.dhall+, spaces =+ missing+ sha256:fccfd4f26601e006bf6a79ca948dbd37c676cdd0db439554447320293d23b3dc+ ? ./spaces.dhall+, upperASCII =+ missing+ sha256:45ae4fbd814b0474e65c28a4ee92b23b979892fa5bb73730bc99675ae790ca29+ ? ./upperASCII.dhall }
@@ -0,0 +1,14 @@+{-+Replace a section of `Text` with another inside a `Text` literal.+-}+let replace+ : ∀(needle : Text) → ∀(replacement : Text) → ∀(haystack : Text) → Text+ = Text/replace++let example0 = assert : replace "-" "_" "foo-bar" ≡ "foo_bar"++let example1 = assert : replace "💣" "💥" "💣💣💣" ≡ "💥💥💥"++let example2 = assert : replace "👨" "👩" "👨👩👧👦" ≡ "👩👩👧👦"++in replace
@@ -0,0 +1,3 @@+ missing+ sha256:1b398b1d464b3a6c7264a690ac3cacb443b5683b43348c859d68e7c2cb925c4f+? ./replicate.dhall
@@ -0,0 +1,20 @@+--| Build a Text by copying the given Text the specified number of times+let concat =+ missing+ sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0+ ? ./concat.dhall++let List/replicate =+ missing+ sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347+ ? ../List/replicate.dhall++let replicate+ : Natural → Text → Text+ = λ(num : Natural) → λ(text : Text) → concat (List/replicate num Text text)++let example0 = assert : replicate 3 "foo" ≡ "foofoofoo"++let property = λ(text : Text) → assert : replicate 0 text ≡ ""++in replicate
@@ -0,0 +1,16 @@+{-|+Escape a Text value such that it can be used safely in shells.+The escaping is done by replacing all `'` with `'"'"'` and wraps that string in+single quotes.++This works for all POSIX-compliant shells and some other shells like csh.+-}+let shell-escape+ : Text -> Text+ = \(xs : Text) -> "'${Text/replace "'" "'\"'\"'" xs}'"++let example0 = assert : shell-escape "foo" === "'foo'"++let example1 = assert : shell-escape "foo'bar" === "'foo'\"'\"'bar'"++in shell-escape
@@ -1,13 +1,3 @@-{--Render a `Text` literal as its own representation as Dhall source code (i.e. a-double-quoted string literal)--Examples:--```-./show "ABC" = "\"ABC\""--./show "\u0000 \$ \\ \n \u263a" = "\"\\u0000 \\u0024 \\\\ \\n ☺\""-```--}-let show : Text → Text = Text/show in show+ missing+ sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784+? ./show.dhall
@@ -0,0 +1,19 @@+{-+Render a `Text` literal as its own representation as Dhall source code (i.e. a+double-quoted string literal)+-}+let show+ : Text → Text+ = Text/show++let example0 = assert : show "ABC" ≡ "\"ABC\""++let example1 =+ assert+ : show+ ''+ ${"\u0000"} $ \ + ${" "}☺''+ ≡ "\"\\u0000 \\u0024 \\\\ \\n ☺\""++in show
@@ -0,0 +1,3 @@+ missing+ sha256:fccfd4f26601e006bf6a79ca948dbd37c676cdd0db439554447320293d23b3dc+? ./spaces.dhall
@@ -0,0 +1,20 @@+{-|+Return a Text with the number of spaces specified.++This function is particularly helpful when trying to generate Text where+whitespace is significant, i.e. with nested indentation.+-}+let replicate =+ missing+ sha256:1b398b1d464b3a6c7264a690ac3cacb443b5683b43348c859d68e7c2cb925c4f+ ? ./replicate.dhall++let spaces+ : Natural → Text+ = λ(a : Natural) → replicate a " "++let example0 = assert : spaces 1 ≡ " "++let example1 = assert : spaces 0 ≡ ""++in spaces
@@ -0,0 +1,56 @@+{-|+Uppercase all ASCII characters++Note that this will also uppercase decomposed Unicode characters that contain+codepoints in the ASCII range+-}+let upperASCII+ : Text → Text+ = List/fold+ (Text → Text)+ [ Text/replace "a" "A"+ , Text/replace "b" "B"+ , Text/replace "c" "C"+ , Text/replace "d" "D"+ , Text/replace "e" "E"+ , Text/replace "f" "F"+ , Text/replace "g" "G"+ , Text/replace "h" "H"+ , Text/replace "i" "I"+ , Text/replace "j" "J"+ , Text/replace "k" "K"+ , Text/replace "l" "L"+ , Text/replace "m" "M"+ , Text/replace "n" "N"+ , Text/replace "o" "O"+ , Text/replace "p" "P"+ , Text/replace "q" "Q"+ , Text/replace "r" "R"+ , Text/replace "s" "S"+ , Text/replace "t" "T"+ , Text/replace "u" "U"+ , Text/replace "v" "V"+ , Text/replace "w" "W"+ , Text/replace "x" "X"+ , Text/replace "y" "Y"+ , Text/replace "z" "Z"+ ]+ Text+ (λ(replacement : Text → Text) → replacement)++let example0 = assert : upperASCII "ABCdef" ≡ "ABCDEF"++let -- This does not uppercase precomposed Unicode characters+ --+ -- • The `á` in the following example is U+00E1+ example1 =+ assert : upperASCII "á" ≡ "á"++let -- … but this does uppercase decomposed Unicode characters+ --+ -- • The `Á` in the following example is U+0041 U+0301+ -- • The `á` in the following example is U+0061 U+0301+ example1 =+ assert : upperASCII "á" ≡ "Á"++in upperASCII
@@ -0,0 +1,5 @@+{ show =+ missing+ sha256:8cabfe35dd0ee25ca65708105e860cbf4b789e0d73134aa905580799e2a46719+ ? ./show.dhall+}
@@ -0,0 +1,15 @@+{-+Render a `Time` as `Text` using the same representation as Dhall source code+(i.e. `hh:mm:ss`)+-}+let show+ : Time → Text+ = Time/show++let example0 = assert : show 03:15:47.90 ≡ "03:15:47.90"++let example1 = assert : show 00:00:00 ≡ "00:00:00"++let example2 = assert : show 11:59:59 ≡ "11:59:59"++in show
@@ -0,0 +1,5 @@+{ show =+ missing+ sha256:d183361f1c4c656bad3b170ec8b8d6705f564faebf94e4ef10c76061104ff061+ ? ./show.dhall+}
@@ -0,0 +1,15 @@+{-+Render a `TimeZone` as `Text` using the same representation as Dhall source code+(i.e. `±HH:MM`)+-}+let show+ : TimeZone → Text+ = TimeZone/show++let example0 = assert : show +07:00 ≡ "+07:00"++let example1 = assert : show +00:00 ≡ "+00:00"++let example2 = assert : show -05:00 ≡ "-05:00"++in show
@@ -0,0 +1,3 @@+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+? ./Type.dhall
@@ -0,0 +1,65 @@+{-|+Dhall encoding of an arbitrary XML element++For example, the following XML element:++```+<foo n="1"><bar>baz</bar></foo>+```++... corresponds to the following Dhall expression:+++```+λ(XML : Type)+ → λ ( xml+ : { text :+ Text → XML+ , rawText :+ Text → XML+ , element :+ { attributes :+ List { mapKey : Text, mapValue : Text }+ , content :+ List XML+ , name :+ Text+ }+ → XML+ }+ )+ → xml.element+ { attributes =+ [ { mapKey = "n", mapValue = "1" } ]+ , content =+ [ xml.element+ { attributes =+ [] : List { mapKey : Text, mapValue : Text }+ , content =+ [ xml.text "baz" ]+ , name =+ "bar"+ }+ ]+ , name =+ "foo"+ }+```+-}+let XML/Type+ : Type+ = ∀(XML : Type) →+ ∀ ( xml+ : { text : Text → XML+ , rawText : Text → XML+ , element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ }+ ) →+ XML++in XML/Type
@@ -0,0 +1,3 @@+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+? ./attribute.dhall
@@ -0,0 +1,6 @@+--| Builds a key-value record with a Text key and value.+let attribute+ : Text → Text → { mapKey : Text, mapValue : Text }+ = λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }++in attribute
@@ -0,0 +1,3 @@+ missing+ sha256:79266d604e147caf37e985581523b684f7bac66de0c93dd828841df3dfc445f9+? ./element.dhall
@@ -0,0 +1,59 @@+{-|+Create an XML element value.++```+let XML = ./package.dhall++in XML.render+ ( XML.element+ { name = "foo"+ , attributes = XML.emptyAttributes+ , content =+ [ XML.leaf { name = "bar", attributes = [ XML.attribute "n" "1" ] }+ , XML.leaf { name = "baz", attributes = [ XML.attribute "n" "2" ] }+ ]+ }+ )++= "<foo><bar n=\"1\"/><baz n=\"2\"/></foo>"+```+-}+let XML =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall++let List/map =+ missing+ sha256:dd845ffb4568d40327f2a817eb42d1c6138b929ca758d50bc33112ef3c885680+ ? ../List/map.dhall++let Args =+ { attributes : List { mapKey : Text, mapValue : Text }+ , name : Text+ , content : List XML+ }+ : Type++let element+ : Args → XML+ = λ(elem : Args) →+ λ(XML : Type) →+ λ ( xml+ : { text : Text → XML+ , rawText : Text → XML+ , element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ }+ ) →+ xml.element+ { attributes = elem.attributes+ , name = elem.name+ , content = List/map XML@1 XML (λ(x : XML@1) → x XML xml) elem.content+ }++in element
@@ -0,0 +1,3 @@+ missing+ sha256:11b86e2d3f3c75d47a1d580213d2a03fd2c36d64f3e9b6381de0ba23472f64d5+? ./emptyAttributes.dhall
@@ -0,0 +1,2 @@+--| Create an empty XML attribute List.+[] : List { mapKey : Text, mapValue : Text }
@@ -0,0 +1,3 @@+ missing+ sha256:5dcedf79a3664a362479f470220bb2f4932facde657c285fd8a3c24ab137c506+? ./leaf.dhall
@@ -0,0 +1,30 @@+{-|+Create an XML element value without child elements.++```+let XML = ./package.dhall++in XML.render (XML.leaf { name = "foobar", attributes = XML.emptyAttributes })++= "<foobar/>"+```+-}+let XML =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall++let element =+ missing+ sha256:79266d604e147caf37e985581523b684f7bac66de0c93dd828841df3dfc445f9+ ? ./element.dhall++let leaf+ : { attributes : List { mapKey : Text, mapValue : Text }, name : Text } →+ XML+ = λ ( elem+ : { attributes : List { mapKey : Text, mapValue : Text }, name : Text }+ ) →+ element (elem ⫽ { content = [] : List XML })++in leaf
@@ -0,0 +1,33 @@+{ Type =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall+, attribute =+ missing+ sha256:f7b6c802ca5764d03d5e9a6e48d9cb167c01392f775d9c2c87b83cdaa60ea0cc+ ? ./attribute.dhall+, render =+ missing+ sha256:395c293702c85d99f6f2b461f3eee320f9fe5749c320c2e8b9ea799a7d210b66+ ? ./render.dhall+, element =+ missing+ sha256:79266d604e147caf37e985581523b684f7bac66de0c93dd828841df3dfc445f9+ ? ./element.dhall+, leaf =+ missing+ sha256:5dcedf79a3664a362479f470220bb2f4932facde657c285fd8a3c24ab137c506+ ? ./leaf.dhall+, text =+ missing+ sha256:a59670560a08bfc815893dee1f3eae21a5252400f8a619d1cd7bdd9f48eea2ab+ ? ./text.dhall+, rawText =+ missing+ sha256:2af9d72c151677d4110039e361b7e9faaf2947e6c9d29aa72aea351ad797e05d+ ? ./rawText.dhall+, emptyAttributes =+ missing+ sha256:11b86e2d3f3c75d47a1d580213d2a03fd2c36d64f3e9b6381de0ba23472f64d5+ ? ./emptyAttributes.dhall+}
@@ -0,0 +1,40 @@+{-|+Create a Text value to be inserted into an XML element as content with no+character escaping.++```+let XML = ./package.dhall++in XML.render+ ( XML.element+ { name = "location"+ , attributes = XML.emptyAttributes+ , content = [ XML.rawText "<bar n=\"1\"/>" ]+ }+ )+= "<foo><bar n=\"1\"/></foo>"+```+-}+let XML =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall++let rawText+ : Text → XML+ = λ(d : Text) →+ λ(XML : Type) →+ λ ( xml+ : { text : Text → XML+ , rawText : Text → XML+ , element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ }+ ) →+ xml.rawText d++in rawText
@@ -0,0 +1,3 @@+ missing+ sha256:395c293702c85d99f6f2b461f3eee320f9fe5749c320c2e8b9ea799a7d210b66+? ./render.dhall
@@ -0,0 +1,140 @@+{-|+Render an `XML` value as `Text`++For indentation and schema validation, see the `xmllint` utility+bundled with libxml2.++```+let XML = ./package.dhall++in XML.render+ ( XML.element+ { name = "foo"+ , attributes = [ XML.attribute "a" "x", XML.attribute "b" (Natural/show 2) ]+ , content = [ XML.leaf { name = "bar", attributes = XML.emptyAttributes } ]+ }+ )+= "<foo a=\"x\" b=\"2\"><bar/></foo>"+```++-}+let XML =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall++let Text/concatMap =+ missing+ sha256:7a0b0b99643de69d6f94ba49441cd0fa0507cbdfa8ace0295f16097af37e226f+ ? ../Text/concatMap.dhall++let Text/concat =+ missing+ sha256:731265b0288e8a905ecff95c97333ee2db614c39d69f1514cb8eed9259745fc0+ ? ../Text/concat.dhall++let element =+ missing+ sha256:79266d604e147caf37e985581523b684f7bac66de0c93dd828841df3dfc445f9+ ? ./element.dhall++let text =+ missing+ sha256:a59670560a08bfc815893dee1f3eae21a5252400f8a619d1cd7bdd9f48eea2ab+ ? ./text.dhall++let emptyAttributes =+ missing+ sha256:11b86e2d3f3c75d47a1d580213d2a03fd2c36d64f3e9b6381de0ba23472f64d5+ ? ./emptyAttributes.dhall++let Attr = { mapKey : Text, mapValue : Text }++let esc = λ(x : Text) → λ(y : Text) → Text/replace x "&${y};"++let `escape&` = esc "&" "amp"++let `escape<` = esc "<" "lt"++let `escape>` = esc ">" "gt"++let `escape'` = esc "'" "apos"++let `escape"` = esc "\"" "quot"++let escapeCommon = λ(text : Text) → `escape<` (`escape&` text)++let escapeAttr = λ(text : Text) → `escape"` (`escape'` (escapeCommon text))++let escapeText = λ(text : Text) → `escape>` (escapeCommon text)++let renderAttr = λ(x : Attr) → " ${x.mapKey}=\"${escapeAttr x.mapValue}\""++let render+ : XML → Text+ = λ(x : XML) →+ x+ Text+ { text = escapeText+ , rawText = λ(t : Text) → t+ , element =+ λ ( elem+ : { attributes : List { mapKey : Text, mapValue : Text }+ , content : List Text+ , name : Text+ }+ ) →+ let attribs = Text/concatMap Attr renderAttr elem.attributes++ in "<${elem.name}${attribs}"+ ++ ( if Natural/isZero (List/length Text elem.content)+ then "/>"+ else ">${Text/concat elem.content}</${elem.name}>"+ )+ }++let simple =+ λ(name : Text) →+ λ(content : List XML) →+ element { name, attributes = emptyAttributes, content }++let example0 =+ assert+ : render+ ( simple+ "note"+ [ simple "to" [ text "Tove" ]+ , simple "from" [ text "Jani" ]+ , simple "heading" [ text "Reminder" ]+ , simple "body" [ text "Don't forget me this weekend!" ]+ ]+ )+ ≡ Text/replace+ "\n"+ ""+ ''+ <note>+ <to>Tove</to>+ <from>Jani</from>+ <heading>Reminder</heading>+ <body>Don't forget me this weekend!</body>+ </note>+ ''++let example1 =+ assert+ : render+ ( element+ { name = "escape"+ , attributes = toMap { attribute = "<>'\"&" }+ , content = [ text "<>'\"&" ]+ }+ )+ ≡ Text/replace+ "\n"+ ""+ ''+ <escape attribute="<>'"&"><>'"&</escape>+ ''++in render
@@ -0,0 +1,3 @@+ missing+ sha256:a59670560a08bfc815893dee1f3eae21a5252400f8a619d1cd7bdd9f48eea2ab+? ./text.dhall
@@ -0,0 +1,39 @@+{-|+Create a Text value to be inserted into an XML element as content.++```+let XML = ./package.dhall++in XML.render+ ( XML.element+ { name = "location"+ , attributes = XML.emptyAttributes+ , content = [ XML.text "/foo/bar" ]+ }+ )+= "<location>/foo/bar</location>"+```+-}+let XML =+ missing+ sha256:ab91a0edaf0513e0083b1dfae5efa160adc99b0e589775a4a699ab77cce528a9+ ? ./Type.dhall++let text+ : Text → XML+ = λ(d : Text) →+ λ(XML : Type) →+ λ ( xml+ : { text : Text → XML+ , rawText : Text → XML+ , element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ }+ ) →+ xml.text d++in text
@@ -1,28 +1,73 @@ { Bool =- ./Bool/package.dhall sha256:7ee950e7c2142be5923f76d00263e536b71d96cb9c190d7743c1679501ddeb0a+ missing+ sha256:dde2b9b71afdd26878c06e90cd2cde4488063457d5fbe30e02baed3bec5eede6 ? ./Bool/package.dhall+, Date =+ missing+ sha256:fc0c5efc924fa99aa8e5dea5d78c3dc1a24cb550028342b90149ea78cb5ca873+ ? ./Date/package.dhall , Double =- ./Double/package.dhall sha256:b8d20ab3216083622ae371fb42a6732bc67bb2d66e84989c8ddba7556a336cf7+ missing+ sha256:b8d20ab3216083622ae371fb42a6732bc67bb2d66e84989c8ddba7556a336cf7 ? ./Double/package.dhall , Function =- ./Function/package.dhall sha256:74c3822b98b9d37f9f820af8e1a7ee790bcfac03050eabd45af4a255fb93e026+ missing+ sha256:f4ca848f69034f9d7a74e12c556c3a3396966c1de3a9427a102d1aff4580192f ? ./Function/package.dhall , Integer =- ./Integer/package.dhall sha256:eb464566d3192dd16ce915a9bd874aaaad612d5c69beb356e5b7d2e0c4949dcf+ missing+ sha256:d1a572ca3a764781496847e4921d7d9a881c18ffcfac6ae28d0e5299066938a0 ? ./Integer/package.dhall+, JSON =+ missing+ sha256:5f98b7722fd13509ef448b075e02b9ff98312ae7a406cf53ed25012dbc9990ac+ ? ./JSON/package.dhall , List =- ./List/package.dhall sha256:108be3af5ebd465f7091039f2216c433e65ae5d25556a9a71786dd84d33ef49a+ missing+ sha256:26d1b4cd800219d8b67043c638926aa6e5517ea74a0bd3e371974514621bca04 ? ./List/package.dhall+, Location =+ missing+ sha256:0eb4e4a60814018009c720f6820aaa13cf9491eb1b09afb7b832039c6ee4d470+ ? ./Location/package.dhall+, Map =+ missing+ sha256:c5e79a9de642644a09b96a2ec3147c5d8662b7926f09610e751c0c0f6ed0b30a+ ? ./Map/package.dhall+, Monoid =+ missing+ sha256:26fafa098600ef7a54ef9dba5ada416bbbdd21df1af306c052420c61553ad4af+ ? ./Monoid.dhall , Natural =- ./Natural/package.dhall sha256:fe08155c3a04500df847ca94d013ecd3dfc73ab5c136109b2414fce3ec42b63a+ missing+ sha256:ee9ed2b28a417ed4e9a0c284801b928bf91b3fbdc1a68616347678c1821f1ddf ? ./Natural/package.dhall+, NonEmpty =+ missing+ sha256:c24686a230a4b3cd51e5a57cd4510b4f8242f813d7823d41bac5954e7af56f7a+ ? ./NonEmpty/package.dhall+, Operator =+ missing+ sha256:861f724704a7b4755c96f173e54d03f314492a2d046723404c31ff612b7bf2e6+ ? ./Operator/package.dhall , Optional =- ./Optional/package.dhall sha256:36a366af67a3c26cd5d196e095d3023f18953c5b5db3a03956fa554609e5442a+ missing+ sha256:74331dfe59c09db65edc7ec4498bff92473c8c06d92752f9470d26e25f91320c ? ./Optional/package.dhall-, JSON =- ./JSON/package.dhall sha256:7f0c25a292e5d34ddfbbf3f6d90505567382f95d822b04f5810745f81ab1ef35- ? ./JSON/package.dhall , Text =- ./Text/package.dhall sha256:c8bc93456397476051dc674c180ddd5db098546861c8df24bda8284511d3305e+ missing+ sha256:79b671a70ac459b799a53bbb8a383cc8b81b40421745c54bf0fb1143168cbd6f ? ./Text/package.dhall+, Time =+ missing+ sha256:6715c4c71a113429fef8b94e4561a93c288942dad9dfd75ac545de96c5b5652a+ ? ./Time/package.dhall+, TimeZone =+ missing+ sha256:c17fd403c637856f34c8287168b92974e8c1a3a7331967f75276d179057084fd+ ? ./TimeZone/package.dhall+, XML =+ missing+ sha256:2e111f0952087d42072b059f0bf4c95861a46bffa67ad4c8c39086edf405f32e+ ? ./XML/package.dhall }
@@ -0,0 +1,6 @@+-- For https://github.com/dhall-lang/dhall-haskell/issues/929+ λ(b : Bool)+→ λ(bool : Type)+→ λ(true : bool)+→ λ(false : bool)+→ if b then true else false
@@ -0,0 +1,1 @@+λ(_ : Bool) → λ(_ : Type) → λ(_ : _) → λ(_ : _@1) → if _@3 then _@1 else _
@@ -1,1 +1,1 @@-λ(_ : A) → b+λ(_ : Bool) → _
@@ -1,1 +1,1 @@-λ(_ : A) → b+λ(_ : Bool) → _
@@ -1,1 +1,1 @@-λ(x : A) → x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-λ(_ : A) → _+λ(_ : Bool) → _
@@ -1,1 +1,1 @@-λ(x : A) → λ(_ : B) → x+λ(x : Bool) → λ(_ : Natural) → x
@@ -1,1 +1,1 @@-λ(_ : A) → λ(_ : B) → _@1+λ(_ : Bool) → λ(_ : Natural) → _@1
@@ -1,1 +1,1 @@-\(_: Bool) -> \(_: Bool) -> _ && _@1+λ(_ : Bool) → λ(_ : Bool) → _ && _@1
@@ -1,1 +1,4 @@+{-+ This test has free variables, so it doesn't typecheck+-} \(x: Bool) -> \(x: Bool) -> [x, x@0, x@1, x@2, x@3]
@@ -1,1 +1,1 @@-\(_: Bool) -> \(_: Bool) -> _@1 && _+λ(_ : Bool) → λ(_ : Bool) → _@1 && _
@@ -1,1 +1,1 @@-A → B+Bool → Natural
@@ -1,1 +1,1 @@-A → B+Bool → Natural
@@ -1,1 +1,1 @@-∀(x : A) → x+∀(x : Type) → x
@@ -1,1 +1,1 @@-A → _+Type → _
@@ -1,1 +1,1 @@-∀(x : A) → B → x+∀(x : Type) → Type → x
@@ -1,1 +1,1 @@-A → B → _@1+Type → Type → _@1
binary file changed (absent → 6 bytes)
binary file changed (absent → 6 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+
binary file changed (absent → 4 bytes)
binary file changed (absent → 6 bytes)
binary file changed (absent → 6 bytes)
binary file changed (absent → 6 bytes)
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+gNatural
@@ -0,0 +1,1 @@+5 : Natural
binary file changed (absent → 16 bytes)
@@ -0,0 +1,1 @@+Natural/show _
binary file changed (absent → 18 bytes)
@@ -0,0 +1,1 @@+f x y z
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+assert : _
@@ -0,0 +1,1 @@+ô
@@ -0,0 +1,1 @@+False
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+if True then x else y
@@ -0,0 +1,1 @@+õ
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,1 @@+lNatural/show
@@ -0,0 +1,1 @@+Natural/show
@@ -0,0 +1,1 @@+pNatural/subtract
@@ -0,0 +1,1 @@+Natural/subtract
binary file changed (absent → 114 bytes)
@@ -0,0 +1,23 @@+[ 0x"00"+, 0x"01"+, 0x"02"+, 0x"03"+, 0x"04"+, 0x"05"+, 0x"06"+, 0x"07"+, 0x"08"+, 0x"09"+, 0x"0a"+, 0x"0b"+, 0x"0c"+, 0x"0d"+, 0x"0e"+, 0x"0f"+, 0x"0A"+, 0x"0B"+, 0x"0C"+, 0x"0D"+, 0x"0E"+, 0x"0F"+]
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+T::r
@@ -0,0 +1,1 @@+Ð
@@ -0,0 +1,1 @@+2000-01-01
binary file changed (absent → 9 bytes)
@@ -0,0 +1,6 @@+{-+The CBOR for this is an (oversized) double-precision number. It could have been+stored as single- (or even half-) precision, but we require decoders to accept+it anyway.+-}+2.0
binary file changed (absent → 3 bytes)
@@ -0,0 +1,7 @@+{-+The CBOR for this is a half-precision number. Although dhall specifies that+encoders should only use half-precision for infinities and NaN, it also+specifies that decoders should tolerate floating point numbers with any+precision.+-}+1.0
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+Infinity
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+-Infinity
binary file changed (absent → 5 bytes)
@@ -0,0 +1,4 @@+{-+The CBOR for this is a single-precision number+-}+2.0
@@ -0,0 +1,1 @@+ÃIÿÿÿÿÿÿÿÿ
@@ -0,0 +1,2 @@+{- -2^65 -}+-36893488147419103232
binary file changed (absent → 13 bytes)
@@ -0,0 +1,2 @@+{- 2^65 -}++36893488147419103232
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+-1
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@++0
binary file changed (absent → 9 bytes)
@@ -0,0 +1,1 @@+λ(x : _) → x
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+λ(_ : Natural) → _
binary file changed (absent → 26 bytes)
@@ -0,0 +1,1 @@+let x : Natural = 1 let y = 2 in x
binary file changed (absent → 20 bytes)
@@ -0,0 +1,1 @@+let x : Natural = 1 in x
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+let x = 1 in x
@@ -0,0 +1,1 @@+gNatural
@@ -0,0 +1,1 @@+[] : List Natural
binary file changed (absent → 7 bytes)
@@ -0,0 +1,1 @@+[] : x
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+[ _ ]
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+merge _ _@1 : _@2
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+merge _ _@1
binary file changed (absent → 13 bytes)
@@ -0,0 +1,2 @@+{- 2^65 -}+36893488147419103232
@@ -0,0 +1,1 @@+
@@ -0,0 +1,5 @@+{-+24 is the first natural number that has a different CBOR encoding, hence the+separate test here.+-}+24
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+0
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ && _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ∧ _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ⩓ _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ == _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ≡ _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ? _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ # _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ != _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ || _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ + _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ⫽ _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ ++ _@1
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_ * _@1
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+∀(x : Natural) → _
@@ -0,0 +1,1 @@+gNaturaldText
@@ -0,0 +1,1 @@+Natural → Text
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+_.x
@@ -0,0 +1,1 @@+¢axgNaturalaydBool
@@ -0,0 +1,1 @@+{ x = Natural, y = Bool }
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+r.{ x, y, z }
@@ -0,0 +1,1 @@+¢axgNaturalaydBool
@@ -0,0 +1,1 @@+{ x : Natural, y : Bool }
binary file changed (absent → 4 bytes)
@@ -0,0 +1,1 @@+Some _
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+"foo${_}bar"
@@ -0,0 +1,1 @@+cfoo
@@ -0,0 +1,1 @@+"foo"
binary file changed (absent → 9 bytes)
@@ -0,0 +1,1 @@+12:00:00
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@++08:00
binary file changed (absent → 7 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+toMap e : T
@@ -0,0 +1,1 @@+toMap e
@@ -0,0 +1,1 @@+¢axgNaturalayö
@@ -0,0 +1,1 @@+< x : Natural | y >
@@ -0,0 +1,1 @@+ax
@@ -0,0 +1,1 @@+x@1
binary file changed (absent → 12 bytes)
@@ -0,0 +1,16 @@+{-++This file tests that a number encoded as a type larger than required is still+read successfully. In this case, the .dhallb file has the bytes:++ 8261 781b 0000 0000 0000 0001++which means the array ["x", uint64(1)]. This could have been stored in fewer+bytes as++ 8261 7801++but decoders are required to allow the oversized representation.++-}+x@1
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+_@4
binary file changed (absent → 9 bytes)
@@ -0,0 +1,13 @@+{-++This file tests that a number encoded as a type larger than required is still+read successfully. In this case, the .dhallb file has the bytes:++ 1b00 0000 0000 0000 01++which means a uint64 with value 1. The number 1 could have been stored in a+single byte as 01, but decoders are required to allow the oversized+representation.++-}+_@1
binary file changed (absent → 10 bytes)
@@ -0,0 +1,1 @@+env:FOO
binary file changed (absent → 41 bytes)
@@ -0,0 +1,1 @@+http://foo:bar@baz:123/path1/path2?query
binary file changed (absent → 36 bytes)
@@ -0,0 +1,1 @@+http://foo:bar@baz:123/path1/path2
binary file changed (absent → 36 bytes)
@@ -0,0 +1,2 @@+{- an empty query string is not the same as an absent query string -}+https://foo:bar@baz:123/path1/path2?
binary file changed (absent → 41 bytes)
@@ -0,0 +1,1 @@+https://foo:bar@baz:123/path1/path2?query
binary file changed (absent → 46 bytes)
@@ -0,0 +1,1 @@+https://authority/path:with!funny-characters
binary file changed (absent → 32 bytes)
@@ -0,0 +1,1 @@+https://authority/path?a%23b%5Bc
binary file changed (absent → 36 bytes)
@@ -0,0 +1,1 @@+https://foo:bar@baz:123/path1/path2
binary file changed (absent → 29 bytes)
@@ -0,0 +1,1 @@+./path0/path1/path2/file
binary file changed (absent → 29 bytes)
@@ -0,0 +1,1 @@+~/path0/path1/path2/file
binary file changed (absent → 29 bytes)
@@ -0,0 +1,1 @@+../path0/path1/path2/file
binary file changed (absent → 29 bytes)
@@ -0,0 +1,1 @@+/path0/path1/path2/file
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+missing
@@ -0,0 +1,2 @@++¢aaab¡aagNatural
@@ -0,0 +1,1 @@+{ a = 1, b = 2 }.({ a : Natural })
binary file changed (absent → 42 bytes)
@@ -0,0 +1,1 @@+xevil string from bad cache
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/AllowedAll.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/Empty.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/NoCORS.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/Null.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/OnlyGithub.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/OnlyOther.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/OnlySelf.dhall
@@ -0,0 +1,1 @@+https://prelude.dhall-lang.org/List/length
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/SelfImportAbsolute.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/SelfImportRelative.dhall
@@ -1,1 +1,1 @@-../failure/cycle.dhall+../failure/unit/Cycle.dhall
@@ -0,0 +1,1 @@+[
@@ -0,0 +1,1 @@+0 0
@@ -0,0 +1,1 @@+#Eg«Íï
@@ -1,1 +0,0 @@-{ foo = 1, bar = True }
@@ -1,1 +0,0 @@-{ bar = True, foo = 1 }
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,3 @@+-- This file contains a free variable. This should be a type error, even if the variable+-- is in scope in the importing expression+x
@@ -0,0 +1,1 @@+{ x = ./simple.dhall sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2 }
@@ -0,0 +1,4 @@+{- This file has a poisoned cache entry. We want to+ ensure we ignore cache entries which don't match+ the hash -}+"Correct benign content"
@@ -9,12 +9,10 @@ this file attempts to import a referentially opaque import (an environment variable in this case) to verify that the import fails. - For this test file we need to select a referentially opaque import that would- likely succeed if imported on its own, so that a non-compliant implementation- doesn't fail this test for the wrong reason (i.e. due to the referentially- opaque not being present). In general, we can't guarantee that referentially- opaque imports exist (because they are referentially opaque!), but the- `HOME` environment variable has a high likelihood of bring present on a POSIX- system.+ For this test file we need to select a referentially opaque import that+ would succeed if imported on its own, so that a non-compliant implementation+ doesn't fail this test for the wrong reason (i.e. due to the import not+ being present). We thus use the `DHALL_TEST_VAR` environment variable, that+ is expected to be set when running import tests. -}-env:HOME as Text+env:DHALL_TEST_VAR as Text
@@ -0,0 +1,1 @@+./simple.dhall as Location
@@ -0,0 +1,1 @@+"Dhall (from import)"
@@ -0,0 +1,15 @@+{- This is a type error because the custom headers are type-checked with an+ empty context. This is necessary because:++ * import resolution precedes β-normalization+ * we also don't want custom headers to leak program state anyway++ This should fail due to the `x` within the custom header being an unbound+ variable+-}++let x = "Bar"++in https://httpbin.org/headers+ using [ { mapKey = "Foo", mapValue = x } ]+ as Text
@@ -1,1 +0,0 @@-../data/cycle.dhall
@@ -1,1 +0,0 @@-../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -1,1 +0,0 @@-missing
@@ -0,0 +1,1 @@+https://httpbin.org/user-agent as Text
@@ -0,0 +1,11 @@+-- Use of a remote import causes Cyclic Import on env:DHALL_HEADERS+toMap+ { DHALL_HEADERS =+ ''+ toMap {+ `httpbin.org:443` = toMap {+ `User-Agent` = http://example.com as Text+ }+ }+ ''+ }
@@ -1,13 +0,0 @@-{- The following remote import attempts to import an environment variable, which- must be disallowed by the referential sanity check-- One reason for doing this is to protect against remote imports exfiltrating- environment variables (such as via custom headers). Only referentially- opaque imports (i.e. local imports) have permission to refer to other- referentially opaque imports in order to protect against this attack.-- The referential sanity check also ensures that remote imports are- referentially transparent. Or in other words, any import that is globally- addressable must have a meaning that is not context-sensitive.--}-https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/tests/import/data/referentiallyOpaque.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/nonexistent-file.dhall
@@ -0,0 +1,1 @@+../../data/cycle.dhall
@@ -0,0 +1,1 @@+../../data/cycle.dhall ? 0
@@ -0,0 +1,3 @@+-- This fails because the `?` operator does not recover from integrity check+-- failures+../../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ? 0
@@ -0,0 +1,1 @@+../../data/doesNotParse.dhall ? 0
@@ -0,0 +1,1 @@+../../data/doesNotTypecheck.dhall ? 0
@@ -0,0 +1,13 @@+{- The following remote import attempts to import an environment variable, which+ must be disallowed by the referential sanity check++ One reason for doing this is to protect against remote imports exfiltrating+ environment variables (such as via custom headers). Only referentially+ opaque imports (i.e. local imports) have permission to refer to other+ referentially opaque imports in order to protect against this attack.++ The referential sanity check also ensures that remote imports are+ referentially transparent. Or in other words, any import that is globally+ addressable must have a meaning that is not context-sensitive.+-}+https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/tests/import/data/referentiallyOpaque.dhall
@@ -0,0 +1,1 @@+env:DHALL_TEST_UNSET
@@ -0,0 +1,1 @@+env:DHALL_TEST_UNSET as Text
@@ -0,0 +1,1 @@+./not-a-file.dhall
@@ -0,0 +1,1 @@+../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -0,0 +1,2 @@+-- This ensures that even if the file gets imported without hash first, the hash check is not skipped later+../../data/simple.dhall + ../../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ../../data/simple.dhall
@@ -0,0 +1,1 @@+missing
@@ -0,0 +1,1 @@+\(x: Bool) -> ../../data/importBoundary.dhall
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/Empty.dhall
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/NoCORS.dhall
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/Null.dhall
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/OnlyOther.dhall
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/OnlySelf.dhall
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/TwoHopsFail.dhall
@@ -0,0 +1,1 @@+"hello"
@@ -1,1 +0,0 @@-env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3 ? 2
@@ -1,1 +0,0 @@-2
@@ -1,1 +0,0 @@-env:UNSET ? 3
@@ -1,1 +0,0 @@-3
@@ -1,2 +0,0 @@- ../data/simple.dhall sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-? 42
@@ -1,1 +0,0 @@-42
@@ -1,1 +0,0 @@-4 ? missing
@@ -1,1 +0,0 @@-4
@@ -1,1 +0,0 @@-(../data/example.txt) ? 42
@@ -1,1 +0,0 @@-42
@@ -1,1 +0,0 @@-../data/example.txt as Text
@@ -1,3 +0,0 @@-''-Hello, world!-''
@@ -1,3 +1,3 @@ https://httpbin.org/user-agent- using [ { header = "User-Agent", value = "Dhall" } ]+ using [ { mapKey = "User-Agent", mapValue = "Dhall" } ] as Text
@@ -1,5 +0,0 @@-{ example0 =- ../data/fieldOrder/1.dhall sha256:d8ae15ff5a40ee7973a23ba75cd98f8e39d14aeb6e1e3f18aadb092fcb825194-, example1 =- ../data/fieldOrder/2.dhall sha256:d8ae15ff5a40ee7973a23ba75cd98f8e39d14aeb6e1e3f18aadb092fcb825194-}
@@ -1,1 +0,0 @@-{ example0 = { bar = True, foo = 1 }, example1 = { bar = True, foo = 1 } }
@@ -0,0 +1,11 @@+{-+An import with an integrity check MUST be fetched from the cache if possible.++If you have set XDG_CACHE_HOME as described in tests/README.md, this hash will+be available in the cache, so even though this is a `missing` import, it can be+resolved by its hash.++(If you're interested, the value is a fully-αβ-normalized copy of+Prelude/Optional/null)+-}+missing sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc
@@ -0,0 +1,3 @@+λ(_ : Type) →+λ(_ : Optional _) →+ merge { None = True, Some = λ(_ : _@1) → False } _
@@ -1,16 +1,12 @@ {- This test verifies that header-forwarding works correctly for relative imports within the same domain - `test.dhall-lang.org` is the same as `prelude.dhall-lang.org` except that- `test.dhall-lang.org` rejects all requests without a `Test` header.+ `test.dhall-lang.org/foo` returns `./bar` and `test.dhall-lang.org/foo`+ returns `True`, and both URLs reject all requests without a `Test` header. This test requires that the initial import to- `https://test.dhall-lang.org/Bool/package.dhall` forwards the `Test` header- to the transitive relative imports of `https://test.dhall-lang.org/Bool/*` in+ `https://test.dhall-lang.org/foo` forwards the `Test` header+ to the transitive relative import of `https://test.dhall-lang.org/bar` in order to succeed.-- Note: You will need to update this test whenever the `Bool` package in the- Prelude changes (sorry) -}-https://test.dhall-lang.org/Bool/package.dhall- using [ { header = "Test", value = "Example" } ]+https://test.dhall-lang.org/foo using (toMap { Test = "Example" })
@@ -1,26 +1,1 @@-{ and =- λ(xs : List Bool)- → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l && r) True-, build =- λ(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool)- → f Bool True False-, even =- λ(xs : List Bool)- → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x == y) True-, fold =- λ(b : Bool)- → λ(bool : Type)- → λ(true : bool)- → λ(false : bool)- → if b then true else false-, not =- λ(b : Bool) → b == False-, odd =- λ(xs : List Bool)- → List/fold Bool xs Bool (λ(x : Bool) → λ(y : Bool) → x != y) False-, or =- λ(xs : List Bool)- → List/fold Bool xs Bool (λ(l : Bool) → λ(r : Bool) → l || r) False-, show =- λ(b : Bool) → if b then "True" else "False"-}+True
@@ -0,0 +1,1 @@+../data/nested.dhall sha256:add9792d79d9e03918e3236f32c6f8e89dbc05efac3451eb835676275f2c20a5
@@ -0,0 +1,1 @@+{ x = 3 }
@@ -3,4 +3,4 @@ https://httpbin.org/user-agent -} https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/tests/import/success/customHeadersA.dhall- using [ { header = "User-Agent", value = "Secret" } ]+ using [ { mapKey = "User-Agent", mapValue = "Secret" } ]
@@ -0,0 +1,1 @@+https://httpbin.org/user-agent as Text
@@ -0,0 +1,5 @@+''+{+ "user-agent": "Dhall"+}+''
@@ -0,0 +1,10 @@+toMap+ { DHALL_HEADERS =+ ''+ toMap {+ `httpbin.org:443` = toMap {+ `User-Agent` = "Dhall"+ }+ }+ ''+ }
@@ -0,0 +1,1 @@+https://httpbin.org/user-agent as Text
@@ -0,0 +1,5 @@+''+{+ "user-agent": "Dhall (from import)"+}+''
@@ -0,0 +1,10 @@+toMap+ { DHALL_HEADERS =+ ''+ toMap {+ `httpbin.org:443` = toMap {+ `User-Agent` = ./dhall-lang/tests/import/data/userAgent.dhall+ }+ }+ ''+ }
@@ -0,0 +1,1 @@+https://httpbin.org/user-agent as Text
@@ -0,0 +1,5 @@+''+{+ "user-agent": "Dhall (from env)"+}+''
@@ -0,0 +1,11 @@+toMap+ { DHALL_HEADERS =+ ''+ toMap {+ `httpbin.org:443` = toMap {+ `User-Agent` = env:USER_AGENT as Text+ }+ }+ ''+ , USER_AGENT = "Dhall (from env)"+ }
@@ -0,0 +1,3 @@+https://httpbin.org/user-agent+ using [ { mapKey = "User-Agent", mapValue = "inline-header" } ]+ as Text
@@ -0,0 +1,5 @@+''+{+ "user-agent": "user-header"+}+''
@@ -0,0 +1,10 @@+toMap+ { DHALL_HEADERS =+ ''+ toMap {+ `httpbin.org:443` = toMap {+ `User-Agent` = "user-header"+ }+ }+ ''+ }
@@ -0,0 +1,1 @@+missing ? missing ? 42
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+missing ? 42 ? 10
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+env:DHALL_TEST_UNSET ? 42
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+missing ? 42
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+../../failure/missing.dhall ? 42
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+42 ? 10
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+42 ? missing
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+env:DHALL_TEST_VAR ? 10
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+missing + 10 ? 42
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+let x = 0 in (missing ? x)
@@ -0,0 +1,1 @@+let x = 0 in x
@@ -0,0 +1,1 @@+\(x: Natural) -> x ? y
@@ -0,0 +1,1 @@+λ(x : Natural) → x
@@ -0,0 +1,1 @@+\(x: Natural) -> (y + missing) ? x
@@ -0,0 +1,1 @@+λ(x : Natural) → x
@@ -0,0 +1,1 @@+../../data/example.bin as Bytes
@@ -0,0 +1,1 @@+0x"0123456789abcdef"
@@ -0,0 +1,1 @@+../../data/example.txt as Text
@@ -0,0 +1,3 @@+''+Hello, world!+''
@@ -0,0 +1,5 @@+-- The let triggers a loading of `simple.dhall` in the cache,+-- but the second import uses a hash that corresponds to a different file already in the content-addressed store.+-- This test ensures that we retrieve the value corresponding to the hash and not the path even if the path is in cache.+let x = ../../data/simple.dhall+in ../../data/simple.dhall sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc
@@ -0,0 +1,1 @@+let x = 3 in λ(_ : Type) → λ(_ : Optional _) → merge { `None` = True, `Some` = λ(_ : _@1) → False } _
@@ -0,0 +1,1 @@+env:DHALL_TEST_VAR
@@ -0,0 +1,1 @@+env:DHALL_TEST_VAR as Text
@@ -0,0 +1,1 @@+"6 * 7"
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+../../data/"file with spaces.txt"
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,1 @@+../../data/poisonedCache.dhall sha256:618f785ce8f3930a9144398f576f0a992544b51212bc9108c31b4e670dc6ed21
@@ -0,0 +1,1 @@+"Correct benign content"
@@ -0,0 +1,1 @@+~/hello.dhall ++ " world"
@@ -0,0 +1,1 @@+"hello" ++ " world"
@@ -0,0 +1,2 @@+-- This is to ensure caching doesn't accidentally confuse import modes+{ n = ../../data/simple.dhall, txt = ../../data/simple.dhall as Text, loc = ../../data/simple.dhall as Location }
@@ -0,0 +1,1 @@+{ loc = < Environment: Text | Local: Text | Missing | Remote: Text >.Local "./dhall-lang/tests/import/data/simple.dhall", n = 3, txt = "3\n" }
@@ -0,0 +1,1 @@+../../../../../dhall-lang/tests/normalization/success/unit/OperatorPlusOneAndOneA.dhall
@@ -0,0 +1,1 @@+2
@@ -0,0 +1,1 @@+../".."/"data"/"example.txt" as Text
@@ -0,0 +1,3 @@+''+Hello, world!+''
@@ -0,0 +1,1 @@+../../failure/unit/FileMissing.dhall ? 0
@@ -0,0 +1,1 @@+0
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/0b983b92aa2222dc3e292c20550ee37dea3f41df/tests/import/data/example.txt as Text
@@ -0,0 +1,3 @@+''+Hello, world!+''
@@ -0,0 +1,1 @@+../../data/simple.dhall
@@ -0,0 +1,1 @@+3
@@ -0,0 +1,1 @@+../../data/simple.dhall sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2
@@ -0,0 +1,1 @@+3
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/0b983b92aa2222dc3e292c20550ee37dea3f41df/tests/import/data/simple.dhall
@@ -0,0 +1,1 @@+3
@@ -0,0 +1,1 @@+/absolute/import as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "/absolute/import"
@@ -0,0 +1,1 @@+./foo/./bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/asLocation/foo/bar/import.dhall"
@@ -0,0 +1,1 @@+./foo/baz/../bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/asLocation/foo/bar/import.dhall"
@@ -0,0 +1,1 @@+./../bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/bar/import.dhall"
@@ -0,0 +1,1 @@+../../bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/bar/import.dhall"
@@ -0,0 +1,1 @@+./foo/../../bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/bar/import.dhall"
@@ -0,0 +1,1 @@+./Relative1A.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/asLocation/some/import.dhall"
@@ -0,0 +1,1 @@+./Canonicalize4A.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/bar/import.dhall"
@@ -0,0 +1,1 @@+../asLocation/Canonicalize4A.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/bar/import.dhall"
@@ -0,0 +1,1 @@+(missing as Location) ? 42 -- `missing` fails as an import, but definitely resolves as Location
@@ -0,0 +1,1 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Missing
@@ -0,0 +1,1 @@+env:DHALL_TEST_VAR as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Environment+ "DHALL_TEST_VAR"
@@ -0,0 +1,6 @@+{-+ If you have set XDG_CACHE_HOME as described in tests/README.md, this hash will+ be available in the cache. Since this is an `as Location` test however, you+ mustn't use the cache value here.+-}+./some/import.dhall sha256:efc43103e49b56c5bf089db8e0365bbfc455b8a2f0dc6ee5727a3586f85969fd as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/asLocation/some/import.dhall"
@@ -0,0 +1,1 @@+~/some/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "~/some/import.dhall"
@@ -0,0 +1,1 @@+missing as Location
@@ -0,0 +1,1 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Missing
@@ -0,0 +1,1 @@+./some/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/asLocation/some/import.dhall"
@@ -0,0 +1,1 @@+../some/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Local+ "./dhall-lang/tests/import/success/unit/some/import.dhall"
@@ -0,0 +1,1 @@+https://example.com/foo/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://example.com/foo/import.dhall"
@@ -0,0 +1,1 @@+https://example.com/foo/./bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://example.com/foo/bar/import.dhall"
@@ -0,0 +1,1 @@+https://example.com/foo/bar/../baz/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://example.com/foo/baz/import.dhall"
@@ -0,0 +1,1 @@+https://example.com/foo/bar/../../baz/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://example.com/baz/import.dhall"
@@ -0,0 +1,4 @@+{-+ The standardized behaviour does not respect https://tools.ietf.org/html/rfc3986#section-5.2 .+-}+https://example.com/../bar/import.dhall as Location
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://example.com/../bar/import.dhall"
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/0b983b92aa2222dc3e292c20550ee37dea3f41df/tests/import/data/simpleLocation.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://raw.githubusercontent.com/dhall-lang/dhall-lang/0b983b92aa2222dc3e292c20550ee37dea3f41df/tests/import/data/simple.dhall"
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/asLocation/Canonicalize3A.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/bar/import.dhall"
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/asLocation/Canonicalize5A.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Remote+ "https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/bar/import.dhall"
@@ -0,0 +1,5 @@+{-+ This test verifies that `env:VAR as Location` isn't rejected as referentially opaque,+ as `env:VAR` on its own would.+-}+https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/asLocation/EnvA.dhall
@@ -0,0 +1,2 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Environment+ "HOME"
@@ -0,0 +1,6 @@+{- This test verifies that `missing as Location` succeeds when chained since:+ * The `missing` is never actually resolved (due to the `as Location`)+ * The `missing` should be treated as referentially transparent (and therefore+ be a valid transitive dependency of a remote import)+-}+https://raw.githubusercontent.com/Nadrieril/dhall-rust/f7d8c64a9799f139ad65427c2518376adb9e2e2f/dhall/tests/import/success/unit/asLocation/MissingA.dhall
@@ -0,0 +1,1 @@+< Environment : Text | Local : Text | Missing | Remote : Text >.Missing
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/AllowedAll.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/NoCORS.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/OnlyGithub.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/acee30866a179c9e9bb3fc02ec8be2883685eb14/tests/import/data/cors/Prelude.dhall
@@ -0,0 +1,1 @@+List/length
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/SelfImportAbsolute.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/SelfImportAbsolute.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/SelfImportRelative.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/SelfImportRelative.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,1 @@+https://test.dhall-lang.org/cors/TwoHopsSuccess.dhall
@@ -0,0 +1,1 @@+42
@@ -0,0 +1,12 @@+{- This test illustrates that `with a = { c = 2 }` is not the same thing as+ `with a.c = 2`:++ * `with a = { c = 2 }` overrides the entire value of the field `a` with a new+ record containing only `c = 2`++ * `with a.c = 2` extends or updates the record stored underneath `a` to+ set the field `c` to `2`.++ Compare this to the `WithNested` test, which contains the `a.c = 2` case+-}+{ a.b = 1 } with a = { c = 2 }
@@ -0,0 +1,1 @@+{ a = { c = 2 } }
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/and [ True, False, True ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/and ([] : List Bool)
@@ -1,1 +0,0 @@-True
@@ -1,2 +0,0 @@-../../../../../../Prelude/Bool/build -(λ(bool : Type) → λ(true : bool) → λ(false : bool) → true)
@@ -1,1 +0,0 @@-True
@@ -1,2 +0,0 @@-../../../../../../Prelude/Bool/build -(λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False, True, False ]
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False, True ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even ([] : List Bool)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/fold True Natural 0 1
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/fold False Natural 0 1
@@ -1,1 +0,0 @@-1
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/not True
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/not False
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True, False, True ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True, False ]
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True ]
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd ([] : List Bool)
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/or [ True, False, True ]
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/or ([] : List Bool)
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/show True
@@ -1,1 +0,0 @@-"True"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/show False
@@ -1,1 +0,0 @@-"False"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Double/show -3.1
@@ -1,1 +0,0 @@-"-3.1"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Double/show 0.4
@@ -1,1 +0,0 @@-"0.4"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/show -3
@@ -1,1 +0,0 @@-"-3"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/show +0
@@ -1,1 +0,0 @@-"+0"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/toDouble -3
@@ -1,1 +0,0 @@--3.0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/toDouble +2
@@ -1,1 +0,0 @@-2.0
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/all Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/all Natural Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/any Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/any Natural Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-False
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ cons "ABC" (cons "DEF" nil)-)
@@ -1,1 +0,0 @@-[ "ABC", "DEF" ]
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ nil-)
@@ -1,1 +0,0 @@-[] : List Text
@@ -1,5 +0,0 @@-../../../../../../Prelude/List/concat Natural-[ [ 0, 1, 2 ]-, [ 3, 4 ]-, [ 5, 6, 7, 8 ]-]
@@ -1,1 +0,0 @@-[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
@@ -1,5 +0,0 @@-../../../../../../Prelude/List/concat Natural-[ [] : List Natural-, [] : List Natural-, [] : List Natural-]
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-[ 2, 2, 3, 3, 5, 5 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) ([] : List Natural)
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/filter Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-[ 2 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/filter Natural Natural/odd [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-[ 3, 5 ]
@@ -1,6 +0,0 @@-../../../../../../Prelude/List/fold-Natural-[ 2, 3, 5 ]-Natural-(λ(x : Natural) → λ(y : Natural) → x + y)-0
@@ -1,1 +0,0 @@-10
@@ -1,7 +0,0 @@- λ(nil : Natural)-→ ../../../../../../Prelude/List/fold- Natural- [ 2, 3, 5 ]- Natural- (λ(x : Natural) → λ(y : Natural) → x + y)- nil
@@ -1,1 +0,0 @@-λ(nil : Natural) → 2 + (3 + (5 + nil))
@@ -1,4 +0,0 @@- λ(list : Type)-→ λ(cons : Natural → list → list)-→ λ(nil : list)-→ ../../../../../../Prelude/List/fold Natural [ 2, 3, 5 ] list cons nil
@@ -1,4 +0,0 @@- λ(list : Type)-→ λ(cons : Natural → list → list)-→ λ(nil : list)-→ cons 2 (cons 3 (cons 5 nil))
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/generate 5 Bool Natural/even
@@ -1,1 +0,0 @@-[ True, False, True, False, True ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/generate 0 Bool Natural/even
@@ -1,1 +0,0 @@-[] : List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/head Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Some 0
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/head Natural ([] : List Natural)
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/indexed Bool [ True, False, True ]
@@ -1,4 +0,0 @@-[ { index = 0, value = True }-, { index = 1, value = False }-, { index = 2, value = True }-]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/indexed Bool ([] : List Bool)
@@ -1,1 +0,0 @@-[] : List { index : Natural, value : Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/iterate 10 Natural (λ(x : Natural) → x * 2) 1
@@ -1,1 +0,0 @@-[ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/iterate 0 Natural (λ(x : Natural) → x * 2) 1
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/last Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Some 2
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/last Natural ([] : List Natural)
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/length Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-3
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/length Natural ([] : List Natural)
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/map Natural Bool Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-[ True, False, False ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/map Natural Bool Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-[] : List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/null Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/null Natural ([] : List Natural)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/replicate 9 Natural 1
@@ -1,1 +0,0 @@-[ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/replicate 0 Natural 1
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/reverse Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-[ 2, 1, 0 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/reverse Natural ([] : List Natural)
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,15 +0,0 @@-../../../../../../Prelude/List/shifted-Bool-[ [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = False }- ]-, [ { index = 0, value = False }- , { index = 1, value = False }- ]-, [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = True }- , { index = 3, value = True }- ]-]
@@ -1,10 +0,0 @@-[ { index = 0, value = True }-, { index = 1, value = True }-, { index = 2, value = False }-, { index = 3, value = False }-, { index = 4, value = False }-, { index = 5, value = True }-, { index = 6, value = True }-, { index = 7, value = True }-, { index = 8, value = True }-]
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/shifted Bool ([] : List (List { index : Natural, value : Bool }))
@@ -1,1 +0,0 @@-[] : List { index : Natural, value : Bool }
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/unzip-Text-Bool-[ { _1 = "ABC", _2 = True }-, { _1 = "DEF", _2 = False }-, { _1 = "GHI", _2 = True }-]
@@ -1,1 +0,0 @@-{ _1 = [ "ABC", "DEF", "GHI" ], _2 = [ True, False, True ] }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/unzip Text Bool ([] : List { _1 : Text, _2 : Bool })
@@ -1,1 +0,0 @@-{ _1 = [] : List Text, _2 = [] : List Bool }
@@ -1,6 +0,0 @@-../../../../../../Prelude/Natural/build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ succ (succ (succ zero))-)
@@ -1,1 +0,0 @@-3
@@ -1,6 +0,0 @@-../../../../../../Prelude/Natural/build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ zero-)
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/enumerate 10
@@ -1,1 +0,0 @@-[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/enumerate 0
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/even 3
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/even 0
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) 1
@@ -1,1 +0,0 @@-125
@@ -1,1 +0,0 @@-λ(zero : Natural) → ../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) zero
@@ -1,1 +0,0 @@-λ(zero : Natural) → 5 * (5 * (5 * zero))
@@ -1,4 +0,0 @@- λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ ../../../../../../Prelude/Natural/fold 3 natural succ zero
@@ -1,4 +0,0 @@- λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ succ (succ (succ zero))
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/isZero 2
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/isZero 0
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/odd 3
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/odd 0
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/product [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-30
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/product ([] : List Natural)
@@ -1,1 +0,0 @@-1
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/show 3
@@ -1,1 +0,0 @@-"3"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/show 0
@@ -1,1 +0,0 @@-"0"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/sum [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-10
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/sum ([] : List Natural)
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toDouble 3
@@ -1,1 +0,0 @@-3.0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toDouble 0
@@ -1,1 +0,0 @@-0.0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toInteger 3
@@ -1,1 +0,0 @@-+3
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toInteger 0
@@ -1,1 +0,0 @@-+0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/all Natural Natural/even (Some 3)
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/all Natural Natural/even (None Natural)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/any Natural Natural/even (Some 2)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/any Natural Natural/even (None Natural)
@@ -1,1 +0,0 @@-False
@@ -1,7 +0,0 @@-../../../../../../Prelude/Optional/build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ some 1-)
@@ -1,1 +0,0 @@-Some 1
@@ -1,7 +0,0 @@-../../../../../../Prelude/Optional/build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ none-)
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (Some (Some 1))
@@ -1,1 +0,0 @@-Some 1
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (Some (None Natural))
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (None (Optional Natural))
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/filter Natural Natural/even (Some 2)
@@ -1,1 +0,0 @@-Some 2
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/filter Natural Natural/odd (Some 2)
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/fold Natural (Some 2) Natural (λ(x : Natural) → x) 0
@@ -1,1 +0,0 @@-2
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/fold Natural (None Natural) Natural (λ(x : Natural) → x) 0
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural [ None Natural, Some 1, Some 2 ]
@@ -1,1 +0,0 @@-Some 1
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural [ None Natural, None Natural ]
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural ([] : List (Optional Natural))
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural [ None Natural, Some 1, Some 2 ]
@@ -1,1 +0,0 @@-Some 2
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural [ None Natural, None Natural ]
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural ([] : List (Optional Natural))
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/length Natural (Some 2)
@@ -1,1 +0,0 @@-1
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/length Natural (None Natural)
@@ -1,1 +0,0 @@-0
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/map Natural Bool Natural/even (Some 3)
@@ -1,1 +0,0 @@-Some False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/map Natural Bool Natural/even (None Natural)
@@ -1,1 +0,0 @@-None Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/null Natural (Some 2)
@@ -1,1 +0,0 @@-False
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/null Natural (None Natural)
@@ -1,1 +0,0 @@-True
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/toList Natural (Some 1)
@@ -1,1 +0,0 @@-[ 1 ]
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/toList Natural (None Natural)
@@ -1,1 +0,0 @@-[] : List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/unzip Text Bool (Some { _1 = "ABC", _2 = True })
@@ -1,1 +0,0 @@-{ _1 = Some "ABC", _2 = Some True }
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/unzip Text Bool (None { _1 : Text, _2 : Bool })
@@ -1,1 +0,0 @@-{ _1 = None Text, _2 = None Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concat [ "ABC", "DEF", "GHI" ]
@@ -1,1 +0,0 @@-"ABCDEFGHI"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concat ([] : List Text)
@@ -1,1 +0,0 @@-""
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-"0 1 2 "
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
@@ -1,1 +0,0 @@-""
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-"0, 1, 2"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show ([] : List Natural)
@@ -1,1 +0,0 @@-""
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatSep ", " [ "ABC", "DEF", "GHI" ]
@@ -1,1 +0,0 @@-"ABC, DEF, GHI"
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatSep ", " ([] : List Text)
@@ -1,1 +0,0 @@-""
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/show "ABC"
@@ -1,1 +0,0 @@-"\"ABC\""
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/show "\u0000 \$ \\ \n \u263a"
@@ -1,1 +0,0 @@-"\"\\u0000 \\u0024 \\\\ \\n ☺\""
@@ -0,0 +1,1 @@+\(foo: { x: Bool, y: Bool }) -> \(bar: { x: Bool }) -> (foo.{x, y} // bar).{ x }
@@ -0,0 +1,3 @@+λ(foo : { x : Bool, y : Bool }) →+λ(bar : { x : Bool }) →+ (foo.{ x, y } ⫽ bar).{ x }
@@ -0,0 +1,2 @@+{- Checks that builtins don't accidentally discard further arguments than their arity -}+Natural/fold 0 (Bool -> Bool) (λ(_ : (Bool -> Bool)) → λ(_ : Bool) → True) (λ(_ : Bool) → False) True
@@ -0,0 +1,1 @@+False
@@ -0,0 +1,1 @@+toMap { `if` = 0, `foo%bar` = 1 }
@@ -0,0 +1,1 @@+[ { mapKey = "foo%bar", mapValue = 1 }, { mapKey = "if", mapValue = 0 } ]
@@ -0,0 +1,1 @@+let T = Natural let ap = λ(f : T → List T) -> λ(x : T) -> f x in ap (λ(x : T) -> ap (λ(y : T) -> [x, y]) 1) 0
@@ -0,0 +1,1 @@+[ 0, 1 ]
@@ -0,0 +1,16 @@+{- The Haskell implementation was incorrectly normalizing partially+ saturated `Natural/fold` and `List/fold` built-ins even though the standard+ requires built-ins to be fully saturated before normalization.++ For example, the Haskell implementation was normalizing `Natural/fold 0` to:++ λ(natural : Type)+ → λ(succ : natural → natural)+ → λ(zero : natural)+ → zero++ ... when the correct result should have been `Natural/fold 0` (no change)+-}+{ example0 = Natural/fold 0+, example1 = List/fold Bool [ True ]+}
@@ -0,0 +1,3 @@+{ example0 = Natural/fold 0+, example1 = List/fold Bool [ True ]+}
@@ -1,6 +1,6 @@-let Text/concatMap = ../../../Prelude/Text/concatMap+let Text/concatMap = ../../../Prelude/Text/concatMap.dhall -let Text/concatSep = ../../../Prelude/Text/concatSep+let Text/concatSep = ../../../Prelude/Text/concatSep.dhall let Row = { cores :@@ -26,12 +26,11 @@ : Row ) → let host =- Optional/fold- Text- row.user- Text- (λ(user : Text) → "${user}@${row.host}")- row.host+ merge+ { None = row.host+ , Some = λ(user : Text) → "${user}@${row.host}"+ }+ row.user let platforms = Text/concatSep "," row.platforms
@@ -59,12 +59,9 @@ ) → λ(y : Text) → ''- ${Optional/fold- Text- x.user- Text- (λ(user : Text) → "${user}@${x.host}")- x.host} ${merge+ ${merge+ { None = x.host, Some = λ(user : Text) → "${user}@${x.host}" }+ x.user} ${merge { Empty = "", NonEmpty = λ(result : Text) → result } ( List/fold Text
@@ -0,0 +1,10 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { name = "", id = None Natural }+ }++in { example0 = Example::{=}+ , example1 = Example::{ name = "John Doe" }+ , example2 = Example::{ id = Some 0 }+ , example3 = Example::{ name = "Mary Jane", id = Some 0 }+ }
@@ -0,0 +1,5 @@+{ example0 = { id = None Natural, name = "" }+, example1 = { id = None Natural, name = "John Doe" }+, example2 = { id = Some 0, name = "" }+, example3 = { id = Some 0, name = "Mary Jane" }+}
@@ -0,0 +1,1 @@+λ(x : Bool) → x == False
@@ -0,0 +1,1 @@+λ(x : Bool) → x == False
@@ -0,0 +1,1 @@+λ(x : Bool) → x != True
@@ -0,0 +1,1 @@+λ(x : Bool) → x != True
@@ -1,32 +0,0 @@-{ example0 =- Optional/build- Natural- ( λ(optional : Type)- → λ(just : Natural → optional)- → λ(nothing : optional)- → just 1- )-, example1 =- Optional/build- Integer- (λ(optional : Type) → λ(x : Integer → optional) → λ(x : optional) → x@1 +1)-, example2 =- λ(id : ∀(a : Type) → a → a)- → Optional/build- Bool- ( λ(optional : Type)- → λ(just : Bool → optional)- → λ(nothing : optional)- → id optional (just True)- )-, example3 =- λ(a : Type)- → λ(x : a)- → Optional/build- a- ( λ(optional : Type)- → λ(just : a → optional)- → λ(nothing : optional)- → just x- )-}
@@ -1,9 +0,0 @@-{ example0 =- Some 1-, example1 =- Some +1-, example2 =- λ(id : ∀(a : Type) → a → a) → id (Optional Bool) (Some True)-, example3 =- λ(a : Type) → λ(x : a) → Some x-}
@@ -1,1 +0,0 @@-Optional/build Text (Optional/fold Text (Some "foo"))
@@ -1,1 +0,0 @@-Some "foo"
@@ -1,7 +0,0 @@- let f =- λ(o : Optional Text)- → Optional/fold Text o Natural (λ(j : Text) → 1) 2--in { example0 = f (Some "foo")- , example1 = f (None Text)- }
@@ -1,1 +0,0 @@-{ example0 = 1, example1 = 2 }
@@ -0,0 +1,1 @@+λ(x : Natural) → x + 1
@@ -0,0 +1,1 @@+λ(x : Natural) → x + 1
@@ -0,0 +1,1 @@+λ(x : Natural) → x * 2
@@ -0,0 +1,1 @@+λ(x : Natural) → x * 2
@@ -0,0 +1,17 @@+let T1 = { a : Natural }+let T2 = { a : Natural, b : Text }+let T3 = { z : List { a : Natural, b : Text } }+let T4 = { z : List { b : Text, c : List Natural } }++let Prelude/List/map = ../../../../Prelude/List/map++let f = λ(old : T1) → old ⫽ { b = "Hello" }+let g = λ(old : T2) → { z = [ old, old.{ a } ⫽ { b = "Bye" } ] : List T2 }+let h_ = λ(old : T2) → old.{ b } ⫽ { c = [ old.a ] : List Natural }+let h =+ λ(old : T3)+ → { z = Prelude/List/map T2 { b : Text, c : List Natural } h_ old.z }++let k = λ(old : T1) → h (g (f old))++in k
@@ -0,0 +1,2 @@+ λ(old : { a : Natural })+→ { z = [ { b = "Hello", c = [ old.a ] }, { b = "Bye", c = [ old.a ] } ] }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).{ a, c }.c
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool }) → 0
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool }) → (x ⫽ { c = 0 }).({ a : Bool, c : Natural }).a
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool }) → x.a
@@ -0,0 +1,1 @@+λ(x : { a : {} }) → (x ⫽ { b = 0 } ∧ { a = { c = 1 } }).b
@@ -0,0 +1,1 @@+λ(x : { a : {} }) → 0
@@ -0,0 +1,1 @@+assert : (1 + 1) === (1 + 1)
@@ -0,0 +1,1 @@+assert : 2 ≡ 2
@@ -1,1 +1,1 @@-"${x}"+λ(x : Text) → "${x}"
@@ -1,1 +1,1 @@-x+λ(x : Text) → x
@@ -0,0 +1,1 @@+Bytes
@@ -0,0 +1,1 @@+Bytes
@@ -0,0 +1,23 @@+[ 0x"00"+, 0x"01"+, 0x"02"+, 0x"03"+, 0x"04"+, 0x"05"+, 0x"06"+, 0x"07"+, 0x"08"+, 0x"09"+, 0x"0a"+, 0x"0b"+, 0x"0c"+, 0x"0d"+, 0x"0e"+, 0x"0f"+, 0x"0A"+, 0x"0B"+, 0x"0C"+, 0x"0D"+, 0x"0E"+, 0x"0F"+]
@@ -0,0 +1,23 @@+[ 0x"00"+, 0x"01"+, 0x"02"+, 0x"03"+, 0x"04"+, 0x"05"+, 0x"06"+, 0x"07"+, 0x"08"+, 0x"09"+, 0x"0a"+, 0x"0b"+, 0x"0c"+, 0x"0d"+, 0x"0e"+, 0x"0f"+, 0x"0A"+, 0x"0B"+, 0x"0C"+, 0x"0D"+, 0x"0E"+, 0x"0F"+]
@@ -0,0 +1,1 @@+{ default = {=}, Type = {} }::{=}
@@ -0,0 +1,1 @@+{=}
@@ -0,0 +1,1 @@+toMap {=} : List {mapKey : Text, mapValue : Natural}
@@ -0,0 +1,1 @@+[] : List { mapKey : Text, mapValue : Natural }
@@ -0,0 +1,1 @@+(1 + 1) === (1 + 2)
@@ -0,0 +1,1 @@+2 ≡ 3
@@ -1,1 +1,1 @@-(λ(_ : X) → λ(_ : X) → _@1) x y+(λ(_ : Bool) → λ(_ : Bool) → _@1) True False
@@ -1,1 +1,1 @@-x+True
@@ -1,1 +1,1 @@-(λ(x : X) → y) x+λ(y : Bool) → (λ(x : Bool) → y) True
@@ -1,1 +1,1 @@-y+λ(y : Bool) → y
@@ -1,1 +1,3 @@-(if True then a else b) (if True then y else z)+ λ(f : Bool → Natural)+→ λ(x : Bool)+→ (if True then f else f) (if True then x else x)
@@ -1,1 +1,1 @@-a y+λ(f : Bool → Natural) → λ(x : Bool) → f x
@@ -1,1 +1,1 @@-(λ(x : X) → x) y+(λ(x : Bool) → x) True
@@ -1,1 +1,1 @@-y+True
@@ -1,1 +1,1 @@-λ(_ : if True then X else Y) → if True then _ else y+let id = λ(X : Type) → X in λ(x : id Bool) → if True then x else x
@@ -1,1 +1,1 @@-λ(_ : X) → _+λ(x : Bool) → x
@@ -1,1 +1,1 @@-(if True then X else Y) → if True then A else B+let id = λ(X : Type) → X in id Bool → id Natural
@@ -1,1 +1,1 @@-X → A+Bool → Natural
@@ -1,1 +1,1 @@-if x then y else y+λ(x : Bool) → λ(y : Natural) → if x then y else y
@@ -1,1 +1,1 @@-y+λ(x : Bool) → λ(y : Natural) → y
@@ -1,1 +1,4 @@-if if True then x else y then if True then a else b else if True then c else d+ λ(b : Bool)+→ λ(x : Natural)+→ λ(y : Natural)+→ if if True then b else b then if True then x else x else if True then y else y
@@ -1,1 +1,1 @@-if x then a else c+λ(b : Bool) → λ(x : Natural) → λ(y : Natural) → if b then x else y
@@ -1,1 +1,1 @@-if x then True else False+λ(x : Bool) → if x then True else False
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -0,0 +1,1 @@+Integer/clamp
@@ -0,0 +1,1 @@+Integer/clamp
@@ -0,0 +1,1 @@+Integer/clamp -6
@@ -0,0 +1,1 @@+0
@@ -0,0 +1,1 @@+Integer/clamp +5
@@ -0,0 +1,1 @@+5
@@ -0,0 +1,1 @@+Integer/clamp +0
@@ -0,0 +1,1 @@+0
@@ -0,0 +1,1 @@+Integer/negate
@@ -0,0 +1,1 @@+Integer/negate
@@ -0,0 +1,1 @@+Integer/negate -7
@@ -0,0 +1,1 @@++7
@@ -0,0 +1,1 @@+Integer/negate +3
@@ -0,0 +1,1 @@+-3
@@ -0,0 +1,1 @@+Integer/negate +0
@@ -0,0 +1,1 @@++0
@@ -1,1 +1,1 @@-let x = y in x+λ(y : Bool) → let x = y in x
@@ -1,1 +1,1 @@-y+λ(y : Bool) → y
@@ -1,1 +1,1 @@-let x : A = y in x+λ(y : Bool) → let x : Bool = y in x
@@ -1,1 +1,1 @@-y+λ(y : Bool) → y
@@ -1,1 +1,1 @@-List/build A (List/fold A x)+λ(T : Type) → λ(x : List T) → List/build T (List/fold T x)
@@ -1,1 +1,8 @@-x+ λ(T : Type)+→ λ(x : List T)+→ List/fold+ T+ x+ (List T)+ (λ(a : T) → λ(`as` : List T) → [ a ] # `as`)+ ([] : List T)
@@ -1,1 +1,3 @@-List/build A0 (λ(list : Type) → λ(cons : A0 → list → list) → λ(nil : list) → x)+ λ(T : Type)+→ λ(f : ∀(list : Type) → (T → list → list) → list → list)+→ List/build T f
@@ -1,1 +1,3 @@-x+ λ(T : Type)+→ λ(f : ∀(list : Type) → (T → list → list) → list → list)+→ f (List T) (λ(a : T) → λ(`as` : List T) → [ a ] # `as`) ([] : List T)
@@ -1,1 +1,1 @@-List/fold A0 ([] : List A1) B g x+λ(T : Type) → λ(f : T → Bool → Bool) → List/fold T ([] : List T) Bool f True
@@ -1,1 +1,1 @@-x+λ(T : Type) → λ(f : T → Bool → Bool) → True
@@ -1,1 +1,1 @@-List/fold A0 [ x ] B (λ(x : A0) → λ(y : B) → x) z+λ(T : Type) → λ(f : T → Bool → Bool) → λ(x : T) → List/fold T [ x ] Bool f True
@@ -1,1 +1,1 @@-x+λ(T : Type) → λ(f : T → Bool → Bool) → λ(x : T) → f x True
@@ -1,1 +1,1 @@-List/head T ([] : List T)+λ(T : Type) → List/head T ([] : List T)
@@ -1,1 +1,1 @@-None T+λ(T : Type) → None T
@@ -1,1 +1,1 @@-List/indexed T ([] : List T)+λ(T : Type) → List/indexed T ([] : List T)
@@ -1,1 +1,1 @@-[] : List { index : Natural, value : T }+λ(T : Type) → [] : List { index : Natural, value : T }
@@ -1,1 +1,1 @@-List/last T ([] : List T)+λ(T : Type) → List/last T ([] : List T)
@@ -1,1 +1,1 @@-None T+λ(T : Type) → None T
@@ -1,1 +1,1 @@-List/length T ([] : List T)+λ(T : Type) → List/length T ([] : List T)
@@ -1,1 +1,1 @@-0+λ(T : Type) → 0
@@ -1,1 +1,1 @@-[ if True then x else y ]+λ(x : Bool) → [ if True then x else x ]
@@ -1,1 +1,1 @@-[ x ]+λ(x : Bool) → [ x ]
@@ -1,1 +1,1 @@-[] : List (if True then x else y)+[] : { x = List Bool }.x
@@ -1,1 +1,1 @@-[] : List x+[] : List Bool
@@ -1,1 +1,1 @@-List/reverse T ([] : List T)+λ(T : Type) → List/reverse T ([] : List T)
@@ -1,1 +1,1 @@-[] : List T+λ(T : Type) → [] : List T
@@ -1,1 +1,1 @@-merge { x = λ(_ : A) → _ } (< x : T >.x y)+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → merge { a = f } (< a : T >.a x)
@@ -1,1 +1,1 @@-y+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → f x
@@ -1,1 +1,1 @@-merge { x = a } < x >.x+λ(x : Bool) → merge { a = x } < a >.a
@@ -1,1 +1,1 @@-a+λ(x : Bool) → x
@@ -0,0 +1,1 @@+merge { None = False, Some = \(b : Bool) -> b } (None Bool)
@@ -0,0 +1,1 @@+False
@@ -1,1 +1,3 @@-merge (if True then x else y) (if True then z else b)+ λ(x : { a : Bool })+→ λ(y : < a >)+→ merge (if True then x else x) (if True then y else y)
@@ -1,1 +1,1 @@-merge x z+λ(x : { a : Bool }) → λ(y : < a >) → merge x y
@@ -0,0 +1,1 @@+merge { None = False, Some = \(b : Bool) -> b } (Some True)
@@ -0,0 +1,1 @@+True
@@ -1,1 +1,4 @@-merge { x = λ(_ : A) → _ } (< x : T >.x y) : A+ λ(T : Type)+→ λ(f : T → Bool)+→ λ(x : T)+→ merge { a = f } (< a : T >.a x) : Bool
@@ -1,1 +1,1 @@-y+λ(T : Type) → λ(f : T → Bool) → λ(x : T) → f x
@@ -1,1 +1,5 @@-merge (if True then x else y) (if True then z else b) : (if True then X else Y)+let id = λ(X : Type) → X++in λ(x : { a : Bool })+ → λ(y : < a >)+ → merge (if True then x else x) (if True then y else y) : id Bool
@@ -1,1 +1,1 @@-merge x z : X+λ(x : { a : Bool }) → λ(y : < a >) → merge x y : Bool
@@ -1,1 +1,1 @@-Natural/build (Natural/fold x)+λ(x : Natural) → Natural/build (Natural/fold x)
@@ -1,1 +1,1 @@-x+λ(x : Natural) → Natural/fold x Natural (λ(x : Natural) → x + 1) 0
@@ -1,2 +1,2 @@-Natural/build-(λ(natural : Type) → λ(succ : natural → natural) → λ(zero : natural) → x)+ λ(f : ∀(natural : Type) → (natural → natural) → natural → natural)+→ Natural/build f
@@ -1,1 +1,2 @@-x+ λ(f : ∀(natural : Type) → (natural → natural) → natural → natural)+→ f Natural (λ(x : Natural) → x + 1) 0
@@ -1,1 +1,1 @@-Natural/fold 1 Natural (λ(x : Natural) → 5) x+λ(x : Bool) → Natural/fold 1 Bool (λ(_ : Bool) → True) x
@@ -1,1 +1,1 @@-5+λ(x : Bool) → True
@@ -1,1 +1,1 @@-Natural/fold 0 B g x+λ(x : Bool) → Natural/fold 0 Bool (λ(_ : Bool) → True) x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -0,0 +1,1 @@+λ(x : Natural) → Natural/subtract x x
@@ -0,0 +1,1 @@+λ(x : Natural) → 0
@@ -0,0 +1,1 @@+λ(x : Natural) → Natural/subtract x 0
@@ -0,0 +1,1 @@+λ(x : Natural) → 0
@@ -0,0 +1,1 @@+Natural/subtract 3 10
@@ -0,0 +1,1 @@+7
@@ -0,0 +1,1 @@+Natural/subtract 3 2
@@ -0,0 +1,1 @@+0
@@ -0,0 +1,3 @@+ λ(x : Natural)+→ λ(y : Natural)+→ Natural/subtract (if True then x else y) (10 + 20)
@@ -0,0 +1,1 @@+λ(x : Natural) → λ(y : Natural) → Natural/subtract x 30
@@ -0,0 +1,1 @@+λ(x : Natural) → Natural/subtract 0 x
@@ -0,0 +1,1 @@+λ(x : Natural) → x
@@ -0,0 +1,1 @@+Natural/subtract 0
@@ -0,0 +1,1 @@+Natural/subtract 0
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }.{ a }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a }
@@ -0,0 +1,2 @@+ λ(x : { a : Bool, b : Bool, c : Bool })+→ x.({ a : Bool, b : Bool }).({ a : Bool })
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a }
@@ -1,1 +0,0 @@-[] : Optional Natural
@@ -1,1 +0,0 @@-None Natural
@@ -1,1 +1,1 @@-x && x+λ(x : Bool) → x && x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-False && x+λ(x : Bool) → False && x
@@ -1,1 +1,1 @@-False+λ(x : Bool) → False
@@ -1,1 +1,1 @@-True && x+λ(x : Bool) → True && x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-True && x && (True && y)+λ(x : Bool) → λ(y : Bool) → True && x && (True && y)
@@ -1,1 +1,1 @@-x && y+λ(x : Bool) → λ(y : Bool) → x && y
@@ -1,1 +1,1 @@-x && False+λ(x : Bool) → x && False
@@ -1,1 +1,1 @@-False+λ(x : Bool) → False
@@ -1,1 +1,1 @@-x && True+λ(x : Bool) → x && True
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-x == x+λ(x : Bool) → x == x
@@ -1,1 +1,1 @@-True+λ(x : Bool) → True
@@ -1,1 +1,1 @@-x == True+λ(x : Bool) → x == True
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-True == x == (True == y)+λ(x : Bool) → λ(y : Bool) → True == x == (True == y)
@@ -1,1 +1,1 @@-x == y+λ(x : Bool) → λ(y : Bool) → x == y
@@ -1,1 +1,1 @@-True == x+λ(x : Bool) → True == x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-x # ([] : List T)+λ(T : Type) → λ(x : List T) → x # ([] : List T)
@@ -1,1 +1,1 @@-x+λ(T : Type) → λ(x : List T) → x
@@ -1,1 +1,1 @@-[ x ] # [ y ]+λ(T : Type) → λ(x : T) → λ(y : T) → [ x ] # [ y ]
@@ -1,1 +1,1 @@-[ x, y ]+λ(T : Type) → λ(x : T) → λ(y : T) → [ x, y ]
@@ -1,1 +1,4 @@-([] : List T) # x # (([] : List T) # y)+ λ(T : Type)+→ λ(x : List T)+→ λ(y : List T)+→ ([] : List T) # x # (([] : List T) # y)
@@ -1,1 +1,1 @@-x # y+λ(T : Type) → λ(x : List T) → λ(y : List T) → x # y
@@ -1,1 +1,1 @@-([] : List T) # x+λ(T : Type) → λ(x : List T) → ([] : List T) # x
@@ -1,1 +1,1 @@-x+λ(T : Type) → λ(x : List T) → x
@@ -1,1 +1,1 @@-x != x+λ(x : Bool) → x != x
@@ -1,1 +1,1 @@-False+λ(x : Bool) → False
@@ -1,1 +1,1 @@-False != x+λ(x : Bool) → False != x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-False != x != (False != y)+λ(x : Bool) → λ(y : Bool) → False != x != (False != y)
@@ -1,1 +1,1 @@-x != y+λ(x : Bool) → λ(y : Bool) → x != y
@@ -1,1 +1,1 @@-x != False+λ(x : Bool) → x != False
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-x || x+λ(x : Bool) → x || x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-False || x+λ(x : Bool) → False || x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-True || x+λ(x : Bool) → True || x
@@ -1,1 +1,1 @@-True+λ(x : Bool) → True
@@ -1,1 +1,1 @@-False || x || (False || y)+λ(x : Bool) → λ(y : Bool) → False || x || (False || y)
@@ -1,1 +1,1 @@-x || y+λ(x : Bool) → λ(y : Bool) → x || y
@@ -1,1 +1,1 @@-x || False+λ(x : Bool) → x || False
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-x || True+λ(x : Bool) → x || True
@@ -1,1 +1,1 @@-True+λ(x : Bool) → True
@@ -1,1 +1,1 @@-0 + x+λ(x : Natural) → 0 + x
@@ -1,1 +1,1 @@-x+λ(x : Natural) → x
@@ -1,1 +1,1 @@-0 + x + (0 + y)+λ(x : Natural) → λ(y : Natural) → 0 + x + (0 + y)
@@ -1,1 +1,1 @@-x + y+λ(x : Natural) → λ(y : Natural) → x + y
@@ -1,1 +1,1 @@-x + 0+λ(x : Natural) → x + 0
@@ -1,1 +1,1 @@-x+λ(x : Natural) → x
@@ -1,1 +1,1 @@-"" ++ x+λ(x : Text) → "" ++ x
@@ -1,5 +1,1 @@-{- The expected result is not `"${x}"`, because the standard requires that any- expression of the form `"${x}"` be simplified further to the equivalent- expression `x`--}-x+λ(x : Text) → x
@@ -1,1 +1,1 @@-"hai" ++ x+λ(x : Text) → "hai" ++ x
@@ -1,1 +1,1 @@-"hai${x}"+λ(x : Text) → "hai${x}"
@@ -1,1 +1,1 @@-x ++ ""+λ(x : Text) → x ++ ""
@@ -1,5 +1,1 @@-{- The expected result is not `"${x}"`, because the standard requires that any- expression of the form `"${x}"` be simplified further to the equivalent- expression `x`--}-x+λ(x : Text) → x
@@ -1,1 +1,1 @@-x ++ "hai"+λ(x : Text) → x ++ "hai"
@@ -1,1 +1,1 @@-"${x}hai"+λ(x : Text) → "${x}hai"
@@ -1,1 +1,1 @@-1 * x+λ(x : Natural) → 1 * x
@@ -1,1 +1,1 @@-x+λ(x : Natural) → x
@@ -1,1 +1,1 @@-0 * x+λ(x : Natural) → 0 * x
@@ -1,1 +1,1 @@-0+λ(x : Natural) → 0
@@ -1,1 +1,1 @@-1 * x * (1 * y)+λ(x : Natural) → λ(y : Natural) → 1 * x * (1 * y)
@@ -1,1 +1,1 @@-x * y+λ(x : Natural) → λ(y : Natural) → x * y
@@ -1,1 +1,1 @@-x * 1+λ(x : Natural) → x * 1
@@ -1,1 +1,1 @@-x+λ(x : Natural) → x
@@ -1,1 +1,1 @@-x * 0+λ(x : Natural) → x * 0
@@ -1,1 +1,1 @@-0+λ(x : Natural) → 0
@@ -1,1 +0,0 @@-Optional/build
@@ -1,1 +0,0 @@-Optional/build
@@ -1,1 +0,0 @@-Optional/build A0 (Optional/fold A1 x)
@@ -1,1 +0,0 @@-x
@@ -1,3 +0,0 @@-Optional/build-A-(λ(optional : Type) → λ(just : A → optional) → λ(nothing : optional) → x)
@@ -1,1 +0,0 @@-x
@@ -1,1 +0,0 @@-Optional/fold
@@ -1,1 +0,0 @@-Optional/fold
@@ -1,1 +0,0 @@-Optional/fold A (None A) B (λ(_ : A) → _) x
@@ -1,1 +0,0 @@-x
@@ -1,1 +0,0 @@-Optional/fold A (Some x) B (λ(_ : A) → _) z
@@ -1,1 +0,0 @@-x
@@ -1,1 +1,1 @@-{ a : if True then y else z, b : x }+λ(x : Bool) → { a = if True then x else x, b = x }
@@ -1,1 +1,1 @@-{ a : y, b : x }+λ(x : Bool) → { a = x, b = x }
@@ -0,0 +1,1 @@+let x = { y = 1 } in { x, x.z = 2 }
@@ -0,0 +1,1 @@+{ x = { y = 1, z = 2 } }
@@ -0,0 +1,1 @@+{ x.y.z = True }
@@ -0,0 +1,1 @@+{ x = { y = { z = True } } }
@@ -0,0 +1,9 @@+{- This expression desugars to:++ { x = { y = 0 } ∧ { z = 0 } }++ ... which then β-normalizes to:++ { x = { y = 0, z = 0 } }+-}+{ x = { y = 0 }, x = { z = 0 } }
@@ -0,0 +1,1 @@+{ x = { y = 0, z = 0 } }
@@ -0,0 +1,4 @@+{- The purpose of this test is to verify that the Nix-like idiom of setting+ multiple overlapping dotted fields works correctly+-}+{ x.y = 1, x.z = True }
@@ -0,0 +1,1 @@+{ x = { y = 1, z = True } }
@@ -0,0 +1,1 @@+let x = 0 in { x }
@@ -0,0 +1,1 @@+{ x = 0 }
@@ -0,0 +1,1 @@+let x = 0 let y = 1 in { x, y, z = 2 }
@@ -0,0 +1,1 @@+{ x = 0, y = 1, z = 2 }
@@ -0,0 +1,7 @@+{- This test ensures that an implementation handles more than one duplicate+ field correctly and combines them with the correct order and associativity+-}+ λ(a : { x : Natural })+→ λ(b : { y : Natural })+→ λ(c : { z : Natural })+→ { k = a, k = b, k = c }
@@ -0,0 +1,4 @@+ λ(a : { x : Natural })+→ λ(b : { y : Natural })+→ λ(c : { z : Natural })+→ { k = a ∧ b ∧ c }
@@ -1,1 +1,1 @@-{ x = a, y = b, z = c }.{ x, z }+{ x = 1, y = 2, z = 3 }.{ x, z }
@@ -1,1 +1,1 @@-{ x = a, z = c }+{ x = 1, z = 3 }
@@ -0,0 +1,1 @@+{ a = 10, b = Some 10 }.({})
@@ -0,0 +1,1 @@+{=}
@@ -0,0 +1,1 @@+{ a = 10, b = Some 10, c = [ "text" ]}.({ a : Natural, b : Optional Natural })
@@ -0,0 +1,1 @@+{ a = 10, b = Some 10 }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.({ a : Bool, b : Bool })
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.({ a : Bool, b : Bool }).a
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.a
@@ -1,1 +1,1 @@-x.{}+λ(x : { a : Bool }) → x.{}
@@ -1,1 +1,1 @@-{=}+λ(x : { a : Bool }) → {=}
@@ -1,1 +1,1 @@-(if True then y else z).{ x, y }+λ(x : { a : Bool, b : Bool, c : Bool }) → (if True then x else x).{ a, b }
@@ -1,1 +1,1 @@-y.{ x, y }+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ c, a }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, c }
@@ -1,1 +0,0 @@-{ a = 10, b = Some 10 }.({})
@@ -1,1 +0,0 @@-{=}
@@ -1,1 +0,0 @@-{ a = 10, b = Some 10, c = [ "text" ]}.({ a : Natural, b : Optional Natural })
@@ -1,1 +0,0 @@-{ a = 10, b = Some 10 }
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, b }.a
@@ -0,0 +1,1 @@+λ(x : { a : Bool, b : Bool, c : Bool }) → x.a
@@ -1,1 +1,1 @@-{ x = v }.x+λ(x : Bool) → { a = x }.a
@@ -1,1 +1,1 @@-v+λ(x : Bool) → x
@@ -1,1 +1,1 @@-(if True then y else z).x+λ(x : { a : Bool }) → λ(y : { a : Bool }) → (if True then x else y).a
@@ -1,1 +1,1 @@-y.x+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x.a
@@ -0,0 +1,1 @@+{ b = 1, a = 0 }
@@ -0,0 +1,1 @@+{ a = 0, b = 1 }
@@ -1,1 +1,1 @@-{ a : if True then A else B, b : T }+let id = λ(X : Type) → X in λ(T : Type) → { a : id Bool, b : T }
@@ -1,1 +1,1 @@-{ a : A, b : T }+λ(T : Type) → { a : Bool, b : T }
@@ -0,0 +1,1 @@+{ b : Bool, a : Natural }
@@ -0,0 +1,1 @@+{ a : Natural, b : Bool }
@@ -1,1 +1,1 @@-{=} ∧ x+λ(x : { a : Bool }) → {=} ∧ x
@@ -1,1 +1,1 @@-x+λ(x : { a : Bool }) → x
@@ -1,1 +1,1 @@-{ x = { z = 1 } } ∧ { b = { y = 2 } }+{ x = { a = 1 } } ∧ { y = { b = 2 } }
@@ -1,1 +1,1 @@-{ b = { y = 2 }, x = { z = 1 } }+{ x = { a = 1 }, y = { b = 2 } }
@@ -1,1 +1,1 @@-x ∧ {=} ∧ ({=} ∧ b)+λ(x : { a : Bool }) → λ(y : { b : Bool }) → x ∧ {=} ∧ ({=} ∧ y)
@@ -1,1 +1,1 @@-x ∧ b+λ(x : { a : Bool }) → λ(y : { b : Bool }) → x ∧ y
@@ -1,1 +1,1 @@-x ∧ {=}+λ(x : { a : Bool }) → x ∧ {=}
@@ -1,1 +1,1 @@-x+λ(x : { a : Bool }) → x
@@ -0,0 +1,1 @@+λ(x : { c : Bool }) → (x ∧ { a = 0, b = 1 }).a
@@ -0,0 +1,1 @@+λ(x : { c : Bool }) → (x ∧ { a = 0 }).a
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → (x ∧ { a = 1 }).b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → x.b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → ({ a = 1 } ∧ x).b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → x.b
@@ -0,0 +1,1 @@+λ(x : { c : Bool }) → ({ a = 0, b = 1 } ∧ x).a
@@ -0,0 +1,1 @@+λ(x : { c : Bool }) → ({ a = 0 } ∧ x).a
@@ -1,1 +1,1 @@-{ x : { z : A } } ⩓ { x : { y : B } }+{ x : { z : Bool } } ⩓ { x : { y : Natural } }
@@ -1,1 +1,1 @@-{ x : { y : B, z : A } }+{ x : { y : Natural, z : Bool } }
@@ -0,0 +1,1 @@+{ a : { b : { x : Bool } } } ⩓ { a : { b : { y : Bool } } }
@@ -0,0 +1,1 @@+{ a : { b : { x : Bool, y : Bool } } }
@@ -1,1 +1,1 @@-{} ⩓ x+{} ⩓ { a : Bool }
@@ -1,1 +1,1 @@-x+{ a : Bool }
@@ -1,1 +1,1 @@-{ x : { z : A } } ⩓ { b : { y : B } }+{ x : { a : Bool } } ⩓ { y : { b : Natural } }
@@ -1,1 +1,1 @@-{ b : { y : B }, x : { z : A } }+{ x : { a : Bool }, y : { b : Natural } }
@@ -1,1 +1,1 @@-x ⩓ {} ⩓ ({} ⩓ b)+{ a : Bool } ⩓ {} ⩓ ({} ⩓ { b : Bool })
@@ -1,1 +1,1 @@-x ⩓ b+{ a : Bool, b : Bool }
@@ -1,1 +1,1 @@-x ⩓ {}+{ a : Bool } ⩓ {}
@@ -1,1 +1,1 @@-x+{ a : Bool }
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → x ⫽ x
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → x
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → (x ⫽ { a = 0 }).a
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → 0
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → (x ⫽ { a = 0 }).b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → x.b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → λ(y : Bool) → ({ a = y } ⫽ x).b
@@ -0,0 +1,1 @@+λ(x : { b : Bool }) → λ(y : Bool) → x.b
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → ({ a = 0, b = 1 } ⫽ x).a
@@ -0,0 +1,1 @@+λ(x : { a : Bool }) → ({ a = 0 } ⫽ x).a
@@ -1,1 +1,1 @@-{=} ⫽ x+λ(x : { a : Bool }) → {=} ⫽ x
@@ -1,1 +1,1 @@-x+λ(x : { a : Bool }) → x
@@ -1,1 +1,1 @@-x ⫽ {=} ⫽ (y ⫽ {=})+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x ⫽ {=} ⫽ (y ⫽ {=})
@@ -1,1 +1,1 @@-x ⫽ y+λ(x : { a : Bool }) → λ(y : { a : Bool }) → x ⫽ y
@@ -1,1 +1,1 @@-x ⫽ {=}+λ(x : { a : Bool }) → x ⫽ {=}
@@ -1,1 +1,1 @@-x+λ(x : { a : Bool }) → x
@@ -0,0 +1,1 @@+λ(x : { c : Natural }) → (x ⫽ { a = 1, b = 2 }).{ a, c }
@@ -0,0 +1,1 @@+λ(x : { c : Natural }) → x.{ c } ⫽ { a = 1 }
@@ -0,0 +1,1 @@+showConstructor <A>.A
@@ -0,0 +1,1 @@+"A"
@@ -0,0 +1,1 @@+showConstructor (< A : Bool>.A False)
@@ -0,0 +1,1 @@+"A"
@@ -1,1 +1,1 @@-Some (if True then x else y)+λ(x : Bool) → λ(y : Bool) → Some (if True then x else y)
@@ -1,1 +1,1 @@-Some x+λ(x : Bool) → λ(y : Bool) → Some x
@@ -1,1 +1,1 @@-"s${"b${x}"}"+λ(x : Text) → "s${"b${x}"}"
@@ -1,1 +1,1 @@-"sb${x}"+λ(x : Text) → "sb${x}"
@@ -0,0 +1,1 @@+λ(x: Text) → "${""}${x}"
@@ -0,0 +1,1 @@+λ(x : Text) → x
@@ -0,0 +1,1 @@+λ(x: Text) → "${"${x}"}"
@@ -0,0 +1,1 @@+λ(x : Text) → x
@@ -0,0 +1,1 @@+λ(x: Text) → "${"${""}"}${x}"
@@ -0,0 +1,1 @@+λ(x : Text) → x
@@ -1,1 +1,1 @@-"s${if True then x else y}"+λ(x : Text) → λ(y : Text) → "s${if True then x else y}"
@@ -1,1 +1,1 @@-"s${x}"+λ(x : Text) → λ(y : Text) → "s${x}"
@@ -0,0 +1,3 @@+{- This test verifies that an implementation works with an abstract "replacement".+-}+λ(x : Text) → Text/replace "a" "-${x}-" "_a__a_"
@@ -0,0 +1,1 @@+λ(x : Text) → "_-${x}-__-${x}-_"
@@ -0,0 +1,4 @@+{- This test verifies that an implementation does not beta normalize with an+ abstract "haystack".+-}+λ(x : Text) → λ(y : Text) → Text/replace "a" "-${x}-" "_a_${y}_a_"
@@ -0,0 +1,1 @@+λ(x : Text) → λ(y : Text) → Text/replace "a" "-${x}-" "_a_${y}_a_"
@@ -0,0 +1,1 @@+Text/replace ""
@@ -0,0 +1,1 @@+Text/replace ""
@@ -0,0 +1,2 @@+λ(replacement : Text) →+ Text/replace "" replacement
@@ -0,0 +1,2 @@+λ(replacement : Text) →+ Text/replace "" replacement
@@ -0,0 +1,3 @@+λ(replacement : Text) →+λ(haystack : Text) →+ Text/replace "" replacement haystack
@@ -0,0 +1,1 @@+λ(replacement : Text) → λ(haystack : Text) → haystack
@@ -0,0 +1,1 @@+Text/replace "foo" "bar" "foobazfoo"
@@ -0,0 +1,1 @@+"barbazbar"
@@ -0,0 +1,1 @@+Text/replace "👨" "👩" "👨👩👧👦"
@@ -0,0 +1,1 @@+"👩👩👧👦"
@@ -0,0 +1,3 @@+-- This test verifies that implementations do not perform Unicode normalization+-- before substitution.+Text/replace "a\u{0301}" "b" "\u{00e1}c"
@@ -0,0 +1,1 @@+"ác"
@@ -0,0 +1,1 @@+Text/replace "aa" "b" "aaaaa"
@@ -0,0 +1,1 @@+"bba"
@@ -0,0 +1,1 @@+Text/replace "foo" "bar" "foo"
@@ -0,0 +1,1 @@+"bar"
@@ -0,0 +1,1 @@+Text/replace "💣" "💥" "💣💣💣"
@@ -0,0 +1,1 @@+"💥💥💥"
@@ -0,0 +1,3 @@+{- This test verifies that an implementation works with a variable as "replacement".+-}+λ(x : Text) → Text/replace "a" x "aaa"
@@ -0,0 +1,1 @@+λ(x : Text) → "${x}${x}${x}"
@@ -0,0 +1,1 @@+Text/show ""
@@ -0,0 +1,1 @@+"\"\""
@@ -1,1 +1,1 @@-Text/show "text ${with} interpolation"+λ(containing : Text) → Text/show "text ${containing} interpolation"
@@ -1,1 +1,1 @@-Text/show "text ${with} interpolation"+λ(containing: Text) → Text/show "text ${containing} interpolation"
@@ -0,0 +1,2 @@+-- Timestamps are records, and this is a no-op+2000-01-01T12:00:00+08:00.{ time, date, timeZone }
@@ -0,0 +1,1 @@+2000-01-01T12:00:00+08:00
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4, baz= 9 }
@@ -0,0 +1,4 @@+[ { mapKey = "bar", mapValue = 4 }+, { mapKey = "baz", mapValue = 9 }+, { mapKey = "foo", mapValue = 1 }+]
@@ -0,0 +1,16 @@+{- This test verifies that the normalized result does not contain a type+ annotation if the input record is non-empty.++ The reason for this test is that implementations might need to store+ optional type annotations for both `toMap` invocations and empty list+ literals. If an implementation does so, a common mistake is to take+ the optional type annotation and always pass it through as the optional+ type annotation for the list literal that `toMap` generates.++ However, the standard specifies that `toMap` should only generate a+ type annotation if the input record is empty. If the input record is+ non-empty then the resulting normalized list is non-empty and therefore+ should not have a type annotation (since a non-empty list with a type+ annotation is not in normal form).+-}+toMap { foo= 1, bar= 4, baz= 9 } : List { mapKey : Text, mapValue : Natural }
@@ -0,0 +1,4 @@+[ { mapKey = "bar", mapValue = 4 }+, { mapKey = "baz", mapValue = 9 }+, { mapKey = "foo", mapValue = 1 }+]
@@ -1,1 +1,1 @@-x : A+λ(x : Bool) → x : Bool
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +0,0 @@-< x = y | y : if True then X else Y | z >
@@ -1,1 +0,0 @@-< x = y | y : X | z >
@@ -1,1 +0,0 @@-< x = if True then y else z >
@@ -1,1 +0,0 @@-< x = y >
@@ -1,1 +0,0 @@-< x = y | z | y : B >
@@ -1,1 +0,0 @@-< x = y | y : B | z >
@@ -1,1 +1,1 @@-< x : T >.x+< x : Bool >.x
@@ -1,1 +1,1 @@-< x : T >.x+< x : Bool >.x
@@ -1,1 +1,1 @@-< x : B | z >+< x : Bool | z >
@@ -1,1 +1,1 @@-< x : B | z >+< x : Bool | z >
@@ -1,1 +1,1 @@-< x : if True then B else Z | z >+let id = λ(X : Type) → X in < x : id Bool | z >
@@ -1,1 +1,1 @@-< x : B | z >+< x : Bool | z >
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -1,1 +1,1 @@-x+λ(x : Bool) → x
@@ -0,0 +1,1 @@+{ a = 1 } with b = 2
@@ -0,0 +1,1 @@+{ a = 1, b = 2 }
@@ -0,0 +1,4 @@+{- This test verifies that an implementation correctly handles chained+ `with` expressions+-}+{ a = 1 } with b = 2 with c = 3
@@ -0,0 +1,1 @@+{ a = 1, b = 2, c = 3 }
@@ -0,0 +1,3 @@+{- This test illustrates that if an intermediate record does+ not exist, the `with` operator can create one -}+{ a = 5 } with b.c = 10
@@ -0,0 +1,1 @@+{ a = 5, b.c = 10 }
@@ -0,0 +1,3 @@+{- This test verifies that an implementation no longer implements the old desugaring (pre-v19.0.0)+-}+\(x: { a : { b : { c : {} } }}) -> x with a.b.c = 42
@@ -0,0 +1,1 @@+λ(x : { a : { b : { c : {} } } }) → x with a.b.c = 42
@@ -0,0 +1,12 @@+{- This test verifies that an implementation handles `with` expressions that+ update nested labels correctly++ A common mistake an implementation might make is to produce the following+ result:++ { a.c = 2 }++ ... due to the nested update clobbering the inner record. A compliant+ implementation extends inner records.+-}+{ a.b = 1 } with a.c = 2
@@ -0,0 +1,1 @@+{ a = { b = 1, c = 2 } }
@@ -0,0 +1,1 @@+(None Natural) with ? = 1
@@ -0,0 +1,1 @@+None Natural
@@ -0,0 +1,1 @@+(Some 0) with ? = 1
@@ -0,0 +1,1 @@+Some 1
@@ -0,0 +1,1 @@+(Some { x = Some { y = Some { z = Some 0 } } }) with ?.x.?.y.?.z.? = 1
@@ -0,0 +1,1 @@+Some { x = Some { y = Some { z = Some 1 } } }
@@ -0,0 +1,1 @@+{ x = Some 0 } with x.? = 1
@@ -0,0 +1,1 @@+{ x = Some 1 }
@@ -0,0 +1,4 @@+{- This test verifies that an implementation will evaluate a+partially abstract `with` expression correctly+-}+λ(x : { b : { c : {} } }) → { a = x } with a.b.c = 42
@@ -0,0 +1,1 @@+λ(x : { b : { c : {} } }) → { a = x with b.c = 42 }
@@ -0,0 +1,6 @@+{- This test ensures that updates are ordered and latter updates take priority+ when the same field is updated more than one time++ In this example, the `a` field is updated twice, and the latter update wins+-}+{ a = 1 } with a = 2 with a = 3
@@ -0,0 +1,1 @@+{ a = 3 }
@@ -0,0 +1,1 @@+(https://example.com/foo using ./headers) sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,1 @@+r.{ x: T }
@@ -0,0 +1,1 @@+let assert = 2 in 1
@@ -1,6 +1,6 @@ {- Builtin names are disallowed in bound variables.- The grammar doesn't explicitely disallow this, but the implementation should+ The grammar doesn't explicitly disallow this, but the implementation should refuse it. See the comments above the `nonreserved-label` rule. -} let Bool : Natural = 1 in Bool
@@ -0,0 +1,1 @@+0x"invalid"
@@ -0,0 +1,1 @@+0x"0"
@@ -1,2 +0,0 @@--- There needs to be a space between a function and its argument-./example.dhall[1]
@@ -0,0 +1,1 @@+./foo sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe1g
@@ -0,0 +1,1 @@+"\u{10FFFF}"
@@ -0,0 +1,6 @@+{-+The parser should reject unicode escape sequences for non-characters+(0xNFFFE-0xNFFFF for each `N` in `{ 0 .. F }), regardless of whether they are+braced or not.+-}+"\uFFFE"
@@ -0,0 +1,4 @@+{- This test verifies that an implementation correctly rejects non-UTF8+ characters, such as this one: "í "+-}+1
@@ -0,0 +1,1 @@+x :T
@@ -0,0 +1,1 @@+f(x)
@@ -0,0 +1,2 @@+-- There needs to be a space between a function and its argument+./example.dhall[1]
@@ -0,0 +1,1 @@+assert :T
@@ -0,0 +1,1 @@+forall(x :T) -> x
@@ -0,0 +1,1 @@+https://example.com/foo using(x)
@@ -0,0 +1,1 @@+if(b) then x else y
@@ -0,0 +1,1 @@+if b then(x) else y
@@ -0,0 +1,1 @@+if b then x else(y)
@@ -0,0 +1,1 @@+x ?y
@@ -0,0 +1,1 @@+missingsha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,1 @@+\(x :T) -> x
@@ -0,0 +1,1 @@+let x :T = y in e
@@ -0,0 +1,1 @@+letx = y in e
@@ -0,0 +1,1 @@+let x = y in(e)
@@ -0,0 +1,1 @@+let x = NaNin x
@@ -0,0 +1,1 @@+let x = 3let y = x in y
@@ -0,0 +1,1 @@+[] :T
@@ -0,0 +1,1 @@+merge x y :T
@@ -0,0 +1,1 @@+merge(x) y
@@ -0,0 +1,1 @@+merge x(y)
@@ -0,0 +1,1 @@+x +y
@@ -0,0 +1,1 @@+{ x :T }
@@ -0,0 +1,1 @@+Some(x)
@@ -0,0 +1,1 @@+toMap x :T
@@ -0,0 +1,1 @@+toMap(x)
@@ -0,0 +1,1 @@+< x :T >
@@ -0,0 +1,5 @@+{-+The parser should reject unicode escape sequences for surrogate pairs+(0xD800-DFFF), regardless of whether they are braced or not.+-}+"\uD800"
@@ -0,0 +1,2 @@+-- A date and time zone is not valid (because the time is missing)+2011-04-01+02:00
@@ -0,0 +1,2 @@+-- April only has 30 days+2000-04-31
@@ -0,0 +1,2 @@+-- Hours must range between 0-23+24:00:00
@@ -0,0 +1,3 @@+-- Leap seconds are not permitted by the Dhall standard, even though RFC 3339+-- supports them+2016-12-31T23:59:60
@@ -0,0 +1,2 @@+-- Minutes must range between 0-59+00:60:00
@@ -0,0 +1,2 @@+-- Months must be between 1-12+2000-13-01
@@ -0,0 +1,2 @@+-- Seconds must range between 0-59 (and leap seconds are not supported)+00:00:60
@@ -0,0 +1,2 @@+-- Negative years are not permitted+-0001-01-01
@@ -0,0 +1,2 @@+-- Only 4-digit years are permitted+10000-01-01
@@ -0,0 +1,1 @@+assert
@@ -0,0 +1,1 @@+True@0
@@ -0,0 +1,1 @@+Bool@1
@@ -0,0 +1,1 @@+Type@0
@@ -0,0 +1,1 @@+env:"\$"
@@ -0,0 +1,1 @@+([]) : List T
@@ -0,0 +1,1 @@+[]
@@ -0,0 +1,1 @@+[ ,, ]
@@ -0,0 +1,1 @@+merge
@@ -0,0 +1,1 @@+merge x
@@ -0,0 +1,1 @@+042
@@ -0,0 +1,1 @@+< x = 3 | y : Bool >
@@ -0,0 +1,1 @@+foo.{ ,, }
@@ -0,0 +1,1 @@+{ if: Text }
@@ -0,0 +1,1 @@+{ then: Text }
@@ -0,0 +1,1 @@+{ else: Text }
@@ -0,0 +1,1 @@+{ let: Text }
@@ -0,0 +1,1 @@+{ in: Text }
@@ -0,0 +1,1 @@+{ using: Text }
@@ -0,0 +1,1 @@+{ missing: Text }
@@ -0,0 +1,1 @@+{ assert: Text }
@@ -0,0 +1,1 @@+{ as: Text }
@@ -0,0 +1,1 @@+{ Infinity: Text }
@@ -0,0 +1,1 @@+{ NaN: Text }
@@ -0,0 +1,1 @@+{ merge: Text }
@@ -0,0 +1,1 @@+{ toMap: Text }
@@ -0,0 +1,1 @@+{ with: Text }
@@ -0,0 +1,1 @@+{ forall: Text }
@@ -0,0 +1,1 @@+{ x.y.z }
@@ -0,0 +1,1 @@+{ ,, }
@@ -0,0 +1,1 @@+Some
@@ -0,0 +1,1 @@+< || >
@@ -0,0 +1,1 @@+https://example.com/"a%20b"/c
@@ -0,0 +1,8 @@+{- At one point the Haskell implementation permitted this idiom, which was not+ standards-compliant++ The problem with the following expression is that the argument to `using`+ is parsed as a `completionExpression`, which means that any use of `toMap`+ within a `using` clause must be parenthesized+-}+https://example.com using toMap { Foo = "Bar" }
@@ -0,0 +1,1 @@+{ x = 0 } // { y = 1 } with x = 1
@@ -0,0 +1,1 @@+foo { x = 0 } with x = 1
@@ -0,0 +1,1 @@+{ x = 0 } with x = 1 : T
@@ -0,0 +1,2 @@+-- For https://github.com/dhall-lang/dhall-haskell/issues/2212+{=}with foo = 0with bar = 1
@@ -0,0 +1,1 @@+showConstructor
@@ -1,2 +0,0 @@--- See issue #205 for why this is not permitted-http://example.com/
@@ -1,15 +0,0 @@-let example1 = λ(A : Type) → λ(B : Type) → λ(C : { x : A, y : B }) → C.({ x : A }) : { x : A }--let example2 =- λ(A : Type)- → λ(B : Type)- → λ(C : { p : A, q : B })- → C.(let r = { p : A } in r) : { p : A }--let A = Natural--let B = Text--in--(example1 A B { x = 10, y = "Text" }) ∧ (example2 A B { p = 10, q = "Text" }) : { x : A, p : A }
@@ -1,4 +1,1 @@-{ foo = ([] : List Natural) # [1, 2, 3] # ([1, 2, 3] : List Natural)-, bar = [] : Optional Natural-, baz = [1] : Optional Natural-} : { foo : List Natural, bar : Optional Natural, baz : Optional Natural }+([] : List Natural) # [ 1, 2, 3 ] # ([ 1, 2, 3 ] : List Natural) : List Natural
binary file changed (167 → 76 bytes)
@@ -0,0 +1,8 @@+ λ(x : Bool)+→ λ(x : Bool)+→ { example0 = 0b0+ , example1 = 0b10+ , example2 = -0b11001+ , example3 = +0b100+ , example4 = x@0b01+ }
binary file changed (absent → 83 bytes)
@@ -1,32 +1,40 @@- λ ( x- : { field0 : Bool- , field1 : Optional (Optional Bool)- , field2 : Natural- , field3 : Integer- , field4 : Double- , field5 : Text- , field6 : List (List Bool)- }- )-→ { field00 = Natural/fold- , field01 = Natural/build- , field02 = Natural/isZero- , field03 = Natural/even- , field04 = Natural/odd- , field05 = Natural/toInteger- , field06 = Natural/show- , field07 = Integer/show- , field08 = Double/show- , field09 = List/build- , field10 = List/fold- , field11 = List/length- , field12 = List/head- , field13 = List/last- , field14 = List/indexed- , field15 = List/reverse- , field16 = Optional/fold- , field17 = Optional/build- , field18 = True- , field19 = False- , field20 = None- }+[ Date/show+, Double/show+, Integer/clamp+, Integer/negate+, Integer/show+, Integer/toDouble+, List/build+, List/fold+, List/head+, List/indexed+, List/last+, List/length+, List/reverse+, Natural/build+, Natural/even+, Natural/fold+, Natural/isZero+, Natural/odd+, Natural/show+, Natural/subtract+, Natural/toInteger+, Text/replace+, Text/show+, Time/show+, TimeZone/show+, Bool+, Bytes+, Date+, Double+, False+, Integer+, List+, Natural+, None+, Optional+, Text+, Time+, TimeZone+, True+]
binary file changed (544 → 405 bytes)
@@ -0,0 +1,25 @@+[ 0x""+, 0x"00"+, 0x"01"+, 0x"02"+, 0x"03"+, 0x"04"+, 0x"05"+, 0x"06"+, 0x"07"+, 0x"08"+, 0x"09"+, 0x"0a"+, 0x"0b"+, 0x"0c"+, 0x"0d"+, 0x"0e"+, 0x"0f"+, 0x"0A"+, 0x"0B"+, 0x"0C"+, 0x"0D"+, 0x"0E"+, 0x"0F"+, 0x"000102030405060708090a0b0c0d0e0f0A0B0C0D0E0F"+]
binary file changed (absent → 144 bytes)
@@ -1,1 +0,0 @@-[ 1.1, -1.1, 1e1, 1.1e1, NaN, Infinity, -Infinity, 0.0 ]
binary file changed (43 → absent bytes)
@@ -0,0 +1,6 @@+ λ(x : Bool)+→ λ(x : Bool)+→ { example0 = 0xFF+ , example1 = -0x1A10+ , example2 = x@0x01+ }
@@ -0,0 +1,1 @@+axdBoolaxdBool£hexample0ÿhexample19hexample2ax
@@ -1,1 +0,0 @@-if True then 1 else 2
@@ -1,1 +0,0 @@-õ
@@ -97,12 +97,11 @@ } ) → λ(y : Text)- → Optional/fold- Text- x.user- Text- (λ(user : Text) → user ++ "@" ++ x.host ++ "")- x.host+ → merge+ { None = x.host+ , Some = λ(user : Text) → user ++ "@" ++ x.host ++ ""+ }+ x.user ++ " " ++ ( merge { Empty = "", NonEmpty = λ(result : Text) → result }
binary file changed (3518 → 3507 bytes)
@@ -0,0 +1,10 @@+{ emptyRecordLiteral = { , = }+, emptyRecordType = { , }+, emptyList = [,] : List Natural+, emptyUnionType = < | >++, recordLiteral = { , x = 1, y = True }+, recordType = { , x : Natural, y : Bool }+, list = [ , 1, 2 ]+, unionType = < | x : Natural | y : Bool >+}
@@ -0,0 +1,1 @@+¨iemptyListgNaturalremptyRecordLiteral oemptyRecordType nemptyUnionType dlistömrecordLiteral¢axayõjrecordType¢axgNaturalaydBooliunionType¢axgNaturalaydBool
@@ -1,3 +0,0 @@- let x = 1-in let y : Natural = 2-in x
binary file changed (29 → absent bytes)
@@ -0,0 +1,3 @@+-- foo + +1
@@ -0,0 +1,1 @@+
@@ -0,0 +1,3 @@+[+ 1, -- item one+{- foo -} 2, 3 ]
@@ -0,0 +1,1 @@+ ö
@@ -0,0 +1,1 @@+missingFoo
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+(missing)
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+missing/
binary file changed (absent → 11 bytes)
@@ -0,0 +1,6 @@+{- foo -}+-- bar+{- --baz -}+-- {- qux -}++1
@@ -0,0 +1,1 @@+
@@ -1,3 +0,0 @@-let a = 1-let b = 2-in a + b
binary file changed (26 → absent bytes)
@@ -1,1 +1,1 @@-[ 0, 1, 01, 10 ]+[ 0, 1, 10 ]
binary file changed (15 → 12 bytes)
@@ -0,0 +1,1 @@+missing//foo
binary file changed (absent → 15 bytes)
@@ -1,4 +1,5 @@ { example1 = let `let` = 1 in `let` , example2 = let `:.` = 1 in `:.` , example3 = let `$ref` = 1 in `$ref`+, example4 = let `` = 1 in `` }
binary file changed (81 → 101 bytes)
@@ -0,0 +1,1 @@+{foo = 1, `` = 2, ` ` = 3}
@@ -0,0 +1,1 @@+£`a cfoo
@@ -0,0 +1,1 @@+<foo: Natural|``: Natural|` `: Natural>
@@ -0,0 +1,1 @@+£`gNaturala gNaturalcfoogNatural
@@ -0,0 +1,15 @@+let example1 = λ(A : Type) → λ(B : Type) → λ(C : { x : A, y : B }) → C.({ x : A }) : { x : A }++let example2 =+ λ(A : Type)+ → λ(B : Type)+ → λ(C : { p : A, q : B })+ → C.(let r = { p : A } in r) : { p : A }++let A = Natural++let B = Text++in++(example1 A B { x = 10, y = "Text" }) ∧ (example2 A B { p = 10, q = "Text" }) : { x : A, p : A }
binary file changed (absent → 279 bytes)
@@ -0,0 +1,1 @@+"$"
@@ -0,0 +1,1 @@+a$
@@ -1,1 +1,1 @@-"\\\"\$\\\/\b\f\n\r\t \u2200(a : Type) \u2192 a"+"\\\"\$\\\/\b\f\n\r\t\u{1D11E} \u2200(a : Type) \u2192 a"
@@ -1,2 +1,2 @@-x\"$\/- â(a : Type) â a+x"\"$\/+ ð â(a : Type) â a
@@ -0,0 +1,8 @@+{- A comment within the interior of a multi-line literal counts as part of the+ literal+-}++''+-- Hello+{- world -}+''
@@ -0,0 +1,2 @@+u-- Hello+{- world -}
@@ -0,0 +1,1 @@+"\u{1FFF0}"
@@ -0,0 +1,1 @@+dð¿°
@@ -1,8 +1,1 @@-{- A comment within the interior of a multi-line literal counts as part of the- literal--}--''--- Hello-{- world -}-''+"-- $--$--{--}$"
@@ -1,2 +1,1 @@-u-- Hello-{- world -}+n-- $--$--{--}$
@@ -0,0 +1,5 @@+''+a''++++''+b''
@@ -0,0 +1,1 @@+aaab
@@ -0,0 +1,1 @@+"\u{1}\u{10}\u{100}\u{1000}\u{10000}\u{100000}"
@@ -0,0 +1,1 @@+oÄáðô
@@ -0,0 +1,1 @@+"A\u2115B\u{1FA00}C\u{43}D\u{00000001F574}E\u0022F"
@@ -0,0 +1,1 @@+sAâBð¨CCDð´E"F
@@ -0,0 +1,1 @@+"\u{10fffd}\u{1fffd}"
@@ -0,0 +1,1 @@+hô¿½ð¿½
@@ -0,0 +1,1 @@+1960-12-25T04:23:34
binary file changed (absent → 32 bytes)
@@ -0,0 +1,1 @@+2020-01-01T12:00:00-08:00
binary file changed (absent → 45 bytes)
@@ -0,0 +1,2 @@+-- Check that lowercase `t` is supported+2000-01-01t12:00:00
binary file changed (absent → 30 bytes)
@@ -0,0 +1,1 @@+00:00:00+00:00
binary file changed (absent → 32 bytes)
@@ -0,0 +1,5 @@+-- Same as `./TimeTimeZoneA.dhall`, but with `Z` as the `TimeZone`+--+-- This ensures that implementation still parse `Z` in conjunction with a time,+-- even if `Z` by itself is not permitted+00:00:00Z
binary file changed (absent → 32 bytes)
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4, baz= 9 }
@@ -0,0 +1,1 @@+£cbarcbaz cfoo
@@ -1,4 +0,0 @@-< A : { }-| B = { = }-| C : {}-> : < A : {} | B : {} | C : {} >
@@ -1,1 +0,0 @@-aB ¢aA aC £aA aB aC
@@ -0,0 +1,1 @@+x : T
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+assert : T
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+assert : x === y
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+assert : x ≡ y
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+assert : T U
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+List/Build
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+T :: r
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+Date
@@ -0,0 +1,1 @@+dDate
@@ -0,0 +1,1 @@+2020-01-01
@@ -0,0 +1,1 @@+ä
@@ -0,0 +1,1 @@+x == x@0
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+5.5
@@ -0,0 +1,1 @@+ùE
@@ -0,0 +1,1 @@+5555.5
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+55555555555.5
binary file changed (absent → 9 bytes)
@@ -0,0 +1,1 @@+1.23e4
binary file changed (absent → 5 bytes)
@@ -0,0 +1,1 @@+1.23e-4
@@ -0,0 +1,1 @@+û? 1ônÒF
@@ -0,0 +1,1 @@+1e4
@@ -0,0 +1,1 @@+ùpâ
@@ -0,0 +1,1 @@+Infinity
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+NaN
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+-Infinity
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+-0.0
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+-1.23
@@ -0,0 +1,1 @@+û¿ó®záG®
@@ -0,0 +1,1 @@+1.23
@@ -0,0 +1,1 @@+û?ó®záG®
@@ -0,0 +1,5 @@+{-+ Some languages do not make principled distinctions between number types, so+ this checks that this Double is not silently considered as a Natural+-}+1.0
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+0.0
binary file changed (absent → 3 bytes)
@@ -0,0 +1,1 @@+{=}
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+r.x
binary file changed (absent → 8 bytes)
@@ -0,0 +1,1 @@+r.List
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+r.`x`
binary file changed (absent → 8 bytes)
@@ -0,0 +1,1 @@+∀(x : T) -> y
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+f x y z
binary file changed (absent → 18 bytes)
@@ -0,0 +1,1 @@+f x
binary file changed (absent → 10 bytes)
@@ -0,0 +1,1 @@+T -> U
binary file changed (absent → 10 bytes)
@@ -0,0 +1,1 @@+forall(x: T) -> U
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+forall(x: T) -> ∀(y: U) -> V
binary file changed (absent → 20 bytes)
@@ -0,0 +1,1 @@+forall(_: T) -> U
binary file changed (absent → 10 bytes)
@@ -0,0 +1,1 @@+∀(x: T) -> U
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+λ(x : T) -> y
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+let x: T = v in e
@@ -0,0 +1,1 @@+let x: T = y in e
binary file changed (absent → 17 bytes)
binary file changed (absent → 17 bytes)
@@ -0,0 +1,1 @@+let x: T = v let y: U = w in e
binary file changed (absent → 27 bytes)
@@ -0,0 +1,1 @@+let x: T = v in let y: U = w in e
binary file changed (absent → 27 bytes)
@@ -0,0 +1,1 @@+let x = y in e
binary file changed (absent → 14 bytes)
@@ -0,0 +1,1 @@+[] : List T
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+[] : T
binary file changed (absent → 7 bytes)
@@ -1,1 +0,0 @@-[] : List T
binary file changed (6 → absent bytes)
@@ -0,0 +1,1 @@+[ , ] : List Bool
@@ -0,0 +1,1 @@+dBool
@@ -0,0 +1,1 @@+[] : List T U
binary file changed (absent → 18 bytes)
@@ -0,0 +1,1 @@+[ , x, y ]
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+[x, y]
@@ -0,0 +1,1 @@+[x, y] : List T
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+[ , x, y, ]
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+[ x, y, ]
binary file changed (absent → 11 bytes)
@@ -0,0 +1,11 @@+[ [+ 1,+ 2,+ 3,+ ]+, [+ , 1+ , 2+ , 3+ ]+]
@@ -0,0 +1,1 @@+ö ö ö
@@ -0,0 +1,1 @@+r.{x, y, z}
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+foo.{ , x, y }
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+foo.{ , x, y, }
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+foo.{ x, y, }
binary file changed (absent → 12 bytes)
@@ -0,0 +1,1 @@+{ x = 1, y = 2 }
@@ -0,0 +1,1 @@+¢axay
@@ -0,0 +1,7 @@+{- The purpose of this test is to illustrate that dotted fields are syntactic+ sugar that does not survive the parsing stage. The underlying expression is+ actually represented and encoded as:++ { x = { y = { z = 1 } } }+-}+{ x.y.z = 1 }
@@ -0,0 +1,1 @@+¡ax¡ay¡az
@@ -0,0 +1,1 @@+{ `x.y`.z = 1 }
@@ -0,0 +1,1 @@+¡cx.y¡az
@@ -0,0 +1,7 @@+{- The purpose of this test is to illustrate that duplicate fields are+ syntactic sugar that does not survive the parsing stage. The underlying+ expression is actually represented and encoded as:++ { x = { y = 1 } ∧ { z = 1 } }+-}+{ x = { y = 1 }, x = { z = 1 } }
@@ -0,0 +1,1 @@+¡ax¡ay¡az
@@ -0,0 +1,1 @@+{ , =, }
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+{ , = }
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+{ =, }
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+{ , x = 0, y = 1 }
binary file changed (absent → 13 bytes)
@@ -0,0 +1,5 @@+{- The purpose of this test is to verify that the combination of the dotted+ field notation and the duplicate record fields desugar to the desired syntax+ tree+-}+{ x.y = 1, x.z = True }
@@ -0,0 +1,1 @@+¡ax¡ay¡azõ
@@ -0,0 +1,1 @@+{ x, y, z }
binary file changed (absent → 21 bytes)
@@ -0,0 +1,1 @@+{ x, y, x }
binary file changed (absent → 22 bytes)
@@ -0,0 +1,1 @@+{ x, y = 1, z, w.a.b = 2 }
binary file changed (absent → 35 bytes)
@@ -0,0 +1,1 @@+{ Some }
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+{ Some = 0 }
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+{ , x = 0, y = 1, }
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+{ x = 0, y = 1, }
binary file changed (absent → 13 bytes)
@@ -0,0 +1,1 @@+{ a = 1, b = 2 }.({ a : Natural })
@@ -0,0 +1,2 @@++¢aaab¡aagNatural
@@ -0,0 +1,1 @@+{ a = 1, b = 2 }.({})
@@ -0,0 +1,2 @@++¢aaab
@@ -0,0 +1,1 @@+{ x: T, y: U }
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+{ , }
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+{ , x : T, y : U }
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+{ , x : T, y : U, }
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+{ x : T, y : U, }
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+record.{ Some }
binary file changed (absent → 16 bytes)
@@ -0,0 +1,2 @@+#!/usr/bin/env -S dhall text --file+"A"
@@ -0,0 +1,1 @@+aA
@@ -0,0 +1,3 @@+#! /usr/bin/env nix-shell+#! nix-shell -i "dhall --file" -p dhall+42
@@ -0,0 +1,1 @@+*
@@ -0,0 +1,1 @@+showConstructor <A>.A
@@ -0,0 +1,1 @@+" ¡aAöaA
@@ -0,0 +1,1 @@+showConstructor (<A : Bool>.A False)
binary file changed (absent → 20 bytes)
@@ -0,0 +1,1 @@+Time
@@ -0,0 +1,1 @@+dTime
@@ -0,0 +1,1 @@+12:00:00
binary file changed (absent → 9 bytes)
@@ -0,0 +1,1 @@+TimeZone
@@ -0,0 +1,1 @@+hTimeZone
@@ -0,0 +1,1 @@++08:00
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+toMap x
@@ -0,0 +1,1 @@+toMap x : T
binary file changed (absent → 11 bytes)
binary file changed (absent → 7 bytes)
@@ -0,0 +1,2 @@+-- This test verifies that a trailing line comment does not require a newline+1--
@@ -0,0 +1,1 @@+
@@ -1,1 +0,0 @@-< x = t | y: T | z | w: T >
binary file changed (24 → absent bytes)
@@ -1,1 +0,0 @@-< x: T | y = t | z | w: T >
binary file changed (24 → absent bytes)
@@ -0,0 +1,1 @@+< | >
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+< | x: T | y: U >
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+< Some: Natural >
@@ -0,0 +1,1 @@+¡dSomegNatural
@@ -0,0 +1,1 @@+< | x: T | y: U | >
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+< x: T | y: U | >
binary file changed (absent → 15 bytes)
@@ -0,0 +1,1 @@+` x `
binary file changed (absent → 6 bytes)
@@ -0,0 +1,1 @@+{ a = 1 } with a = 2
@@ -0,0 +1,1 @@+¡aaaa
@@ -0,0 +1,4 @@+{- This test verifies that an implementation correctly encodes chained+ `with` expressions in a left-associative way.+-}+{ a.b = 1, c.d = 2 } with a.b = 3 with c.e = 4
@@ -0,0 +1,1 @@+¢aa¡abac¡adaaabacae
@@ -0,0 +1,13 @@+{- The purpose of this test is to illustrate that function application has+ higher precedence than `with` so that chained with expressions parse+ correctly++ The following expression should parse as:++ ({ a = Some 1 } with a = Some 2) with a = Some 3++ ... and not parse as:++ { a = Some 1 } with a = (Some 2 with a = Some 3)+-}+{ a = Some 1 } with a = Some 2 with a = Some 3
@@ -0,0 +1,1 @@+¡aaöaaöaaö
@@ -0,0 +1,1 @@+{ x = 0 } with x = 1 + 1
binary file changed (absent → 23 bytes)
@@ -0,0 +1,1 @@+foo::{ x = 0 } with x = 1
binary file changed (absent → 26 bytes)
@@ -0,0 +1,1 @@+{ Some = 0 } with Some = 1
binary file changed (absent → 23 bytes)
@@ -0,0 +1,1 @@+if True then 1 else 2
@@ -0,0 +1,1 @@+õ
@@ -0,0 +1,1 @@+/absolute/import as Location
@@ -0,0 +1,1 @@+öhabsolutefimport
@@ -0,0 +1,1 @@+env:HOME as Location
@@ -0,0 +1,1 @@+ ödHOME
@@ -0,0 +1,1 @@+./some/import sha256:0000000000000000000000000000000000000000000000000000000000000000 as Location
binary file changed (absent → 53 bytes)
@@ -0,0 +1,1 @@+./local/import as Location
@@ -0,0 +1,1 @@+öelocalfimport
@@ -0,0 +1,1 @@+missing as Location
@@ -0,0 +1,1 @@+ö
@@ -0,0 +1,1 @@+https://prelude.dhall-lang.org/package.dhall as Location
@@ -0,0 +1,1 @@+öövprelude.dhall-lang.orgmpackage.dhallö
@@ -0,0 +1,1 @@+https://example.com/foo using x
binary file changed (absent → 27 bytes)
@@ -0,0 +1,1 @@+https://example.com/foo using (./headers sha256:0000000000000000000000000000000000000000000000000000000000000000) sha256:1111111111111111111111111111111111111111111111111111111111111111
binary file changed (absent → 107 bytes)
@@ -0,0 +1,1 @@+https://example.com/foo using ./headers sha256:0000000000000000000000000000000000000000000000000000000000000000 sha256:1111111111111111111111111111111111111111111111111111111111111111
binary file changed (absent → 107 bytes)
@@ -0,0 +1,1 @@+https://example.com/foo using ./headers sha256:0000000000000000000000000000000000000000000000000000000000000000
binary file changed (absent → 72 bytes)
@@ -0,0 +1,1 @@+https://example.com/foo using (./headers sha256:0000000000000000000000000000000000000000000000000000000000000000)
binary file changed (absent → 72 bytes)
@@ -0,0 +1,1 @@+./import asText
binary file changed (absent → 24 bytes)
@@ -0,0 +1,1 @@+missing
binary file changed (absent → 6 bytes)
@@ -1,2 +1,2 @@ -- Yes, this is legal-env:"\"\\\a\b\f\n\r\t\v"+env:"\"\\\a\b\f\n\r\t\v!<[~"
binary file changed (16 → 20 bytes)
@@ -8,7 +8,7 @@ -} https://example.com/foo using- [ { header = "Authorization"- , value = "token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4"+ [ { mapKey = "Authorization"+ , mapValue = "token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" } ]
binary file changed (108 → 111 bytes)
@@ -1,1 +0,0 @@-https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate using (./a.dhall sha256:16173e984d35ee3ffd8b6b79167df89480e67d1cd03ea5d0fc93689e4d928e61) sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
binary file changed (241 → absent bytes)
@@ -1,2 +1,2 @@ -- Verify that certain punctuation marks terminate paths correctly-<foo = ./example| bar: ./example>+<foo: ./example| bar: ./example>
binary file changed (47 → 47 bytes)
@@ -1,3 +1,1 @@-{ example0 = /"foo"/bar/"baz qux"-, example1 = https://example.com/foo/"bar?baz"?qux-}+/"foo"/bar/"baz qux"
binary file changed (78 → 22 bytes)
@@ -0,0 +1,1 @@+http://example.com/someFile.dhall
binary file changed (absent → 35 bytes)
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True
binary file changed (absent → 116 bytes)
@@ -0,0 +1,3 @@+-- the normal form for an empty path is a path of `/`+-- see RFC7230 section 2.7.3+https://example.com
binary file changed (absent → 21 bytes)
@@ -0,0 +1,1 @@+https://example.com/
binary file changed (absent → 21 bytes)
@@ -0,0 +1,2 @@+-- empty path segments are not equivalent to missing path segments+https://example.com/foo//bar
binary file changed (absent → 29 bytes)
@@ -0,0 +1,3 @@+-- an empty query string is not the same as a missing one+-- see RFC 3986 section 6.2.3+https://example.com/foo?
binary file changed (absent → 24 bytes)
@@ -0,0 +1,1 @@+https://example.com/a%20b/c%2fd/e+f/g%2dh
binary file changed (absent → 42 bytes)
@@ -0,0 +1,1 @@+https://example.com/foo?a%20b=c%2fd&e+f/?
binary file changed (absent → 41 bytes)
@@ -0,0 +1,11 @@+{- Fragment identifiers are not allowed in URLs because they serve no purpose+ for Dhall and they could lead to ambiguity if a parser interprets them as+ the list append operator (`#`)++ The following expression therefore only has one valid parse, which is to+ interpret the `#` as a list append. In other words, the following expression+ is parsed as:++ (https://example.com/foo) # bar+-}+https://example.com/foo#bar
binary file changed (absent → 33 bytes)
@@ -0,0 +1,1 @@+https://127.0.0.1/index.dhall
binary file changed (absent → 30 bytes)
@@ -0,0 +1,1 @@+https://200.249.250.255/index.dhall
binary file changed (absent → 36 bytes)
@@ -0,0 +1,1 @@+https://[2001:db8:85a3:0:0:8a2e:370:7334]/tutorial.dhall
binary file changed (absent → 58 bytes)
@@ -0,0 +1,1 @@+https://[2001:db8:85a3::8a2e:370:7334]/tutorial.dhall
binary file changed (absent → 55 bytes)
@@ -0,0 +1,1 @@+https://[::]/index.dhall
binary file changed (absent → 25 bytes)
@@ -0,0 +1,1 @@+http://[AAAA:BBBB:CCCC:DDDD:EEEE:FFFF:0000::]/tutorial.dhall
binary file changed (absent → 63 bytes)
@@ -0,0 +1,1 @@+https://[2001:db8:85a3::8a2e:3.112.115.52]/tutorial.dhall
binary file changed (absent → 59 bytes)
@@ -0,0 +1,1 @@+https://example.com:1234/foo
binary file changed (absent → 29 bytes)
@@ -0,0 +1,1 @@+https://-._~%2C!$&'*+;=:@0abc1--12a------a-a--a-0/foo?/-._~%2C!$&'*+;=:@/?
binary file changed (absent → 75 bytes)
@@ -0,0 +1,1 @@+https://john:doe@example.com/foo
binary file changed (absent → 33 bytes)
@@ -0,0 +1,1 @@+x && y
@@ -0,0 +1,1 @@+w && x && y && z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x == y
@@ -0,0 +1,1 @@+w == x == y == z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x != y
@@ -0,0 +1,1 @@+w != x != y != z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x || y
@@ -0,0 +1,1 @@+w || x || y || z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x === y
@@ -0,0 +1,1 @@+w === x === y === z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x ? y
@@ -0,0 +1,1 @@+w ? x ? y ? z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x # y
@@ -0,0 +1,1 @@+w # x # y # z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x + y
@@ -0,0 +1,1 @@+w + x + y + z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x * y
@@ -0,0 +1,1 @@+w * x * y * z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+a && b || c d == e || f != g && h || i
binary file changed (absent → 59 bytes)
@@ -0,0 +1,1 @@+2 + 3 * 4 === 4 * 3 + 2
@@ -0,0 +1,1 @@+
@@ -0,0 +1,1 @@+a + b * d + e f * (g + h)
binary file changed (absent → 45 bytes)
@@ -0,0 +1,1 @@+a // b c /\ d ⫽ e.{x} ∧ f
binary file changed (absent → 42 bytes)
@@ -0,0 +1,1 @@+x /\ y
@@ -0,0 +1,1 @@+w /\ x /\ y /\ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x ∧ y
@@ -0,0 +1,1 @@+w ∧ x /\ y ∧ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x //\\ y
@@ -0,0 +1,1 @@+w //\\ x //\\ y //\\ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x ⩓ y
@@ -0,0 +1,1 @@+w ⩓ x //\\ y ⩓ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x // y
@@ -0,0 +1,1 @@+w // x // y // z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x ⫽ y
@@ -0,0 +1,1 @@+w ⫽ x // y ⫽ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+x ++ y
@@ -0,0 +1,1 @@+w ++ x ++ y ++ z
binary file changed (absent → 25 bytes)
binary file changed (absent → 11 bytes)
@@ -0,0 +1,1 @@+https://example.com using (toMap { Foo = "Bar" })
binary file changed (absent → 36 bytes)
@@ -0,0 +1,1 @@+(Some 0) with ? = 1
binary file changed (absent → 14 bytes)
@@ -0,0 +1,1 @@+{ x = "foo" }.x
@@ -0,0 +1,1 @@+sha256:fd881e3d48cbc85b4044697bdce8167a77f3fb4665ff0b647a1210a17528818a
@@ -0,0 +1,1 @@+< Foo : Text | Bar : Natural >.Foo
@@ -0,0 +1,1 @@+sha256:35ba8bddad36acfb29cc6f1700364544c145e96cf522f592f18f90c2f96e6e9c
@@ -0,0 +1,1 @@+{ foo : { bar : Text } } ⩓ { foo : { baz : Bool }, qux : Integer }
@@ -0,0 +1,1 @@+sha256:4495bbf3fea6c579c65ee51463b225747803b94668013528b9ca0384304cb350
@@ -0,0 +1,1 @@+{ foo : { bar : Text } } //\\ { foo : { baz : Bool }, qux : Integer }
@@ -0,0 +1,1 @@+sha256:4495bbf3fea6c579c65ee51463b225747803b94668013528b9ca0384304cb350
@@ -0,0 +1,1 @@+{ foo = 1, bar = "ABC" } // { baz = True }
@@ -0,0 +1,1 @@+sha256:18fbad84131d28b6d412e6bc09d5ee8eaf432b639c6cc6f1bef1b4ef366642d7
@@ -0,0 +1,1 @@+{ x = 1, y = True, z = "ABC" }.{ x, y }
@@ -0,0 +1,1 @@+sha256:b7ae500723633be94b53b905384236fcd18cbce59314bb51044bb7d3f3939e6e
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/and.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/and.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,2 @@+../../../../../../Prelude/Bool/build.dhall+(λ(bool : Type) → λ(true : bool) → λ(false : bool) → true)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,2 @@+../../../../../../Prelude/Bool/build.dhall+(λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False, True, False ]
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False, True ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/fold.dhall True Natural 0 1
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/fold.dhall False Natural 0 1
@@ -0,0 +1,1 @@+sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/not.dhall True
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/not.dhall False
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True, False ]
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True ]
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/or.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/or.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/show.dhall True
@@ -0,0 +1,1 @@+sha256:cdbb7fd982ba05e709fe67b23818fffb65ff9c0b8abde1abb5ac1a8245891a3f
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/show.dhall False
@@ -0,0 +1,1 @@+sha256:2357bb42b56beb99180d967177c0490061bd3536a147dfe144d2630f983004e5
@@ -0,0 +1,1 @@+../../../../../../Prelude/Double/show.dhall -3.1
@@ -0,0 +1,1 @@+sha256:d0b3cdb4f3cd5375495629450de676f445c0da6980a5ada251df199079d0ef89
@@ -0,0 +1,1 @@+../../../../../../Prelude/Double/show.dhall 0.4
@@ -0,0 +1,1 @@+sha256:dd5e8756d06f12ef6e003dc769b6e1222e5aa0c8491579dc65b2dd6f4f0ec53d
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/show.dhall -3
@@ -0,0 +1,1 @@+sha256:053de6c2b7f281dd82dd9b643cc848e64633b88c9c57082ec0ac41257c5592d7
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/show.dhall +0
@@ -0,0 +1,1 @@+sha256:4ab1c5aa262f39cdbe1f4924accb69bb44e2a616b5a0ca39655eebd0cc863d33
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/toDouble.dhall -3
@@ -0,0 +1,1 @@+sha256:3c97d2d6c7d01c1c324e6e0a7fcf3b756ff56cf1bf398c4945f04898ae9325a7
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/toDouble.dhall +2
@@ -0,0 +1,1 @@+sha256:fe5c1f8c6cc72fc9aeb61e3b0c5217bf62d2427bcfa678aeefeaa9d04cb9627c
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/all.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/all.dhall Natural Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/any.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/any.dhall Natural Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/build.dhall+Text+( λ(list : Type)+→ λ(cons : Text → list → list)+→ λ(nil : list)+→ cons "ABC" (cons "DEF" nil)+)
@@ -0,0 +1,1 @@+sha256:8a08646db7447b14cf03a497635242b6fb76365017fc1699b2a8807272a2ec58
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/build.dhall+Text+( λ(list : Type)+→ λ(cons : Text → list → list)+→ λ(nil : list)+→ nil+)
@@ -0,0 +1,1 @@+sha256:6da0c98142d1168ac9d6080b7853d2b59b97d42079e1b2f121daf449b3b2e449
@@ -0,0 +1,5 @@+../../../../../../Prelude/List/concat.dhall Natural+[ [ 0, 1, 2 ]+, [ 3, 4 ]+, [ 5, 6, 7, 8 ]+]
@@ -0,0 +1,1 @@+sha256:ae3a399d05bafcee80c088ca6c740f0c61c2a4c6fce6d7e4f4fa26560eac083f
@@ -0,0 +1,5 @@+../../../../../../Prelude/List/concat.dhall Natural+[ [] : List Natural+, [] : List Natural+, [] : List Natural+]
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/concatMap.dhall Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:ea1f5046bcba6efb41bde23738d9a3f3aa2cda3dc722999d9e4f477eb9d1b12d
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/concatMap.dhall Natural Natural (λ(n : Natural) → [ n, n ]) ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/filter.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:988afbf26d86e95a4e6b78b0c344c9f987dcd5f7d7a7c541601bb1e9a01c9102
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/filter.dhall Natural Natural/odd [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:68248e1b69b249e6aeebcd36e7034f159b75d2931105fb4d41fc55d644b7ee8d
@@ -0,0 +1,6 @@+../../../../../../Prelude/List/fold.dhall+Natural+[ 2, 3, 5 ]+Natural+(λ(x : Natural) → λ(y : Natural) → x + y)+0
@@ -0,0 +1,1 @@+sha256:d4428061b6fd69b6b45574603ac71060f9756a5c9a1642df322812e3a7ea858b
@@ -0,0 +1,7 @@+ λ(nil : Natural)+→ ../../../../../../Prelude/List/fold.dhall+ Natural+ [ 2, 3, 5 ]+ Natural+ (λ(x : Natural) → λ(y : Natural) → x + y)+ nil
@@ -0,0 +1,1 @@+sha256:3bd732ae873cb107c3dfef4ae953f6480af310b27fda6b678b43569841e1012b
@@ -0,0 +1,4 @@+ λ(list : Type)+→ λ(cons : Natural → list → list)+→ λ(nil : list)+→ ../../../../../../Prelude/List/fold.dhall Natural [ 2, 3, 5 ] list cons nil
@@ -0,0 +1,1 @@+sha256:186c485f65cbbf97aba127a1205a16ee1125ec279e727ff05d8f8ada624257c7
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/generate.dhall 5 Bool Natural/even
@@ -0,0 +1,1 @@+sha256:0860d18cdc28bc4e7b081bf8c9891ab07e303e4f72b3439bb3a92d7dedd7e8fa
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/generate.dhall 0 Bool Natural/even
@@ -0,0 +1,1 @@+sha256:fb7841e1b3b3e3511196b38df96e73ac7785edef663ea450f97b3c1322742d69
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/head.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:7ac81b06d39113c93f17cc3d2aa55867453f68f35f58a4d577f5bacbb969225f
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/head.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/indexed.dhall Bool [ True, False, True ]
@@ -0,0 +1,1 @@+sha256:7225a557384940f3f2f7f40e5e3e36384be7892c08a24e5467d0f75cd0dda9e1
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/indexed.dhall Bool ([] : List Bool)
@@ -0,0 +1,1 @@+sha256:ff10538dd6bf3bf736bf38f54575e1ddd251aa1d6aad7c6ff6f4159bfc87cc4a
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/iterate.dhall 10 Natural (λ(x : Natural) → x * 2) 1
@@ -0,0 +1,1 @@+sha256:577ea4905798b4fbd4803b3a7c82902594f0c3e5d84af46cec4514da9801760a
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/iterate.dhall 0 Natural (λ(x : Natural) → x * 2) 1
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/last.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:1400a0fa058e1c8fc58926856000d82d99fad204bf48e36f54dccaafc0acd3a0
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/last.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/length.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/length.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/map.dhall Natural Bool Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:aaf20d96e69473f836397764ec61b64a65dc5084ee33692ecd8b85ca63962827
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/map.dhall Natural Bool Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:fb7841e1b3b3e3511196b38df96e73ac7785edef663ea450f97b3c1322742d69
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/null.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/null.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/replicate.dhall 9 Natural 1
@@ -0,0 +1,1 @@+sha256:4241079fe7c8a46be37831a35dedb60645c3a86a2ab24778e03c27c820813cdc
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/replicate.dhall 0 Natural 1
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/reverse.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:ed586af4895ad8118e77976c6ee2fef5a39f69eb9378df32349c81fee2d61d4d
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/reverse.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,15 @@+../../../../../../Prelude/List/shifted.dhall+Bool+[ [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = False }+ ]+, [ { index = 0, value = False }+ , { index = 1, value = False }+ ]+, [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = True }+ ]+]
@@ -0,0 +1,1 @@+sha256:e5c27411e9b0692ac96e6914420f17748eda33d3854067675c6a3b3780fb15a6
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/shifted.dhall Bool ([] : List (List { index : Natural, value : Bool }))
@@ -0,0 +1,1 @@+sha256:ff10538dd6bf3bf736bf38f54575e1ddd251aa1d6aad7c6ff6f4159bfc87cc4a
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/unzip.dhall+Text+Bool+[ { _1 = "ABC", _2 = True }+, { _1 = "DEF", _2 = False }+, { _1 = "GHI", _2 = True }+]
@@ -0,0 +1,1 @@+sha256:fffb0db166d08b99a1beb1650a3c9ee6e7bf6ce1054150bea4dae9b8ce5e4fbf
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/unzip.dhall Text Bool ([] : List { _1 : Text, _2 : Bool })
@@ -0,0 +1,1 @@+sha256:c598ac5f10c7d20fe201f94ed5d9d18a847e89c65db9478492c930e5c42af710
@@ -0,0 +1,6 @@+../../../../../../Prelude/Natural/build.dhall+( λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ succ (succ (succ zero))+)
@@ -0,0 +1,1 @@+sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2
@@ -0,0 +1,6 @@+../../../../../../Prelude/Natural/build.dhall+( λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ zero+)
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/enumerate.dhall 10
@@ -0,0 +1,1 @@+sha256:a7af1902b53cc68a9613b659ebf58d06c840072625d14f9fde7eefa0e0f2add0
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/enumerate.dhall 0
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/even.dhall 3
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/even.dhall 0
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/fold.dhall 3 Natural (λ(x : Natural) → 5 * x) 1
@@ -0,0 +1,1 @@+sha256:39b0b6e0e0b616af4f20c7b06fefcd26dcdbd5be772d885fe73487574ec8b56b
@@ -0,0 +1,1 @@+λ(zero : Natural) → ../../../../../../Prelude/Natural/fold.dhall 3 Natural (λ(x : Natural) → 5 * x) zero
@@ -0,0 +1,1 @@+sha256:c6ddb630f2abfcd78aa874079323ba2a9f80f548c5687346a0fcedff78d14f52
@@ -0,0 +1,4 @@+ λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ ../../../../../../Prelude/Natural/fold.dhall 3 natural succ zero
@@ -0,0 +1,1 @@+sha256:08681d6fb9b1bb78be37f5a976186daa8fc39d0d1d3f7dbb716dc33937a6746d
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/isZero.dhall 2
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/isZero.dhall 0
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/odd.dhall 3
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/odd.dhall 0
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/product.dhall [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:49036d5d861d35d4aff797975a3447ebae71a9057951a03fc810ab8e8e00a498
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/product.dhall ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/show.dhall 3
@@ -0,0 +1,1 @@+sha256:c8911e8084484ca0d468334986a19f0a11cc18b31f41f272e7d4ad2cd479ad39
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/show.dhall 0
@@ -0,0 +1,1 @@+sha256:e3062e0493964ebaef8880667ad8a6289c277618c0b31141610abf5d69e7c9ea
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/sum.dhall [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+sha256:d4428061b6fd69b6b45574603ac71060f9756a5c9a1642df322812e3a7ea858b
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/sum.dhall ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toDouble.dhall 3
@@ -0,0 +1,1 @@+sha256:45b03fd4a48720ca71d4d12967cdde317c918d7c0295845cf9628784a124108d
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toDouble.dhall 0
@@ -0,0 +1,1 @@+sha256:3c213998cb56b97b31168d9dce02d084fb5f5103caef41fb6dc375f593749a7d
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toInteger.dhall 3
@@ -0,0 +1,1 @@+sha256:aa773179ef61a5d65c774bcc510806531ce8fa97c550961526153e42959e6f76
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toInteger.dhall 0
@@ -0,0 +1,1 @@+sha256:5abe149a174ca99b6da92c97b0a7c8900a5f9acddb720bf7173eef877c6a187b
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/all.dhall Natural Natural/even (Some 3)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/all.dhall Natural Natural/even (None Natural)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/any.dhall Natural Natural/even (Some 2)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/any.dhall Natural Natural/even (None Natural)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,7 @@+../../../../../../Prelude/Optional/build.dhall+Natural+( λ(optional : Type)+→ λ(some : Natural → optional)+→ λ(none : optional)+→ some 1+)
@@ -0,0 +1,1 @@+sha256:033652a641ac54a27f52b874877889c6a9c7f8c435dae9f8e956e4d402d6f2c7
@@ -0,0 +1,7 @@+../../../../../../Prelude/Optional/build.dhall+Natural+( λ(optional : Type)+→ λ(some : Natural → optional)+→ λ(none : optional)+→ none+)
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (Some (Some 1))
@@ -0,0 +1,1 @@+sha256:033652a641ac54a27f52b874877889c6a9c7f8c435dae9f8e956e4d402d6f2c7
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (Some (None Natural))
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (None (Optional Natural))
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/filter.dhall Natural Natural/even (Some 2)
@@ -0,0 +1,1 @@+sha256:1400a0fa058e1c8fc58926856000d82d99fad204bf48e36f54dccaafc0acd3a0
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/filter.dhall Natural Natural/odd (Some 2)
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/fold.dhall Natural (Some 2) Natural (λ(x : Natural) → x) 0
@@ -0,0 +1,1 @@+sha256:4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/fold.dhall Natural (None Natural) Natural (λ(x : Natural) → x) 0
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural [ None Natural, Some 1, Some 2 ]
@@ -0,0 +1,1 @@+sha256:033652a641ac54a27f52b874877889c6a9c7f8c435dae9f8e956e4d402d6f2c7
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural [ None Natural, None Natural ]
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural ([] : List (Optional Natural))
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural [ None Natural, Some 1, Some 2 ]
@@ -0,0 +1,1 @@+sha256:1400a0fa058e1c8fc58926856000d82d99fad204bf48e36f54dccaafc0acd3a0
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural [ None Natural, None Natural ]
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural ([] : List (Optional Natural))
@@ -0,0 +1,1 @@+sha256:bfdc295856e05e3610d202d9c12f56f7c423de81cd6069f590786ca176b94df3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/length.dhall Natural (Some 2)
@@ -0,0 +1,1 @@+sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/length.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+sha256:d0a48d41dcc572839faa9499b6c316b8d0d7115efac2ac770f062cd5fd6d0181
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/map.dhall Natural Bool Natural/even (Some 3)
@@ -0,0 +1,1 @@+sha256:3af5b2f9dcc58e7950e2f0281f796de2ac5e87554ae758e38c36cd55cf53743e
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/map.dhall Natural Bool Natural/even (None Natural)
@@ -0,0 +1,1 @@+sha256:2c9884f8336ed425b13068919b216c42be286636c657faa15b911382436b3f00
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/null.dhall Natural (Some 2)
@@ -0,0 +1,1 @@+sha256:2017ff3461395672aa0aa4f64894fd2f95a4b120e2690e8951656d79adc2eed2
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/null.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/toList.dhall Natural (Some 1)
@@ -0,0 +1,1 @@+sha256:75be41333b1ef7a6f5c5cfbcd6097681f3968736dc393b9bf53b2e609564217f
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/toList.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+sha256:d79a2e0e14809ab2dbd2d180e60da8e129a5fb197bdd0caed57e3828402e48a9
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/unzip.dhall Text Bool (Some { _1 = "ABC", _2 = True })
@@ -0,0 +1,1 @@+sha256:5604f6ef6cf7385166101c61738c34a84983f1b7b4695858fa2068fc669eb2c1
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/unzip.dhall Text Bool (None { _1 : Text, _2 : Bool })
@@ -0,0 +1,1 @@+sha256:6de82c54048538c97063c9ae31919b4ca21018ae7119bc123508c136ee653280
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concat.dhall [ "ABC", "DEF", "GHI" ]
@@ -0,0 +1,1 @@+sha256:1f73cf8a6efa724376c3342f9e0104c499e16420732b8c25efc6ab1c18979772
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concat.dhall ([] : List Text)
@@ -0,0 +1,1 @@+sha256:f08ed5225480d827ff3ce74b756afa6330f66d974d6f0d6160d767b5c45642aa
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMap.dhall Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:fa7f18d0522f120dbf229ff0a55f96792ce76613ba17611c53f3f5efd81df510
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMap.dhall Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:f08ed5225480d827ff3ce74b756afa6330f66d974d6f0d6160d767b5c45642aa
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMapSep.dhall ", " Natural Natural/show [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+sha256:952e63727a69b5f2db65645167c3a8f60dbc350608562a1c90423c819a1b5baf
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMapSep.dhall ", " Natural Natural/show ([] : List Natural)
@@ -0,0 +1,1 @@+sha256:f08ed5225480d827ff3ce74b756afa6330f66d974d6f0d6160d767b5c45642aa
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatSep.dhall ", " [ "ABC", "DEF", "GHI" ]
@@ -0,0 +1,1 @@+sha256:151ad6d86cced932c9ed6fa5d69b88fb47e160a13762f4d92dcb1e847ccd30d6
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatSep.dhall ", " ([] : List Text)
@@ -0,0 +1,1 @@+sha256:f08ed5225480d827ff3ce74b756afa6330f66d974d6f0d6160d767b5c45642aa
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/show.dhall "ABC"
@@ -0,0 +1,1 @@+sha256:8dffa347e98424c7b1e91e3e3758fc203a4e52fd990dc4b050da18cdb39655d3
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/show.dhall "\u0000 \$ \\ \n \u263a"
@@ -0,0 +1,1 @@+sha256:92655b5ee59ddfb1decfd19cf8b37e8f2dd5dbd317f55bcbb780bf6ed2010b0a
@@ -0,0 +1,51 @@+let Text/concatMap = ../../../Prelude/Text/concatMap++let Text/concatSep = ../../../Prelude/Text/concatSep++let Row =+ { cores :+ Natural+ , host :+ Text+ , key :+ Text+ , mandatoryFeatures :+ List Text+ , platforms :+ List Text+ , speedFactor :+ Natural+ , supportedFeatures :+ List Text+ , user :+ Optional Text+ }++let renderRow =+ λ ( row+ : Row+ )+ → let host =+ merge+ { None = row.host+ , Some = λ(user : Text) → "${user}@${row.host}"+ }+ row.user+ + let platforms = Text/concatSep "," row.platforms+ + let key = row.key+ + let cores = Integer/show (Natural/toInteger row.cores)+ + let speedFactor = Integer/show (Natural/toInteger row.speedFactor)+ + let supportedFeatures = Text/concatSep "," row.supportedFeatures+ + let mandatoryFeatures = Text/concatSep "," row.mandatoryFeatures+ + in ''+ ${host} ${platforms} ${key} ${cores} ${speedFactor} ${supportedFeatures} ${mandatoryFeatures}+ ''++in Text/concatMap Row renderRow
@@ -0,0 +1,1 @@+sha256:573b0d8fbc28c09c155cf239963b6ba71941aace25e23806043017f7fe75098b
@@ -0,0 +1,6 @@+{ example0 = Double/show -0.42+, example1 = Double/show 13.37+, example2 = Double/show NaN+, example3 = Double/show Infinity+, example4 = Double/show -Infinity+}
@@ -0,0 +1,1 @@+sha256:519ea07f25f759795d4326f06a97401fe0a5efe7823139976d1158c939ee6176
@@ -0,0 +1,8 @@+let Role = < Wizard | Fighter | Rogue >++let show : Role → Text+ =+ λ(x : Role)+ → merge { Wizard = "Wizard", Fighter = "Fighter", Rogue = "Rogue" } x++in show Role.Wizard
@@ -0,0 +1,1 @@+sha256:0e6e479638f87eca04805548d70b5de9d22c5359e7d84ccbcfe148577bc25a4e
@@ -0,0 +1,4 @@+{ example0 = Integer/show +1337+, example1 = Integer/show -42+, example2 = Integer/show +0+}
@@ -0,0 +1,1 @@+sha256:7ff01ad1c68550be713834548385874f38fd7b989e3c4b8cad7125bc266e2bb3
@@ -0,0 +1,10 @@+[ Integer/toDouble +179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792+, Integer/toDouble +179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791+, Integer/toDouble +179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218945+, Integer/toDouble +179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944++, Integer/toDouble -179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792+, Integer/toDouble -179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791+, Integer/toDouble -179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218945+, Integer/toDouble -179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944+]
@@ -0,0 +1,1 @@+sha256:439d81a4aee03a27da069772c4ea51d64c025faac1a2e749734cc5e4cf0f2484
@@ -0,0 +1,3 @@+let l = λ(n : Natural) → λ(m : Natural) → λ(x : Natural) → n + m * x+let f = l 2 3+in f 445
@@ -0,0 +1,1 @@+sha256:97285916da4ee4a1e108af044b449edcdfb818c2f55aefd64f0af76b347da16d
@@ -0,0 +1,22 @@+{ example0 =+ List/build+ Bool+ ( λ(list : Type)+ → λ(cons : Bool → list → list)+ → λ(nil : list)+ → cons True (cons False nil)+ )+, example1 =+ List/build+ Bool+ (λ(x : Type) → λ(x : Bool → x → x) → λ(x : x@1) → x@1 True (x@1 False x))+, example2 =+ λ(id : ∀(a : Type) → a → a)+ → List/build+ Bool+ ( λ(list : Type)+ → λ(cons : Bool → list → list)+ → λ(nil : list)+ → id list (cons True (cons False nil))+ )+}
@@ -0,0 +1,1 @@+sha256:f8f03d5be6563b275253b4d995499e783112ff98ed231855e9152ba45970f8c7
@@ -0,0 +1,4 @@+''+ foo+bar+''
@@ -0,0 +1,1 @@+sha256:2ab4fb081094ad6729186b7cd8a0ec67f7845bbea59ec5a484bff2de42390137
@@ -0,0 +1,18 @@+{ example0 =+ Natural/build+ ( λ(natural : Type)+ → λ(succ : natural → natural)+ → λ(zero : natural)+ → succ zero+ )+, example1 =+ Natural/build (λ(x : Type) → λ(x : x → x) → λ(x : x@1) → x@1 x)+, example2 =+ λ(id : ∀(a : Type) → a → a)+ → Natural/build+ ( λ(natural : Type)+ → λ(succ : natural → natural)+ → λ(zero : natural)+ → id natural (succ zero)+ )+}
@@ -0,0 +1,1 @@+sha256:3e14f3cbed2ddcc78cb9bf66bf2372c2059fd6c4b406ca309a05b89b7f62b011
@@ -0,0 +1,1 @@+1 + 2
@@ -0,0 +1,1 @@+sha256:15f52ecf91c94c1baac02d5a4964b2ed8fa401641a2c8a95e8306ec7c1e3b8d2
@@ -0,0 +1,1 @@+Natural/show 42
@@ -0,0 +1,1 @@+sha256:3d1abfe685ff9abcf5e1a6bcce9b1a8374fc8ac176c22ef3e0188bd29e7d8c6d
@@ -0,0 +1,1 @@+Natural/toInteger 1
@@ -0,0 +1,1 @@+sha256:d2cbb0e226f332ea76d63b3ae4332780c4051d1388d3e190debd5441f4595a04
@@ -0,0 +1,1 @@+{ b = 2 } // { a = 1 }
@@ -0,0 +1,1 @@+sha256:97090822fa42ff0245484a518e2457f85271f4c36fc9462b82498d85b2cc98fc
@@ -0,0 +1,6 @@+{ example0 = λ(x : Bool) → x && True+, example1 = λ(x : Bool) → True && x+, example2 = λ(x : Bool) → x && False+, example3 = λ(x : Bool) → False && x+, example4 = λ(x : Bool) → x && x+}
@@ -0,0 +1,1 @@+sha256:ceac399e820b2a86c65077e07e77bb62f10253fda02a51e438457adf4368b580
@@ -0,0 +1,4 @@+{ example0 = λ(x : Bool) → x == True+, example1 = λ(x : Bool) → True == x+, example2 = λ(x : Bool) → x == x+}
@@ -0,0 +1,1 @@+sha256:5524bd7e3ecdeaa98a25f51f40a1cb33896c2e3e0e21e14c939d17dac946fa4d
@@ -0,0 +1,3 @@+{ example0 = λ(x : Bool) → if x then True else False+, example1 = λ(x : Bool) → λ(y : Text) → if x then y else y+}
@@ -0,0 +1,1 @@+sha256:40b3cdc4cc8f2ff9b733e5e8d8613ec8c3d17fc11f22cfd96d8109765c15add5
@@ -0,0 +1,4 @@+{ example0 = λ(x : Bool) → x != False+, example1 = λ(x : Bool) → False != x+, example2 = λ(x : Bool) → x != x+}
@@ -0,0 +1,1 @@+sha256:69d11e754a064f8abe927e5df446896372a6367135e08c52b5c2274e3bd03bc7
@@ -0,0 +1,6 @@+{ example0 = λ(x : Bool) → x || True+, example1 = λ(x : Bool) → True || x+, example2 = λ(x : Bool) → x || False+, example3 = λ(x : Bool) → False || x+, example4 = λ(x : Bool) → x || x+}
@@ -0,0 +1,1 @@+sha256:41437a8eb5753b2d340fc27cc192265459da57cd65d487447a261f2eede2f5ef
@@ -0,0 +1,3 @@+-- This parses, but will fail to type-check, because in the absence of the `T`+-- it is interpreted as a `Date` applied to a `Time`+2020-01-01 12:00:00
@@ -0,0 +1,1 @@+let x = Sort in 0
@@ -0,0 +1,49 @@+ let bottom : Type = ∀(any : Type) → any++in let not : Type → Type = λ(p : Type) → p → bottom++in let pow = λ(X : Kind) → X → Type++in let U = ∀(X : Kind) → (pow (pow X) → X) → pow (pow X)++in let tau+ : pow (pow U) → U+ = λ(t : pow (pow U))+ → λ(X : Kind)+ → λ(f : pow (pow X) → X)+ → λ(p : pow X)+ → t (λ(x : U) → p (f (x X f)))++in let sigma : U → pow (pow U) = λ(s : U) → s U (λ(t : pow (pow U)) → tau t)++in let Delta+ : pow U+ = λ(y : U) → not (∀(p : pow U) → sigma y p → p (tau (sigma y)))++in let Omega : U = tau (λ(p : pow U) → ∀(x : U) → sigma x p → p x)++in let Theta : Type = ∀(p : pow U) → (∀(x : U) → sigma x p → p x) → p Omega++in let D : Type = ∀(p : pow U) → sigma Omega p → p (tau (sigma Omega))++in let lem1+ : ∀(p : pow U) → (∀(x : U) → sigma x p → p x) → p Omega+ = λ(p : pow U)+ → λ(t1 : ∀(x : U) → sigma x p → p x)+ → t1 Omega (λ(x : U) → t1 (tau (sigma x)))++in let lem3 : D = λ(p : pow U) → lem1 (λ(y : U) → p (tau (sigma y)))++in let lem2+ : not D+ = lem1+ Delta+ ( λ(x : U)+ → λ(H2 : sigma x Delta)+ → λ(H3 : ∀(p : pow U) → sigma x p → p (tau (sigma x)))+ → H3 Delta H2 (λ(pp : pow U) → H3 (λ(y : U) → pp (tau (sigma y))))+ )++in let evidence : bottom = lem2 lem3++in evidence
@@ -0,0 +1,1 @@+{ a = Kind }
@@ -0,0 +1,1 @@+{ x = 1 } : { y : Natural }
@@ -0,0 +1,1 @@+{ x = 1 } : { x : Text }
@@ -0,0 +1,1 @@+assert : (\(_: Bool) -> _) === (\(x: Bool) -> _)
@@ -0,0 +1,1 @@+\(_: Bool) -> assert : (\(_: Bool) -> _) === (\(x: Bool) -> _)
@@ -0,0 +1,1 @@+assert : -0.0 ≡ +0.0
@@ -0,0 +1,1 @@+assert : Bool
@@ -0,0 +1,1 @@+assert : 1 === 2
@@ -0,0 +1,6 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { id = None Natural }+ }++in Example::{=}
@@ -0,0 +1,6 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { name = True, id = None Natural }+ }++in Example::{=}
@@ -0,0 +1,6 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { name = "", id = None Natural }+ }++in Example::{ nam = "John Doe" }
@@ -0,0 +1,6 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { name = "", id = None Natural }+ }++in Example::{ name = True }
@@ -0,0 +1,1 @@+toMap {=}
@@ -0,0 +1,1 @@+1 === False
@@ -0,0 +1,1 @@+Bool === Bool
@@ -0,0 +1,1 @@+(λ(_ : Natural) → _) True
@@ -0,0 +1,1 @@+True True
@@ -0,0 +1,1 @@+λ(_ : 1) → _
@@ -0,0 +1,1 @@+2 → _
@@ -0,0 +1,1 @@+Kind → Sort
@@ -0,0 +1,1 @@+Bool -> 1
@@ -0,0 +1,1 @@+Type → Sort
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= "Bar" }
@@ -0,0 +1,1 @@+if True then 1 else ""
@@ -0,0 +1,1 @@+if True then Kind else Kind
@@ -0,0 +1,1 @@+if 1 then 1 else 1
@@ -0,0 +1,1 @@+\(x: let x = 0 in Sort) -> 1
@@ -0,0 +1,14 @@+-- When you check if an inferred type is equivalent to an annotation,+-- you must alpha-beta-normalize both sides first. But it is not safe+-- to beta-normalise an expression which hasn't first been+-- typechecked.+--+-- This test contains an annotation which doesn't typecheck, and+-- which, when beta-normalized, doesn't terminate. It exists to+-- verify that implementations typecheck the annotation before+-- checking equivalence.+let a+ : (λ(x : Natural) → x x) (λ(x : Natural) → x x)+ = 3++in 5
@@ -0,0 +1,1 @@+let x : Natural = True in True
@@ -0,0 +1,1 @@+[] : List Type
@@ -0,0 +1,1 @@+[ Bool ]
@@ -0,0 +1,1 @@+[ True, 1 ]
@@ -0,0 +1,1 @@+merge {=} (< x : Bool >.x True)
@@ -0,0 +1,1 @@+merge { x = 0 } < x >.x : Bool
@@ -0,0 +1,1 @@+merge {=} <> : Type
@@ -0,0 +1,1 @@+\(x: { True: Natural, False: Natural }) -> merge x True
@@ -0,0 +1,1 @@+\(x: <>) -> (merge {=} x) : Bool
@@ -0,0 +1,1 @@+\(x: <>) -> let y: Bool = merge {=} x in 1
@@ -0,0 +1,1 @@+merge {=} <>
@@ -0,0 +1,1 @@+merge { x = None } (<x: Type>.x Bool)
@@ -0,0 +1,1 @@+merge { x = True } (< x : Bool >.x True)
@@ -0,0 +1,1 @@+merge { x = λ(_ : Bool) → _ } <> : Bool
@@ -0,0 +1,1 @@+merge { x = λ(_ : Bool) → _ } (< x : Natural >.x 1)
@@ -0,0 +1,1 @@+merge { x = λ(_ : Bool) → _, y = λ(_ : Natural) → _ } (< x : Bool | y : Natural >.x True)
@@ -0,0 +1,1 @@+merge True < x >.x
@@ -0,0 +1,1 @@+merge {=} <x>.x
@@ -0,0 +1,1 @@+merge { x = 0 } <x | y>.x
@@ -0,0 +1,1 @@+merge {=} True
@@ -0,0 +1,1 @@+merge { x = 1, y = 2 } < x >.x
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4 } : Natural
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4 } : List Natural
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4 } : List { mapKey : Natural, mapValue : Natural }
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4 } : List { mapKey : Text, mapValue : Text }
@@ -0,0 +1,1 @@+Natural/subtract True True
@@ -0,0 +1,1 @@+(0 : Bool) : Natural
@@ -0,0 +1,1 @@+(0 : Natural) : Bool
@@ -0,0 +1,1 @@+toMap "text"
@@ -0,0 +1,1 @@+1 && 1
@@ -0,0 +1,1 @@+1 == 1
@@ -0,0 +1,1 @@+1 # [ True ]
@@ -0,0 +1,1 @@+[ True ] # [ 1 ]
@@ -0,0 +1,1 @@+1 # 2
@@ -0,0 +1,1 @@+[ True ] # 1
@@ -0,0 +1,1 @@+1 != 1
@@ -0,0 +1,1 @@+1 || 1
@@ -0,0 +1,1 @@+True + True
@@ -0,0 +1,1 @@+1 ++ ""
@@ -0,0 +1,1 @@+"" ++ 1
@@ -0,0 +1,1 @@+True * True
@@ -0,0 +1,1 @@+[] : Optional Bool
@@ -0,0 +1,1 @@+[ 1 ] : Optional Natural
@@ -0,0 +1,13 @@+{- This test illustrates that duplicate fields need not be literals in order+ to be properly normalized. One or both of the duplicate fields can be+ abstract because field duplication delegates its behavior to the `∧`+ operator++ This particular example fails because it desugars to:++ λ(r : { y : Natural }) → { x = { y = 1 } ∧ r }++ ... and the `∧` operator can infer that the two records collide on the+ field `y`+-}+λ(r : { y : Natural }) → { x = { y = 1 }, x = r }
@@ -0,0 +1,8 @@+{- This fails because the expression desugars to:++ { x = { y = 0 } ∧ { y = 0 } }++ ... which is ill-typed due to `∧` forbidding collisions and the two `y`+ fields collide.+-}+{ x = { y = 0 }, x = { y = 0 } }
@@ -0,0 +1,7 @@+{- This fails because the expression desugars to:++ { x = 0 ∧ 0 }++ ... which is ill-typed due to ∧ only working on records+-}+{ x = 0, x = 0 }
@@ -0,0 +1,1 @@+{ y = {=} }.( {y : Natural} )
@@ -0,0 +1,1 @@+{ y = {=} }.( {x : Natural} )
@@ -0,0 +1,1 @@+{ x = 1 }.{ x, x }
@@ -0,0 +1,1 @@+{=}.{ x }
@@ -0,0 +1,1 @@+{ y = {=} }.{ x }
@@ -0,0 +1,1 @@+True.{ x }
@@ -0,0 +1,1 @@+{=}.x
@@ -0,0 +1,1 @@+{ y = {=} }.x
@@ -0,0 +1,1 @@+True.x
@@ -0,0 +1,1 @@+Bool.x
@@ -0,0 +1,1 @@+{ x: Natural, x: Natural }
@@ -0,0 +1,1 @@+{ x : True }
@@ -0,0 +1,1 @@+True ∧ {=}
@@ -0,0 +1,1 @@+{ x = True } ∧ { x = False }
@@ -0,0 +1,1 @@+{=} ∧ True
@@ -0,0 +1,1 @@+Bool ⩓ {}
@@ -0,0 +1,1 @@+{ x : Bool } ⩓ { x : Natural }
@@ -0,0 +1,1 @@+{} ⩓ Bool
@@ -0,0 +1,1 @@+Optional/build
@@ -0,0 +1,1 @@+Optional/fold
@@ -0,0 +1,1 @@+True ⫽ {=}
@@ -0,0 +1,1 @@+{=} ⫽ True
@@ -0,0 +1,1 @@+showConstructor < A : Bool >.A
@@ -0,0 +1,1 @@+showConstructor None
@@ -0,0 +1,1 @@+showConstructor 0
@@ -0,0 +1,1 @@+Some Bool
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+"${1}"
@@ -0,0 +1,2 @@+-- The mapKey must be Text+toMap {=} : List { mapKey : Bool, mapValue : Text }
@@ -0,0 +1,1 @@+toMap { x = Bool }
@@ -0,0 +1,1 @@+1 : Bool
@@ -0,0 +1,1 @@+< x : Bool >.y
@@ -0,0 +1,1 @@+constructors < Left : Natural | Right : Bool >
@@ -0,0 +1,1 @@+<x | x>
@@ -0,0 +1,1 @@+<x | x: Natural>
@@ -0,0 +1,1 @@+< x : True >
@@ -0,0 +1,1 @@+x
@@ -0,0 +1,1 @@+Some ({=} with x = Bool)
@@ -0,0 +1,6 @@+{- The `with` keyword cannot "descend" past a field that is not a record++ In the following example, the `a` field is not a record, therefore there is+ no possibility of adding or overriding `a` with an inner `b` field+-}+{ a = 1 } with a.b = 2
@@ -0,0 +1,1 @@+{ x = 0 } with ? = 1
@@ -0,0 +1,1 @@+5 with a = 10
@@ -0,0 +1,1 @@+(None { x : Natural }) with ?.x = True
@@ -0,0 +1,1 @@+(None Natural) with ? = "hello"
@@ -0,0 +1,4 @@+-- The purpose of this test is to check that an implementation is not parsing a+-- standalone `Z` as a `TimeOffset`. Instead, this should be treated as an+-- unbound variable named `Z`+Z
@@ -0,0 +1,11 @@+{-+ This URL returns (probably) a different result for each request. This test+ ensures that import results for a given URL are correctly cached within an+ execution of dhall.+-}+let _ =+ assert+ : https://test.dhall-lang.org/random-string as Text+ ≡ https://test.dhall-lang.org/random-string as Text++in 0
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,10 @@+{-+ This URL returns (probably) a different result for each request. This test+ ensures that import locations are canonicalized before being cached.+-}+let _ =+ assert+ : https://test.dhall-lang.org/random-string as Text+ ≡ https://test.dhall-lang.org/foo/../random-string as Text++in 0
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,4 @@+ λ ( record+ : ∀(k : Kind) → ∀(makeRecord : ∀(x : Type) → ∀(y : Type → Type) → k) → k+ )+→ record Type (λ(x : Type) → λ(y : Type → Type) → x)
@@ -0,0 +1,4 @@+ ∀ ( record+ : ∀(k : Kind) → ∀(makeRecord : ∀(x : Type) → ∀(y : Type → Type) → k) → k+ )+→ Type
@@ -0,0 +1,1 @@+λ(record : { x : Type, y : Type → Type }) → record.x
@@ -0,0 +1,1 @@+∀(record : { x : Type, y : Type → Type }) → Type
@@ -0,0 +1,1 @@+{ foo = 1 } ⫽ { bar = Text }
@@ -0,0 +1,1 @@+{ bar : Type, foo : Natural }
@@ -0,0 +1,1 @@+{ a = 0 } ⫽ { a = Bool }
@@ -0,0 +1,1 @@+{ a : Type }
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/and.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/and.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,2 @@+../../../../../../Prelude/Bool/build.dhall+(λ(bool : Type) → λ(true : bool) → λ(false : bool) → true)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,2 @@+../../../../../../Prelude/Bool/build.dhall+(λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False, True, False ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False, True ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall [ False ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/even.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/fold.dhall True Natural 0 1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/fold.dhall False Natural 0 1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/not.dhall True
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/not.dhall False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True, False ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall [ True ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/odd.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/or.dhall [ True, False, True ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/or.dhall ([] : List Bool)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/show.dhall True
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Bool/show.dhall False
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Double/show.dhall -3.1
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Double/show.dhall 0.4
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/show.dhall -3
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/show.dhall +0
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/toDouble.dhall -3
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+../../../../../../Prelude/Integer/toDouble.dhall +2
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/all.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/all.dhall Natural Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/any.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/any.dhall Natural Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/build.dhall+Text+( λ(list : Type)+→ λ(cons : Text → list → list)+→ λ(nil : list)+→ cons "ABC" (cons "DEF" nil)+)
@@ -0,0 +1,1 @@+List Text
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/build.dhall+Text+( λ(list : Type)+→ λ(cons : Text → list → list)+→ λ(nil : list)+→ nil+)
@@ -0,0 +1,1 @@+List Text
@@ -0,0 +1,5 @@+../../../../../../Prelude/List/concat.dhall Natural+[ [ 0, 1, 2 ]+, [ 3, 4 ]+, [ 5, 6, 7, 8 ]+]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,5 @@+../../../../../../Prelude/List/concat.dhall Natural+[ [] : List Natural+, [] : List Natural+, [] : List Natural+]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/concatMap.dhall Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/concatMap.dhall Natural Natural (λ(n : Natural) → [ n, n ]) ([] : List Natural)
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/filter.dhall Natural Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/filter.dhall Natural Natural/odd [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,6 @@+../../../../../../Prelude/List/fold.dhall+Natural+[ 2, 3, 5 ]+Natural+(λ(x : Natural) → λ(y : Natural) → x + y)+0
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,7 @@+ λ(nil : Natural)+→ ../../../../../../Prelude/List/fold.dhall+ Natural+ [ 2, 3, 5 ]+ Natural+ (λ(x : Natural) → λ(y : Natural) → x + y)+ nil
@@ -0,0 +1,1 @@+∀(nil : Natural) → Natural
@@ -0,0 +1,4 @@+ λ(list : Type)+→ λ(cons : Natural → list → list)+→ λ(nil : list)+→ ../../../../../../Prelude/List/fold.dhall Natural [ 2, 3, 5 ] list cons nil
@@ -0,0 +1,1 @@+∀(list : Type) → ∀(cons : Natural → list → list) → ∀(nil : list) → list
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/generate.dhall 5 Bool Natural/even
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/generate.dhall 0 Bool Natural/even
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/head.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/head.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/indexed.dhall Bool [ True, False, True ]
@@ -0,0 +1,1 @@+List { index : Natural, value : Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/indexed.dhall Bool ([] : List Bool)
@@ -0,0 +1,1 @@+List { index : Natural, value : Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/iterate.dhall 10 Natural (λ(x : Natural) → x * 2) 1
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/iterate.dhall 0 Natural (λ(x : Natural) → x * 2) 1
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/last.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/last.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/length.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/length.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/map.dhall Natural Bool Natural/even [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/map.dhall Natural Bool Natural/even ([] : List Natural)
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/null.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/null.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/replicate.dhall 9 Natural 1
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/replicate.dhall 0 Natural 1
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/reverse.dhall Natural [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/reverse.dhall Natural ([] : List Natural)
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,15 @@+../../../../../../Prelude/List/shifted.dhall+Bool+[ [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = False }+ ]+, [ { index = 0, value = False }+ , { index = 1, value = False }+ ]+, [ { index = 0, value = True }+ , { index = 1, value = True }+ , { index = 2, value = True }+ , { index = 3, value = True }+ ]+]
@@ -0,0 +1,1 @@+List { index : Natural, value : Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/shifted.dhall Bool ([] : List (List { index : Natural, value : Bool }))
@@ -0,0 +1,1 @@+List { index : Natural, value : Bool }
@@ -0,0 +1,7 @@+../../../../../../Prelude/List/unzip.dhall+Text+Bool+[ { _1 = "ABC", _2 = True }+, { _1 = "DEF", _2 = False }+, { _1 = "GHI", _2 = True }+]
@@ -0,0 +1,1 @@+{ _1 : List Text, _2 : List Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/List/unzip.dhall Text Bool ([] : List { _1 : Text, _2 : Bool })
@@ -0,0 +1,1 @@+{ _1 : List Text, _2 : List Bool }
@@ -0,0 +1,1 @@+../../../../../Prelude/Bool/and
@@ -0,0 +1,1 @@+∀(xs : List Bool) → Bool
@@ -0,0 +1,1 @@+../../../../../Prelude/Bool/or
@@ -0,0 +1,1 @@+∀(xs : List Bool) → Bool
@@ -0,0 +1,1 @@+../../../../../Prelude/Bool/even
@@ -0,0 +1,1 @@+∀(xs : List Bool) → Bool
@@ -0,0 +1,1 @@+../../../../../Prelude/Bool/odd
@@ -0,0 +1,1 @@+∀(xs : List Bool) → Bool
@@ -0,0 +1,1 @@+../../../../../Prelude/List/concat
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(xss : List (List a)) → List a
@@ -0,0 +1,1 @@+../../../../../Prelude/List/shifted
@@ -0,0 +1,3 @@+ ∀(a : Type)+→ ∀(kvss : List (List { index : Natural, value : a }))+→ List { index : Natural, value : a }
@@ -0,0 +1,1 @@+../../../../../Prelude/Natural/sum
@@ -0,0 +1,1 @@+∀(xs : List Natural) → Natural
@@ -0,0 +1,1 @@+../../../../../Prelude/Natural/product
@@ -0,0 +1,1 @@+∀(xs : List Natural) → Natural
@@ -0,0 +1,1 @@+../../../../../Prelude/Optional/head
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(xs : List (Optional a)) → Optional a
@@ -0,0 +1,1 @@+../../../../../Prelude/Optional/last
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(xs : List (Optional a)) → Optional a
@@ -0,0 +1,1 @@+../../../../../Prelude/Text/concat
@@ -0,0 +1,1 @@+∀(xs : List Text) → Text
@@ -0,0 +1,6 @@+../../../../../../Prelude/Natural/build.dhall+( λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ succ (succ (succ zero))+)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,6 @@+../../../../../../Prelude/Natural/build.dhall+( λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ zero+)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/enumerate.dhall 10
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/enumerate.dhall 0
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/even.dhall 3
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/even.dhall 0
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/fold.dhall 3 Natural (λ(x : Natural) → 5 * x) 1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+λ(zero : Natural) → ../../../../../../Prelude/Natural/fold.dhall 3 Natural (λ(x : Natural) → 5 * x) zero
@@ -0,0 +1,1 @@+∀(zero : Natural) → Natural
@@ -0,0 +1,4 @@+ λ(natural : Type)+→ λ(succ : natural → natural)+→ λ(zero : natural)+→ ../../../../../../Prelude/Natural/fold.dhall 3 natural succ zero
@@ -0,0 +1,1 @@+∀(natural : Type) → ∀(succ : natural → natural) → ∀(zero : natural) → natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/isZero.dhall 2
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/isZero.dhall 0
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/odd.dhall 3
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/odd.dhall 0
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/product.dhall [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/product.dhall ([] : List Natural)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/show.dhall 3
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/show.dhall 0
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/sum.dhall [ 2, 3, 5 ]
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/sum.dhall ([] : List Natural)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toDouble.dhall 3
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toDouble.dhall 0
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toInteger.dhall 3
@@ -0,0 +1,1 @@+Integer
@@ -0,0 +1,1 @@+../../../../../../Prelude/Natural/toInteger.dhall 0
@@ -0,0 +1,1 @@+Integer
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/all.dhall Natural Natural/even (Some 3)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/all.dhall Natural Natural/even (None Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/any.dhall Natural Natural/even (Some 2)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/any.dhall Natural Natural/even (None Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,7 @@+../../../../../../Prelude/Optional/build.dhall+Natural+( λ(optional : Type)+→ λ(some : Natural → optional)+→ λ(none : optional)+→ some 1+)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,7 @@+../../../../../../Prelude/Optional/build.dhall+Natural+( λ(optional : Type)+→ λ(some : Natural → optional)+→ λ(none : optional)+→ none+)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (Some (Some 1))
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (Some (None Natural))
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/concat.dhall Natural (None (Optional Natural))
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/filter.dhall Natural Natural/even (Some 2)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/filter.dhall Natural Natural/odd (Some 2)
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/fold.dhall Natural (Some 2) Natural (λ(x : Natural) → x) 0
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/fold.dhall Natural (None Natural) Natural (λ(x : Natural) → x) 0
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural [ None Natural, Some 1, Some 2 ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural [ None Natural, None Natural ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/head.dhall Natural ([] : List (Optional Natural))
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural [ None Natural, Some 1, Some 2 ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural [ None Natural, None Natural ]
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/last.dhall Natural ([] : List (Optional Natural))
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/length.dhall Natural (Some 2)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/length.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/map.dhall Natural Bool Natural/even (Some 3)
@@ -0,0 +1,1 @@+Optional Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/map.dhall Natural Bool Natural/even (None Natural)
@@ -0,0 +1,1 @@+Optional Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/null.dhall Natural (Some 2)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/null.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/toList.dhall Natural (Some 1)
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/toList.dhall Natural (None Natural)
@@ -0,0 +1,1 @@+List Natural
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/unzip.dhall Text Bool (Some { _1 = "ABC", _2 = True })
@@ -0,0 +1,1 @@+{ _1 : Optional Text, _2 : Optional Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/Optional/unzip.dhall Text Bool (None { _1 : Text, _2 : Bool })
@@ -0,0 +1,1 @@+{ _1 : Optional Text, _2 : Optional Bool }
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concat.dhall [ "ABC", "DEF", "GHI" ]
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concat.dhall ([] : List Text)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMap.dhall Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMap.dhall Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMapSep.dhall ", " Natural Natural/show [ 0, 1, 2 ]
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatMapSep.dhall ", " Natural Natural/show ([] : List Natural)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatSep.dhall ", " [ "ABC", "DEF", "GHI" ]
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../../../../Prelude/Text/concatSep.dhall ", " ([] : List Text)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+../../../Prelude/package.dhall
@@ -0,0 +1,740 @@+{ Bool :+ { and : ∀(xs : List Bool) → Bool+ , build :+ ∀(f : ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool) → Bool+ , equal : ∀(x : Bool) → ∀(y : Bool) → Bool+ , even : ∀(xs : List Bool) → Bool+ , fold :+ ∀(b : Bool) → ∀(bool : Type) → ∀(true : bool) → ∀(false : bool) → bool+ , not : ∀(b : Bool) → Bool+ , odd : ∀(xs : List Bool) → Bool+ , or : ∀(xs : List Bool) → Bool+ , show : ∀(b : Bool) → Text+ }+, Date : { show : Date → Text }+, Double : { show : Double → Text }+, Function :+ { compose :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(c : Type) →+ ∀(f : a → b) →+ ∀(g : b → c) →+ ∀(x : a) →+ c+ , composeList : ∀(a : Type) → ∀(functions : List (a → a)) → a → a+ , identity : ∀(a : Type) → ∀(x : a) → a+ }+, Integer :+ { abs : ∀(n : Integer) → Natural+ , add : ∀(m : Integer) → ∀(n : Integer) → Integer+ , clamp : Integer → Natural+ , equal : ∀(a : Integer) → ∀(b : Integer) → Bool+ , greaterThan : ∀(x : Integer) → ∀(y : Integer) → Bool+ , greaterThanEqual : ∀(x : Integer) → ∀(y : Integer) → Bool+ , lessThan : ∀(x : Integer) → ∀(y : Integer) → Bool+ , lessThanEqual : ∀(x : Integer) → ∀(y : Integer) → Bool+ , multiply : ∀(m : Integer) → ∀(n : Integer) → Integer+ , negate : Integer → Integer+ , negative : ∀(n : Integer) → Bool+ , nonNegative : ∀(n : Integer) → Bool+ , nonPositive : ∀(n : Integer) → Bool+ , positive : ∀(n : Integer) → Bool+ , show : Integer → Text+ , subtract : ∀(m : Integer) → ∀(n : Integer) → Integer+ , toDouble : Integer → Double+ , toNatural : ∀(n : Integer) → Optional Natural+ }+, JSON :+ { Nesting : Type+ , Tagged : ∀(a : Type) → Type+ , Type : Type+ , array :+ ∀ ( x+ : List+ ( ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ )+ ) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , bool :+ ∀(x : Bool) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , double :+ ∀(x : Double) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , integer :+ ∀(x : Integer) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , keyText :+ ∀(key : Text) → ∀(value : Text) → { mapKey : Text, mapValue : Text }+ , keyValue :+ ∀(v : Type) →+ ∀(key : Text) →+ ∀(value : v) →+ { mapKey : Text, mapValue : v }+ , natural :+ ∀(x : Natural) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , null :+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , number :+ ∀(x : Double) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , object :+ ∀ ( x+ : List+ { mapKey : Text+ , mapValue :+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ }+ ) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , omitNullFields :+ ∀ ( old+ : ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ ) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , render :+ ∀ ( json+ : ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ ) →+ Text+ , renderCompact :+ ∀ ( j+ : ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ ) →+ Text+ , renderInteger : ∀(integer : Integer) → Text+ , renderYAML :+ ∀ ( json+ : ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ ) →+ Text+ , string :+ ∀(x : Text) →+ ∀(JSON : Type) →+ ∀ ( json+ : { array : List JSON → JSON+ , bool : Bool → JSON+ , double : Double → JSON+ , integer : Integer → JSON+ , null : JSON+ , object : List { mapKey : Text, mapValue : JSON } → JSON+ , string : Text → JSON+ }+ ) →+ JSON+ , tagInline :+ ∀(tagFieldName : Text) →+ ∀(a : Type) →+ ∀(contents : a) →+ { contents : a, field : Text, nesting : < Inline | Nested : Text > }+ , tagNested :+ ∀(contentsFieldName : Text) →+ ∀(tagFieldName : Text) →+ ∀(a : Type) →+ ∀(contents : a) →+ { contents : a, field : Text, nesting : < Inline | Nested : Text > }+ }+, List :+ { all : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → Bool+ , any : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → Bool+ , build :+ ∀(a : Type) →+ (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list) →+ List a+ , concat : ∀(a : Type) → ∀(xss : List (List a)) → List a+ , concatMap :+ ∀(a : Type) → ∀(b : Type) → ∀(f : a → List b) → ∀(xs : List a) → List b+ , default : ∀(a : Type) → ∀(o : Optional (List a)) → List a+ , drop : ∀(n : Natural) → ∀(a : Type) → ∀(xs : List a) → List a+ , empty : ∀(a : Type) → List a+ , filter : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : List a) → List a+ , filterMap :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → Optional b) →+ ∀(xs : List a) →+ List b+ , fold :+ ∀(a : Type) →+ List a →+ ∀(list : Type) →+ ∀(cons : a → list → list) →+ ∀(nil : list) →+ list+ , foldLeft :+ ∀(a : Type) →+ ∀(xs : List a) →+ ∀(list : Type) →+ ∀(cons : list → a → list) →+ ∀(nil : list) →+ list+ , generate : ∀(n : Natural) → ∀(a : Type) → ∀(f : Natural → a) → List a+ , head : ∀(a : Type) → List a → Optional a+ , index : ∀(n : Natural) → ∀(a : Type) → ∀(xs : List a) → Optional a+ , indexed : ∀(a : Type) → List a → List { index : Natural, value : a }+ , iterate : ∀(n : Natural) → ∀(a : Type) → ∀(f : a → a) → ∀(x : a) → List a+ , last : ∀(a : Type) → List a → Optional a+ , length : ∀(a : Type) → List a → Natural+ , map : ∀(a : Type) → ∀(b : Type) → ∀(f : a → b) → ∀(xs : List a) → List b+ , mapMaybe :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → Optional b) →+ ∀(xs : List a) →+ List b+ , mapWithIndex :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : Natural → a → b) →+ ∀(xs : List a) →+ List b+ , null : ∀(a : Type) → ∀(xs : List a) → Bool+ , partition :+ ∀(a : Type) →+ ∀(f : a → Bool) →+ ∀(xs : List a) →+ { false : List a, true : List a }+ , replicate : ∀(n : Natural) → ∀(a : Type) → ∀(x : a) → List a+ , reverse : ∀(a : Type) → List a → List a+ , shifted :+ ∀(a : Type) →+ ∀(kvss : List (List { index : Natural, value : a })) →+ List { index : Natural, value : a }+ , take : ∀(n : Natural) → ∀(a : Type) → ∀(xs : List a) → List a+ , unpackOptionals : ∀(a : Type) → ∀(xs : List (Optional a)) → List a+ , unzip :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(xs : List { _1 : a, _2 : b }) →+ { _1 : List a, _2 : List b }+ , zip :+ ∀(a : Type) →+ ∀(xs : List a) →+ ∀(b : Type) →+ ∀(ys : List b) →+ List { _1 : a, _2 : b }+ }+, Location : { Type : Type }+, Map :+ { Entry : ∀(k : Type) → ∀(v : Type) → Type+ , Type : ∀(k : Type) → ∀(v : Type) → Type+ , empty : ∀(k : Type) → ∀(v : Type) → List { mapKey : k, mapValue : v }+ , keyText :+ ∀(key : Text) → ∀(value : Text) → { mapKey : Text, mapValue : Text }+ , keyValue :+ ∀(v : Type) →+ ∀(key : Text) →+ ∀(value : v) →+ { mapKey : Text, mapValue : v }+ , keys :+ ∀(k : Type) →+ ∀(v : Type) →+ ∀(xs : List { mapKey : k, mapValue : v }) →+ List k+ , map :+ ∀(k : Type) →+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → b) →+ ∀(m : List { mapKey : k, mapValue : a }) →+ List { mapKey : k, mapValue : b }+ , mapMaybe :+ ∀(k : Type) →+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → Optional b) →+ ∀(m : List { mapKey : k, mapValue : a }) →+ List { mapKey : k, mapValue : b }+ , unpackOptionals :+ ∀(k : Type) →+ ∀(v : Type) →+ ∀(xs : List { mapKey : k, mapValue : Optional v }) →+ List { mapKey : k, mapValue : v }+ , values :+ ∀(k : Type) →+ ∀(v : Type) →+ ∀(xs : List { mapKey : k, mapValue : v }) →+ List v+ }+, Monoid : ∀(m : Type) → Type+, Natural :+ { build :+ ( ∀(natural : Type) →+ ∀(succ : natural → natural) →+ ∀(zero : natural) →+ natural+ ) →+ Natural+ , enumerate : ∀(n : Natural) → List Natural+ , equal : ∀(a : Natural) → ∀(b : Natural) → Bool+ , even : Natural → Bool+ , fold :+ Natural →+ ∀(natural : Type) →+ ∀(succ : natural → natural) →+ ∀(zero : natural) →+ natural+ , greaterThan : ∀(x : Natural) → ∀(y : Natural) → Bool+ , greaterThanEqual : ∀(x : Natural) → ∀(y : Natural) → Bool+ , isZero : Natural → Bool+ , lessThan : ∀(x : Natural) → ∀(y : Natural) → Bool+ , lessThanEqual : ∀(x : Natural) → ∀(y : Natural) → Bool+ , listMax : ∀(xs : List Natural) → Optional Natural+ , listMin : ∀(xs : List Natural) → Optional Natural+ , max : ∀(a : Natural) → ∀(b : Natural) → Natural+ , min : ∀(a : Natural) → ∀(b : Natural) → Natural+ , odd : Natural → Bool+ , product : ∀(xs : List Natural) → Natural+ , show : Natural → Text+ , sort : ∀(xs : List Natural) → List Natural+ , subtract : Natural → Natural → Natural+ , sum : ∀(xs : List Natural) → Natural+ , toDouble : ∀(n : Natural) → Double+ , toInteger : Natural → Integer+ }+, NonEmpty :+ { Type : ∀(a : Type) → Type+ , all :+ ∀(a : Type) →+ ∀(f : a → Bool) →+ ∀(xs : { head : a, tail : List a }) →+ Bool+ , any :+ ∀(a : Type) →+ ∀(f : a → Bool) →+ ∀(xs : { head : a, tail : List a }) →+ Bool+ , concat :+ ∀(a : Type) →+ ∀ ( xss+ : { head : { head : a, tail : List a }+ , tail : List { head : a, tail : List a }+ }+ ) →+ { head : a, tail : List a }+ , concatMap :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → { head : b, tail : List b }) →+ ∀(xs : { head : a, tail : List a }) →+ { head : b, tail : List b }+ , head : ∀(a : Type) → ∀(xs : { head : a, tail : List a }) → a+ , index :+ ∀(n : Natural) →+ ∀(a : Type) →+ ∀(xs : { head : a, tail : List a }) →+ Optional a+ , indexed :+ ∀(a : Type) →+ ∀(xs : { head : a, tail : List a }) →+ { head : { index : Natural, value : a }+ , tail : List { index : Natural, value : a }+ }+ , last : ∀(a : Type) → ∀(xs : { head : a, tail : List a }) → a+ , length : ∀(a : Type) → ∀(xs : { head : a, tail : List a }) → Natural+ , make :+ ∀(a : Type) →+ ∀(head : a) →+ ∀(tail : List a) →+ { head : a, tail : List a }+ , map :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → b) →+ ∀(xs : { head : a, tail : List a }) →+ { head : b, tail : List b }+ , reverse :+ ∀(a : Type) →+ ∀(xs : { head : a, tail : List a }) →+ { head : a, tail : List a }+ , shifted :+ ∀(a : Type) →+ ∀ ( kvss+ : { head :+ { head : { index : Natural, value : a }+ , tail : List { index : Natural, value : a }+ }+ , tail :+ List+ { head : { index : Natural, value : a }+ , tail : List { index : Natural, value : a }+ }+ }+ ) →+ { head : { index : Natural, value : a }+ , tail : List { index : Natural, value : a }+ }+ , singleton : ∀(a : Type) → ∀(x : a) → { head : a, tail : List a }+ , toList : ∀(a : Type) → ∀(xs : { head : a, tail : List a }) → List a+ , unzip :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(xs : { head : { _1 : a, _2 : b }, tail : List { _1 : a, _2 : b } }) →+ { _1 : { head : a, tail : List a }, _2 : { head : b, tail : List b } }+ , zip :+ ∀(a : Type) →+ ∀(xs : { head : a, tail : List a }) →+ ∀(b : Type) →+ ∀(ys : { head : b, tail : List b }) →+ { head : { _1 : a, _2 : b }, tail : List { _1 : a, _2 : b } }+ }+, Operator :+ { `!=` : ∀(m : Bool) → ∀(n : Bool) → Bool+ , `#` : ∀(type : Type) → ∀(m : List type) → ∀(n : List type) → List type+ , `&&` : ∀(m : Bool) → ∀(n : Bool) → Bool+ , `*` : ∀(m : Natural) → ∀(n : Natural) → Natural+ , `+` : ∀(m : Natural) → ∀(n : Natural) → Natural+ , `++` : ∀(m : Text) → ∀(n : Text) → Text+ , `==` : ∀(m : Bool) → ∀(n : Bool) → Bool+ , `||` : ∀(m : Bool) → ∀(n : Bool) → Bool+ }+, Optional :+ { all : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Bool+ , any : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Bool+ , build :+ ∀(a : Type) →+ ∀ ( build+ : ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ ) →+ Optional a+ , concat : ∀(a : Type) → ∀(x : Optional (Optional a)) → Optional a+ , concatMap :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → Optional b) →+ ∀(o : Optional a) →+ Optional b+ , default : ∀(a : Type) → ∀(default : a) → ∀(o : Optional a) → a+ , equal :+ ∀(a : Type) →+ ∀(compare : a → a → Bool) →+ ∀(ox : Optional a) →+ ∀(oy : Optional a) →+ Bool+ , filter : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Optional a+ , fold :+ ∀(a : Type) →+ ∀(o : Optional a) →+ ∀(optional : Type) →+ ∀(some : a → optional) →+ ∀(none : optional) →+ optional+ , head : ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a+ , last : ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a+ , length : ∀(a : Type) → ∀(xs : Optional a) → Natural+ , map :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(f : a → b) →+ ∀(o : Optional a) →+ Optional b+ , null : ∀(a : Type) → ∀(xs : Optional a) → Bool+ , toList : ∀(a : Type) → ∀(o : Optional a) → List a+ , unzip :+ ∀(a : Type) →+ ∀(b : Type) →+ ∀(xs : Optional { _1 : a, _2 : b }) →+ { _1 : Optional a, _2 : Optional b }+ }+, Text :+ { concat : ∀(xs : List Text) → Text+ , concatMap : ∀(a : Type) → ∀(f : a → Text) → ∀(xs : List a) → Text+ , concatMapSep :+ ∀(separator : Text) →+ ∀(a : Type) →+ ∀(f : a → Text) →+ ∀(elements : List a) →+ Text+ , concatSep : ∀(separator : Text) → ∀(elements : List Text) → Text+ , default : ∀(o : Optional Text) → Text+ , defaultMap : ∀(a : Type) → ∀(f : a → Text) → ∀(o : Optional a) → Text+ , lowerASCII : ∀(nil : Text) → Text+ , replace :+ ∀(needle : Text) → ∀(replacement : Text) → ∀(haystack : Text) → Text+ , replicate : ∀(num : Natural) → ∀(text : Text) → Text+ , shell-escape : ∀(xs : Text) → Text+ , show : Text → Text+ , spaces : ∀(a : Natural) → Text+ , upperASCII : ∀(nil : Text) → Text+ }+, Time : { show : Time → Text }+, TimeZone : { show : TimeZone → Text }+, XML :+ { Type : Type+ , attribute :+ ∀(key : Text) → ∀(value : Text) → { mapKey : Text, mapValue : Text }+ , element :+ ∀ ( elem+ : { attributes : List { mapKey : Text, mapValue : Text }+ , content :+ List+ ( ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes :+ List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ )+ , name : Text+ }+ ) →+ ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ , emptyAttributes : List { mapKey : Text, mapValue : Text }+ , leaf :+ ∀ ( elem+ : { attributes : List { mapKey : Text, mapValue : Text }+ , name : Text+ }+ ) →+ ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ , rawText :+ ∀(d : Text) →+ ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ , render :+ ∀ ( x+ : ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ ) →+ Text+ , text :+ ∀(d : Text) →+ ∀(XML : Type) →+ ∀ ( xml+ : { element :+ { attributes : List { mapKey : Text, mapValue : Text }+ , content : List XML+ , name : Text+ } →+ XML+ , rawText : Text → XML+ , text : Text → XML+ }+ ) →+ XML+ }+}
@@ -0,0 +1,5 @@+let types = { Scopes = < Public | Private > }++let prelude = { types = types }++in prelude.types.Scopes.Public
@@ -0,0 +1,1 @@+< Private | Public >
@@ -0,0 +1,1 @@+{ x = Text, y = List }
@@ -0,0 +1,1 @@+{ x : Type, y : Type → Type }
@@ -0,0 +1,1 @@+let T = 0 in λ(T : Type) → λ(x : T) → 1
@@ -0,0 +1,1 @@+∀(T : Type) → ∀(x : T) → Natural
@@ -0,0 +1,1 @@+(λ(T : Type) → let x = 0 in λ(x : T) → x) : ∀(T : Type) → ∀(x : T) → T
@@ -0,0 +1,1 @@+∀(T : Type) → ∀(x : T) → T
@@ -0,0 +1,1 @@+{ x : { a : Bool } } ⩓ { x : { b : Bool } } ⩓ { x : { c : Bool } }
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+λ(todo : ∀(a : Type) → a) → todo
@@ -0,0 +1,1 @@+∀(todo : ∀(a : Type) → a) → ∀(a : Type) → a
@@ -0,0 +1,1 @@+{ x = Text }.x
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+< Foo : Text | Bar : Natural >.Foo
@@ -0,0 +1,1 @@+∀(Foo : Text) → < Bar : Natural | Foo : Text >
@@ -0,0 +1,5 @@+ let anonymousFunction = λ(a : Type) → List a++in λ(HigherOrderType : (Type → Type) → Type)+ → λ(x : HigherOrderType anonymousFunction)+ → (x : HigherOrderType anonymousFunction)
@@ -0,0 +1,3 @@+ ∀(HigherOrderType : (Type → Type) → Type)+→ ∀(x : HigherOrderType (λ(a : Type) → List a))+→ HigherOrderType (λ(a : Type) → List a)
@@ -0,0 +1,1 @@+{ foo = 1 } ∧ { bar = Text }
@@ -0,0 +1,1 @@+{ bar : Type, foo : Natural }
@@ -0,0 +1,25 @@+let Example =+ { Type = { name : Text, id : Optional Natural }+ , default = { name = "", id = None Natural }+ }++let ExtraFields = Example ∧ { extra = {=} }++let RequiredFields =+ { Type = { name : Text, id : Optional Natural }+ , default = { id = None Natural }+ }++let WrongDefaultType =+ { Type = { name : Text, id : Optional Natural }+ , default = { id = True }+ }++in { example0 = Example::{=}+ , example1 = Example::{ name = "John Doe" }+ , example2 = Example::{ id = Some 0 }+ , example3 = Example::{ name = "Mary Jane", id = Some 0 }+ , example4 = ExtraFields::{=}+ , example5 = RequiredFields::{ name = "Jane Smith" }+ , example6 = WrongDefaultType::{ name = "Bob Roberts", id = Some 0 }+ }
@@ -0,0 +1,8 @@+{ example0 : { id : Optional Natural, name : Text }+, example1 : { id : Optional Natural, name : Text }+, example2 : { id : Optional Natural, name : Text }+, example3 : { id : Optional Natural, name : Text }+, example4 : { id : Optional Natural, name : Text }+, example5 : { id : Optional Natural, name : Text }+, example6 : { id : Optional Natural, name : Text }+}
@@ -0,0 +1,6 @@+let x = Bool+let x = Natural+in \(x: x@1 {- Bool -})+ -> \(x: x@1 {- Natural -})+ -> let x = if x@1 then 0 else 1+ in (x + x@1) : x@3
@@ -0,0 +1,1 @@+∀(x : Bool) → ∀(x : Natural) → Natural
@@ -0,0 +1,1 @@+{ x = Bool, y = Text, z = List }
@@ -0,0 +1,1 @@+{ x : Type, y : Type, z : Type → Type }
@@ -0,0 +1,1 @@+λ(k : Kind) → λ(a : k → k → Type) → λ(x : k) → a x
@@ -0,0 +1,1 @@+∀(k : Kind) → ∀(a : k → k → Type) → ∀(x : k) → k → Type
@@ -0,0 +1,6 @@+let Foo = < Bar : Natural | Baz : Natural >++in λ(a : Type)+ → λ(f : Natural → a)+ → λ(ts : Foo)+ → merge { Bar = λ(a : Natural) → f a, Baz = f } ts
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(f : Natural → a) → ∀(ts : < Bar : Natural | Baz : Natural >) → a
@@ -0,0 +1,9 @@+-- Verify that users can use `.` to both access a record field and a union+-- constructor within the same expression. This is a common idiom if a user+-- provides a types package.++let Scope = < Public | Private >++let types = { Scope = Scope }++in types.Scope.Public
@@ -0,0 +1,1 @@+< Private | Public >
@@ -0,0 +1,15 @@+{- This test caught a regression in the Haskell implementation's typechecker.++ The typechecker was not sorting the fields of a record type inferred from a+ projection, meaning that it inferred that the fully normalized type of+ the subexpression `{ bar = "", foo = "" }.{ foo, bar }` was+ `{ foo : Text, bar : Text }` when according to the standard the inferred type+ should have been `{ bar : Text, foo : Text }`. On top of that the Haskell+ implementation was sensitive to field order, leading to a type mismatch+ when applying a function whose input type had the fields sorted.++ This test ensures that implementations correctly handle order-insensitivity+ when projecting fields and/or comparing types, just in case they are+ order-sensitive like the Haskell implementation.+-}+λ(f : { bar : Text, foo : Text } → Bool) → f { bar = "", foo = "" }.{ foo, bar }
@@ -0,0 +1,1 @@+∀(f : { bar : Text, foo : Text } → Bool) → Bool
@@ -0,0 +1,3 @@+toMap+ { x = Bool }.{}+: List { mapKey : { t = Text }.t, mapValue : { t = Double }.t }
@@ -0,0 +1,1 @@+List { mapKey : Text, mapValue : Double }
@@ -0,0 +1,1 @@+< Left : Type → Type | Right : Type >.Left List
@@ -0,0 +1,1 @@+< Left : Type → Type | Right : Type >
@@ -0,0 +1,1 @@+assert : (\(x: Bool) -> x) === (\(y: Bool) -> y)
@@ -0,0 +1,1 @@+(λ(x : Bool) → x) ≡ (λ(y : Bool) → y)
@@ -0,0 +1,6 @@+{-+ Equivalence must compare the result of the binary encoding, so in+ particular comparing Doubles should not use standard float equality (where+ NaN != NaN).+-}+assert : NaN === NaN
@@ -0,0 +1,1 @@+NaN ≡ NaN
@@ -0,0 +1,1 @@+assert : 1 + 1 === 2
@@ -0,0 +1,1 @@+2 ≡ 2
@@ -0,0 +1,1 @@+assert : 1 === 1
@@ -0,0 +1,1 @@+1 ≡ 1
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+0x"0123456789abcdefABCDEF"
@@ -0,0 +1,1 @@+Bytes
@@ -0,0 +1,1 @@+{ default = {=}, Type = {} }::{=}
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+λ(t : Type) → < t : t >.t
@@ -0,0 +1,1 @@+∀(t : Type) → ∀(t : t) → < t : t@1 >
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+1.0
@@ -0,0 +1,1 @@+Double
@@ -0,0 +1,1 @@+Double/show
@@ -0,0 +1,1 @@+Double → Text
@@ -0,0 +1,1 @@+1 === 2
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+λ(_ : Bool) → _
@@ -0,0 +1,1 @@+(λ(_ : Bool) → _) True
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+List/length (let x = 0 in Bool)
@@ -0,0 +1,1 @@+List Bool → Natural
@@ -0,0 +1,1 @@+(λ(g : Natural → Bool) → assert : g 0 ≡ g 0) Natural/even
@@ -0,0 +1,1 @@+True ≡ True
@@ -0,0 +1,1 @@+Bool → Bool
@@ -0,0 +1,1 @@+λ(x : Bool) → Bool
@@ -0,0 +1,1 @@+∀(x : Bool) → Type
@@ -0,0 +1,1 @@+λ(x : Bool) → Type
@@ -0,0 +1,1 @@+∀(x : Bool) → Kind
@@ -0,0 +1,1 @@+λ(x : Bool) → x
@@ -0,0 +1,1 @@+∀(x : Bool) → Bool
@@ -0,0 +1,1 @@+λ(x : { t = Bool }.t) → x
@@ -0,0 +1,1 @@+∀(x : Bool) → Bool
@@ -0,0 +1,1 @@+Kind → Kind
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+Kind → Bool
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+Kind → Type
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+Bool → Bool
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+Type → Kind
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+Type → Bool
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+Type → Type
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+Type → _
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+if True then False else True
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+if True then (Type -> Type) else Type
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+if True then Bool else Natural
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,9 @@+ if if True then True else True++then if True then False else True++else if True++then True++else True
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+Integer
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+Integer/clamp
@@ -0,0 +1,1 @@+Integer → Natural
@@ -0,0 +1,1 @@++1
@@ -0,0 +1,1 @@+Integer
@@ -0,0 +1,1 @@+Integer/negate
@@ -0,0 +1,1 @@+Integer → Integer
@@ -0,0 +1,1 @@+Integer/show
@@ -0,0 +1,1 @@+Integer → Text
@@ -0,0 +1,1 @@+Integer/toDouble
@@ -0,0 +1,1 @@+Integer → Double
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+let x = True in x
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+let x = Bool let y : x = True in y
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+let x = Bool in True : x
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+let x : Bool = True in x
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+List
@@ -0,0 +1,1 @@+Type → Type
@@ -0,0 +1,1 @@+List/build
@@ -0,0 +1,3 @@+ ∀(a : Type)+→ (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list)+→ List a
@@ -0,0 +1,1 @@+List/fold
@@ -0,0 +1,6 @@+ ∀(a : Type)+→ List a+→ ∀(list : Type)+→ ∀(cons : a → list → list)+→ ∀(nil : list)+→ list
@@ -0,0 +1,1 @@+List/head
@@ -0,0 +1,1 @@+∀(a : Type) → List a → Optional a
@@ -0,0 +1,1 @@+List/indexed
@@ -0,0 +1,1 @@+∀(a : Type) → List a → List { index : Natural, value : a }
@@ -0,0 +1,1 @@+List/last
@@ -0,0 +1,1 @@+∀(a : Type) → List a → Optional a
@@ -0,0 +1,1 @@+List/length
@@ -0,0 +1,1 @@+∀(a : Type) → List a → Natural
@@ -0,0 +1,1 @@+[] : List Bool
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+[] : { x = List Bool }.x
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+[ if True then False else True ]
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+[ True ]
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+List/reverse
@@ -0,0 +1,1 @@+∀(a : Type) → List a → List a
@@ -0,0 +1,1 @@+merge { x = 1 } < x >.x
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+λ(x : <>) → merge {=} x : Bool
@@ -0,0 +1,1 @@+∀(x : <>) → Bool
@@ -0,0 +1,1 @@+merge { None = False, Some = \(b : Bool) -> b } (None Bool)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+merge { x = λ(_ : Bool) → _ } (< x : Bool >.x True)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+merge { x = 5 } < x >.x
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+merge { x = λ(_ : Bool) → _ } (< x : Bool >.x True) : Bool
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+merge { x = λ(y : Bool) → y } < x >.x : (∀(y : Bool) → Bool)
@@ -0,0 +1,1 @@+∀(y : Bool) → Bool
@@ -0,0 +1,1 @@+λ(x : Optional Bool) → merge { None = 0, Some = λ(_ : Bool) → 1 } x
@@ -0,0 +1,1 @@+∀(x : Optional Bool) → Natural
@@ -0,0 +1,1 @@+merge { None = False, Some = \(b : Bool) -> b } (Some True)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+let _ = Bool in merge {_ = \(x: _) -> x} (<_: Bool>._ True)
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+Natural/build
@@ -0,0 +1,6 @@+ ( ∀(natural : Type)+ → ∀(succ : natural → natural)+ → ∀(zero : natural)+ → natural+ )+→ Natural
@@ -0,0 +1,1 @@+Natural/even
@@ -0,0 +1,1 @@+Natural → Bool
@@ -0,0 +1,1 @@+Natural/fold
@@ -0,0 +1,5 @@+ Natural+→ ∀(natural : Type)+→ ∀(succ : natural → natural)+→ ∀(zero : natural)+→ natural
@@ -0,0 +1,1 @@+Natural/isZero
@@ -0,0 +1,1 @@+Natural → Bool
@@ -0,0 +1,1 @@+1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+Natural/odd
@@ -0,0 +1,1 @@+Natural → Bool
@@ -0,0 +1,1 @@+Natural/show
@@ -0,0 +1,1 @@+Natural → Text
@@ -0,0 +1,1 @@+Natural/subtract
@@ -0,0 +1,1 @@+Natural → Natural → Natural
@@ -0,0 +1,1 @@+Natural/toInteger
@@ -0,0 +1,1 @@+Natural → Integer
@@ -0,0 +1,1 @@+None
@@ -0,0 +1,1 @@+∀(A : Type) → Optional A
@@ -0,0 +1,1 @@+True && False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True && False && False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True == False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True == False == False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+[ True ] # [ True ]
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+(if True then [ True ] else [ False ]) # (if True then [ True ] else [ False ])
@@ -0,0 +1,1 @@+List Bool
@@ -0,0 +1,1 @@+True != False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True != False != False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True || False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+True || False || False
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+1 + 1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+1 + 1 + (1 + 1)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+"a" ++ "b"
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+"x" ++ "a" ++ ("y" ++ "b")
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+1 * 1
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+1 * 1 * (1 * 1)
@@ -0,0 +1,1 @@+Natural
@@ -0,0 +1,1 @@+Optional
@@ -0,0 +1,1 @@+Type → Type
@@ -0,0 +1,1 @@+{=}
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+{ x.y.z = 1 }
@@ -0,0 +1,1 @@+{ x : { y : { z : Natural } } }
@@ -0,0 +1,14 @@+{- This example verifies that a Dhall interpreter correctly handles a corner+ case that other languages sometimes misbehave on++ The expression should desugar like this:++ λ(r : { z : Natural }) → { x.y = 1, x = r }++ λ(r : { z : Natural }) → { x = { y = 1 }, x = r }++ λ(r : { z : Natural }) → { x = { y = 1 } ∧ r }++ ... which type-checks since `{ y = 1 }` and `r` do not collide+-}+λ(r : { z : Natural }) → { x.y = 1, x = r }
@@ -0,0 +1,1 @@+∀(r : { z : Natural }) → { x : { y : Natural, z : Natural } }
@@ -0,0 +1,12 @@+{- This test illustrates that duplicate fields need not be literals in order+ to be properly normalized. One or both of the duplicate fields can be+ abstract because field duplication delegates its behavior to the ∧ operator++ This particular example succeeds because it desugars to:++ λ(r : { z : Natural }) → { x = { y = 1 } ∧ r }++ ... and the `∧` operator can infer the absence of conflicts due to knowing+ the type of `r`+-}+λ(r : { z : Natural }) → { x = { y = 1 }, x = r }
@@ -0,0 +1,1 @@+∀(r : { z : Natural }) → { x : { y : Natural, z : Natural } }
@@ -0,0 +1,12 @@+{- This type-checks because the expression desugars to:++ { x = { y = 0 } ∧ { z = 0 } }++ ... which in turn type-checks due to the absence of a field collision.++ This expression is analogous to the following common Nix/TOML/Cue idiom,+ which we would like to support:++ { x.y = 0, x.z = 0 }+-}+{ x = { y = 0 }, x = { z = 0 } }
@@ -0,0 +1,1 @@+{ x : { y : Natural, z : Natural } }
@@ -0,0 +1,1 @@+{ x = True : { t = Bool }.t }
@@ -0,0 +1,1 @@+{ x : Bool }
@@ -0,0 +1,1 @@+\(x: Bool) -> { x }
@@ -0,0 +1,1 @@+∀(x : Bool) → { x : Bool }
@@ -0,0 +1,1 @@+\(x: Bool) -> \(x: Natural) -> { x }
@@ -0,0 +1,1 @@+∀(x : Bool) → ∀(x : Natural) → { x : Natural }
@@ -0,0 +1,1 @@+let `None` = 0 let `Some` = \(_: Bool) -> 1 in { None, Some }
@@ -0,0 +1,1 @@+{ None : Natural, Some : Bool → Natural }
@@ -0,0 +1,1 @@+{ b = 1, a = 2 }
@@ -0,0 +1,1 @@+{ a : Natural, b : Natural }
@@ -0,0 +1,1 @@+{ x = Type, y = {} }
@@ -0,0 +1,1 @@+{ x : Kind, y : Type }
@@ -0,0 +1,1 @@+{ x = {=}, y = Bool }
@@ -0,0 +1,1 @@+{ x : {}, y : Type }
@@ -0,0 +1,1 @@+{ a = { b = Type } }
@@ -0,0 +1,1 @@+{ a : { b : Kind } }
@@ -0,0 +1,1 @@+{ a = { b = Type → Type } }
@@ -0,0 +1,1 @@+{ a : { b : Kind } }
@@ -0,0 +1,1 @@+{ a = { b = Bool } }
@@ -0,0 +1,1 @@+{ a : { b : Type } }
@@ -0,0 +1,1 @@+{ a = { b = Bool → Bool } }
@@ -0,0 +1,1 @@+{ a : { b : Type } }
@@ -0,0 +1,1 @@+{ x = Type }
@@ -0,0 +1,1 @@+{ x : Kind }
@@ -0,0 +1,1 @@+{ x = {} }
@@ -0,0 +1,1 @@+{ x : Type }
@@ -0,0 +1,1 @@+{ x = {=} }
@@ -0,0 +1,1 @@+{ x : {} }
@@ -0,0 +1,1 @@+let e = { a = 10, b = "Text" } let s = { a : Natural } in e.(s)
@@ -0,0 +1,1 @@+{ a : Natural }
@@ -0,0 +1,1 @@+let e = { a = 10, b = "Text" } let s = { } in e.(s)
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,5 @@+-- This tests that we prefer the type from the selector over the inferred field+-- type from the record+-- ie the result should be `{ a : Natural → Natural }`+-- not `{ a : ∀(x : Natural) → Natural }`+let e = { a = λ(x : Natural) → x } let s = { a : Natural → Natural } in e.(s)
@@ -0,0 +1,1 @@+{ a : Natural → Natural }
@@ -0,0 +1,1 @@+{ x = {=} }.{}
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+{ x = Type }.{}
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+{ x = Type, y = Type }.{ x }
@@ -0,0 +1,1 @@+{ x : Kind }
@@ -0,0 +1,1 @@+{ x = Bool, y = Natural }.{ x }
@@ -0,0 +1,1 @@+{ x : Type }
@@ -0,0 +1,1 @@+{ x = {=}, y = {=} }.{ x }
@@ -0,0 +1,1 @@+{ x : {} }
@@ -0,0 +1,1 @@+{ x = Type }.x
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{ x = {} }.x
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x = {=} }.x
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+{ x : Bool }
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{}
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x : Kind }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ a : Kind → Kind }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : Kind, y : Type }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : Kind, y : Bool }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : Bool, y : Type }
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{ a : { b : Kind } }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ a : { b : Kind → Kind } }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : Type }
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{ x : Bool } ⩓ { y : Type }
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{=} ∧ { x = True }
@@ -0,0 +1,1 @@+{ x : Bool }
@@ -0,0 +1,1 @@+{ x = True } ∧ { y = Bool }
@@ -0,0 +1,1 @@+{ x : Bool, y : Type }
@@ -0,0 +1,1 @@+{ x = { a = True } } ∧ { x = { b = True } }
@@ -0,0 +1,1 @@+{ x : { a : Bool, b : Bool } }
@@ -0,0 +1,1 @@+{ x = { a = Type } } ∧ { x = { b = Type } }
@@ -0,0 +1,1 @@+{ x : { a : Kind, b : Kind } }
@@ -0,0 +1,1 @@+{ x = { a = Bool } } ∧ { x = { b = Natural } }
@@ -0,0 +1,1 @@+{ x : { a : Type, b : Type } }
@@ -0,0 +1,1 @@+{ x = True } ∧ {=}
@@ -0,0 +1,1 @@+{ x : Bool }
@@ -0,0 +1,1 @@+{ x = True } ∧ { y = True }
@@ -0,0 +1,1 @@+{ x : Bool, y : Bool }
@@ -0,0 +1,1 @@+{ x = Type } ∧ { y = Type }
@@ -0,0 +1,1 @@+{ x : Kind, y : Kind }
@@ -0,0 +1,1 @@+{ x = Bool } ∧ { y = Natural }
@@ -0,0 +1,1 @@+{ x : Type, y : Type }
@@ -0,0 +1,1 @@+{ a : { b : { x : Bool } } } ⩓ { a : { b : { y : Bool } } }
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x : { a : Bool } } ⩓ { y : { b : Bool } }
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x : { a : Kind } } ⩓ { y : { b : Kind } }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : { a : Type } } ⩓ { y : { b : Type } }
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{ x : Bool } ⩓ {}
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x : Bool } ⩓ { y : Bool }
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+{ x : Kind } ⩓ { y : Kind }
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+{ x : Type } ⩓ { y : Type }
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+{ x = {=} } ⫽ { x = Bool }
@@ -0,0 +1,1 @@+{ x : Type }
@@ -0,0 +1,1 @@+{ x = {=} } ⫽ {=}
@@ -0,0 +1,1 @@+{ x : {} }
@@ -0,0 +1,1 @@+{ x = {=} } ⫽ { x = {=} }
@@ -0,0 +1,1 @@+{ x : {} }
@@ -0,0 +1,1 @@+{ x = {=} } ⫽ { x = True }
@@ -0,0 +1,1 @@+{ x : Bool }
@@ -0,0 +1,1 @@+{ x = Type } ⫽ { x = Type }
@@ -0,0 +1,1 @@+{ x : Kind }
@@ -0,0 +1,1 @@+{ x = Bool } ⫽ { x = Natural }
@@ -0,0 +1,1 @@+{ x : Type }
@@ -0,0 +1,1 @@+showConstructor <A>.A
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+showConstructor (< A : Bool>.A False)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+showConstructor (Some 0)
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+Some True
@@ -0,0 +1,1 @@+Optional Bool
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+"a"
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+"a${if True then "a" else "b"}"
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+"a${"b"}"
@@ -0,0 +1,1 @@+Text
@@ -0,0 +1,1 @@+Text/replace
@@ -0,0 +1,1 @@+∀(needle : Text) → ∀(replacement : Text) → ∀(haystack : Text) → Text
@@ -0,0 +1,1 @@+Text/show
@@ -0,0 +1,1 @@+Text → Text
@@ -0,0 +1,1 @@+toMap { foo= 1, bar= 4, baz= 9 }
@@ -0,0 +1,1 @@+toMap { foo = 1, bar = 4, baz = 9 } : List { mapKey : Text, mapValue : Natural }
@@ -0,0 +1,1 @@+List { mapKey : Text, mapValue : Natural }
@@ -0,0 +1,1 @@+List { mapKey : Text, mapValue : Natural }
@@ -0,0 +1,1 @@+toMap { x = λ(x : Bool) → x } : List { mapKey : Text, mapValue : ∀(x : Bool) → Bool }
@@ -0,0 +1,1 @@+List { mapKey : Text, mapValue : ∀(x : Bool) → Bool }
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+True : Bool
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+(λ(x : Bool) → x) : ∀(x : Bool) → Bool
@@ -0,0 +1,1 @@+∀(x : Bool) → Bool
@@ -0,0 +1,1 @@+True : { x = Bool }.x
@@ -0,0 +1,1 @@+Bool
@@ -0,0 +1,1 @@+Kind : Sort
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+< x | y : Bool >.x
@@ -0,0 +1,1 @@+< x | y : Bool >
@@ -0,0 +1,1 @@+< x : Bool >.x
@@ -0,0 +1,1 @@+∀(x : Bool) → < x : Bool >
@@ -0,0 +1,1 @@+<>
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+< x : Kind >
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+< x : Kind | y : Type >
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+< x : Kind | y : Bool >
@@ -0,0 +1,1 @@+Sort
@@ -0,0 +1,1 @@+< x : Bool | y : Type >
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+< x : Bool | y | z : Type >
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,1 @@+< x : Bool >
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+< x : Type >
@@ -0,0 +1,1 @@+Kind
@@ -0,0 +1,3 @@+{- This test illustrates that if an intermediate record does+ not exist, the `with` operator can create one -}+{ a = 5 } with b.c = 10
@@ -0,0 +1,1 @@+{ a : Natural, b : { c : Natural } }
@@ -0,0 +1,1 @@+Some ({ x = Bool } with x = 0)
@@ -0,0 +1,1 @@+Optional { x : Natural }
@@ -0,0 +1,4 @@+{- This test illustrates that the `with` keyword is permitted to override+ existing fields nested within a child record+-}+{ a = { p = 2, q = "hi" }, b = 5.6 } with a.p = True
@@ -0,0 +1,1 @@+{ a : { p : Bool, q : Text }, b : Double }
@@ -0,0 +1,4 @@+{- This test illustrates how the `with` keyword is permitted to extend a record+ with new fields+-}+{ a = 1 } with b = 2
@@ -0,0 +1,1 @@+{ a : Natural, b : Natural }
@@ -0,0 +1,4 @@+{- This test illustrates that the `with` keyword is permitted to override+ existing fields with a value of a new type (just like the `//` operator)+-}+{ a = 1 } with a = True
@@ -0,0 +1,1 @@+{ a : Bool }
@@ -0,0 +1,1 @@+(Some 0) with ? = 1
@@ -0,0 +1,1 @@+Optional Natural
@@ -0,0 +1,1 @@+Date
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+2000-01-01
@@ -0,0 +1,1 @@+Date
@@ -0,0 +1,1 @@+2000-01-01T12:00:00
@@ -0,0 +1,1 @@+{ date : Date, time : Time }
@@ -0,0 +1,1 @@+2000-01-01T12:00:00+08:00
@@ -0,0 +1,1 @@+{ date : Date, time : Time, timeZone : TimeZone }
@@ -0,0 +1,1 @@+Time
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@+12:00:00
@@ -0,0 +1,1 @@+Time
@@ -0,0 +1,1 @@+12:00:00+08:00
@@ -0,0 +1,1 @@+{ time : Time, timeZone : TimeZone }
@@ -0,0 +1,1 @@+TimeZone
@@ -0,0 +1,1 @@+Type
@@ -0,0 +1,1 @@++08:00
@@ -0,0 +1,1 @@+TimeZone
@@ -1,3 +0,0 @@--- This file contains a free variable. This should be a type error, even if the variable--- is in scope in the importing expression-x
@@ -1,1 +0,0 @@-{ foo = 1 } ∧ { bar = Text }
@@ -1,15 +0,0 @@-{- This is a type error because the custom headers are type-checked with an- empty context. This is necessary because:-- * import resolution precedes β-normalization- * we also don't want custom headers to leak program state anyway-- This should fail due to the `x` within the custom header being an unbound- variable--}--let x = "Bar"--in https://httpbin.org/headers- using [ { header = "Foo", value = x } ]- as Text
@@ -1,1 +0,0 @@-{ a = 1, a = 2 }
@@ -1,49 +0,0 @@- let bottom : Type = ∀(any : Type) → any--in let not : Type → Type = λ(p : Type) → p → bottom--in let pow = λ(X : Kind) → X → Type--in let U = ∀(X : Kind) → (pow (pow X) → X) → pow (pow X)--in let tau- : pow (pow U) → U- = λ(t : pow (pow U))- → λ(X : Kind)- → λ(f : pow (pow X) → X)- → λ(p : pow X)- → t (λ(x : U) → p (f (x X f)))--in let sigma : U → pow (pow U) = λ(s : U) → s U (λ(t : pow (pow U)) → tau t)--in let Delta- : pow U- = λ(y : U) → not (∀(p : pow U) → sigma y p → p (tau (sigma y)))--in let Omega : U = tau (λ(p : pow U) → ∀(x : U) → sigma x p → p x)--in let Theta : Type = ∀(p : pow U) → (∀(x : U) → sigma x p → p x) → p Omega--in let D : Type = ∀(p : pow U) → sigma Omega p → p (tau (sigma Omega))--in let lem1- : ∀(p : pow U) → (∀(x : U) → sigma x p → p x) → p Omega- = λ(p : pow U)- → λ(t1 : ∀(x : U) → sigma x p → p x)- → t1 Omega (λ(x : U) → t1 (tau (sigma x)))--in let lem3 : D = λ(p : pow U) → lem1 (λ(y : U) → p (tau (sigma y)))--in let lem2- : not D- = lem1- Delta- ( λ(x : U)- → λ(H2 : sigma x Delta)- → λ(H3 : ∀(p : pow U) → sigma x p → p (tau (sigma x)))- → H3 Delta H2 (λ(pp : pow U) → H3 (λ(y : U) → pp (tau (sigma y))))- )--in let evidence : bottom = lem2 lem3--in evidence
@@ -1,1 +0,0 @@-\(x: Bool) -> ../data/importBoundary.dhall
@@ -1,1 +0,0 @@-< Left : Natural | Right : Type >
@@ -1,1 +0,0 @@-{ foo = 1 } ⫽ { bar = Text }
@@ -1,4 +0,0 @@- λ ( record- : ∀(k : Kind) → ∀(makeRecord : ∀(x : Type) → ∀(y : Type → Type) → k) → k- )-→ record Type (λ(x : Type) → λ(y : Type → Type) → x)
@@ -1,4 +0,0 @@- ∀ ( record- : ∀(k : Kind) → ∀(makeRecord : ∀(x : Type) → ∀(y : Type → Type) → k) → k- )-→ Type
@@ -1,1 +0,0 @@-λ(record : { x : Type, y : Type → Type }) → record.x
@@ -1,1 +0,0 @@-∀(record : { x : Type, y : Type → Type }) → Type
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/and [ True, False, True ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/and ([] : List Bool)
@@ -1,1 +0,0 @@-Bool
@@ -1,2 +0,0 @@-../../../../../../Prelude/Bool/build -(λ(bool : Type) → λ(true : bool) → λ(false : bool) → true)
@@ -1,1 +0,0 @@-Bool
@@ -1,2 +0,0 @@-../../../../../../Prelude/Bool/build -(λ(bool : Type) → λ(true : bool) → λ(false : bool) → false)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False, True, False ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False, True ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even [ False ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/even ([] : List Bool)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/fold True Natural 0 1
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/fold False Natural 0 1
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/not True
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/not False
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True, False, True ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True, False ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd [ True ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/odd ([] : List Bool)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/or [ True, False, True ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/or ([] : List Bool)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/show True
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Bool/show False
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Double/show -3.1
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Double/show 0.4
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/show -3
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/show +0
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/toDouble -3
@@ -1,1 +0,0 @@-Double
@@ -1,1 +0,0 @@-../../../../../../Prelude/Integer/toDouble +2
@@ -1,1 +0,0 @@-Double
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/all Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/all Natural Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/any Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/any Natural Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ cons "ABC" (cons "DEF" nil)-)
@@ -1,1 +0,0 @@-List Text
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/build-Text-( λ(list : Type)-→ λ(cons : Text → list → list)-→ λ(nil : list)-→ nil-)
@@ -1,1 +0,0 @@-List Text
@@ -1,5 +0,0 @@-../../../../../../Prelude/List/concat Natural-[ [ 0, 1, 2 ]-, [ 3, 4 ]-, [ 5, 6, 7, 8 ]-]
@@ -1,1 +0,0 @@-List Natural
@@ -1,5 +0,0 @@-../../../../../../Prelude/List/concat Natural-[ [] : List Natural-, [] : List Natural-, [] : List Natural-]
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/concatMap Natural Natural (λ(n : Natural) → [ n, n ]) ([] : List Natural)
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/filter Natural Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/filter Natural Natural/odd [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-List Natural
@@ -1,6 +0,0 @@-../../../../../../Prelude/List/fold-Natural-[ 2, 3, 5 ]-Natural-(λ(x : Natural) → λ(y : Natural) → x + y)-0
@@ -1,1 +0,0 @@-Natural
@@ -1,7 +0,0 @@- λ(nil : Natural)-→ ../../../../../../Prelude/List/fold- Natural- [ 2, 3, 5 ]- Natural- (λ(x : Natural) → λ(y : Natural) → x + y)- nil
@@ -1,1 +0,0 @@-∀(nil : Natural) → Natural
@@ -1,4 +0,0 @@- λ(list : Type)-→ λ(cons : Natural → list → list)-→ λ(nil : list)-→ ../../../../../../Prelude/List/fold Natural [ 2, 3, 5 ] list cons nil
@@ -1,1 +0,0 @@-∀(list : Type) → ∀(cons : Natural → list → list) → ∀(nil : list) → list
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/generate 5 Bool Natural/even
@@ -1,1 +0,0 @@-List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/generate 0 Bool Natural/even
@@ -1,1 +0,0 @@-List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/head Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/head Natural ([] : List Natural)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/indexed Bool [ True, False, True ]
@@ -1,1 +0,0 @@-List { index : Natural, value : Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/indexed Bool ([] : List Bool)
@@ -1,1 +0,0 @@-List { index : Natural, value : Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/iterate 10 Natural (λ(x : Natural) → x * 2) 1
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/iterate 0 Natural (λ(x : Natural) → x * 2) 1
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/last Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/last Natural ([] : List Natural)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/length Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/length Natural ([] : List Natural)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/map Natural Bool Natural/even [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/map Natural Bool Natural/even ([] : List Natural)
@@ -1,1 +0,0 @@-List Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/null Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/null Natural ([] : List Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/replicate 9 Natural 1
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/replicate 0 Natural 1
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/reverse Natural [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/reverse Natural ([] : List Natural)
@@ -1,1 +0,0 @@-List Natural
@@ -1,15 +0,0 @@-../../../../../../Prelude/List/shifted-Bool-[ [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = False }- ]-, [ { index = 0, value = False }- , { index = 1, value = False }- ]-, [ { index = 0, value = True }- , { index = 1, value = True }- , { index = 2, value = True }- , { index = 3, value = True }- ]-]
@@ -1,1 +0,0 @@-List { index : Natural, value : Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/shifted Bool ([] : List (List { index : Natural, value : Bool }))
@@ -1,1 +0,0 @@-List { index : Natural, value : Bool }
@@ -1,7 +0,0 @@-../../../../../../Prelude/List/unzip-Text-Bool-[ { _1 = "ABC", _2 = True }-, { _1 = "DEF", _2 = False }-, { _1 = "GHI", _2 = True }-]
@@ -1,1 +0,0 @@-{ _1 : List Text, _2 : List Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/List/unzip Text Bool ([] : List { _1 : Text, _2 : Bool })
@@ -1,1 +0,0 @@-{ _1 : List Text, _2 : List Bool }
@@ -1,1 +0,0 @@-../../../../../Prelude/Bool/and
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Bool
@@ -1,1 +0,0 @@-../../../../../Prelude/Bool/or
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Bool
@@ -1,1 +0,0 @@-../../../../../Prelude/Bool/even
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Bool
@@ -1,1 +0,0 @@-../../../../../Prelude/Bool/odd
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Bool
@@ -1,1 +0,0 @@-../../../../../Prelude/List/concat
@@ -1,1 +0,0 @@-∀(a : Type) → ../../../../../Prelude/Monoid (List a)
@@ -1,1 +0,0 @@-../../../../../Prelude/List/shifted
@@ -1,1 +0,0 @@-∀(a : Type) → ../../../../../Prelude/Monoid (List { index : Natural, value : a })
@@ -1,1 +0,0 @@-../../../../../Prelude/Natural/sum
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Natural
@@ -1,1 +0,0 @@-../../../../../Prelude/Natural/product
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Natural
@@ -1,1 +0,0 @@-../../../../../Prelude/Optional/head
@@ -1,1 +0,0 @@-∀(a : Type) → ../../../../../Prelude/Monoid (Optional a)
@@ -1,1 +0,0 @@-../../../../../Prelude/Optional/last
@@ -1,1 +0,0 @@-∀(a : Type) → ../../../../../Prelude/Monoid (Optional a)
@@ -1,1 +0,0 @@-../../../../../Prelude/Text/concat
@@ -1,1 +0,0 @@-../../../../../Prelude/Monoid Text
@@ -1,6 +0,0 @@-../../../../../../Prelude/Natural/build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ succ (succ (succ zero))-)
@@ -1,1 +0,0 @@-Natural
@@ -1,6 +0,0 @@-../../../../../../Prelude/Natural/build-( λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ zero-)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/enumerate 10
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/enumerate 0
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/even 3
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/even 0
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) 1
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-λ(zero : Natural) → ../../../../../../Prelude/Natural/fold 3 Natural (λ(x : Natural) → 5 * x) zero
@@ -1,1 +0,0 @@-∀(zero : Natural) → Natural
@@ -1,4 +0,0 @@- λ(natural : Type)-→ λ(succ : natural → natural)-→ λ(zero : natural)-→ ../../../../../../Prelude/Natural/fold 3 natural succ zero
@@ -1,1 +0,0 @@-∀(natural : Type) → ∀(succ : natural → natural) → ∀(zero : natural) → natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/isZero 2
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/isZero 0
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/odd 3
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/odd 0
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/product [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/product ([] : List Natural)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/show 3
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/show 0
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/sum [ 2, 3, 5 ]
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/sum ([] : List Natural)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toDouble 3
@@ -1,1 +0,0 @@-Double
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toDouble 0
@@ -1,1 +0,0 @@-Double
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toInteger 3
@@ -1,1 +0,0 @@-Integer
@@ -1,1 +0,0 @@-../../../../../../Prelude/Natural/toInteger 0
@@ -1,1 +0,0 @@-Integer
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/all Natural Natural/even (Some 3)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/all Natural Natural/even (None Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/any Natural Natural/even (Some 2)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/any Natural Natural/even (None Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,7 +0,0 @@-../../../../../../Prelude/Optional/build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ some 1-)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,7 +0,0 @@-../../../../../../Prelude/Optional/build-Natural-( λ(optional : Type)-→ λ(some : Natural → optional)-→ λ(none : optional)-→ none-)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (Some (Some 1))
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (Some (None Natural))
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/concat Natural (None (Optional Natural))
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/filter Natural Natural/even (Some 2)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/filter Natural Natural/odd (Some 2)
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/fold Natural (Some 2) Natural (λ(x : Natural) → x) 0
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/fold Natural (None Natural) Natural (λ(x : Natural) → x) 0
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural [ None Natural, Some 1, Some 2 ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural [ None Natural, None Natural ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/head Natural ([] : List (Optional Natural))
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural [ None Natural, Some 1, Some 2 ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural [ None Natural, None Natural ]
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/last Natural ([] : List (Optional Natural))
@@ -1,1 +0,0 @@-Optional Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/length Natural (Some 2)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/length Natural (None Natural)
@@ -1,1 +0,0 @@-Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/map Natural Bool Natural/even (Some 3)
@@ -1,1 +0,0 @@-Optional Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/map Natural Bool Natural/even (None Natural)
@@ -1,1 +0,0 @@-Optional Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/null Natural (Some 2)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/null Natural (None Natural)
@@ -1,1 +0,0 @@-Bool
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/toList Natural (Some 1)
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/toList Natural (None Natural)
@@ -1,1 +0,0 @@-List Natural
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/unzip Text Bool (Some { _1 = "ABC", _2 = True })
@@ -1,1 +0,0 @@-{ _1 : Optional Text, _2 : Optional Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/Optional/unzip Text Bool (None { _1 : Text, _2 : Bool })
@@ -1,1 +0,0 @@-{ _1 : Optional Text, _2 : Optional Bool }
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concat [ "ABC", "DEF", "GHI" ]
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concat ([] : List Text)
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMap Natural (λ(n : Natural) → "${Natural/show n} ") ([] : List Natural)
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show [ 0, 1, 2 ]
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatMapSep ", " Natural Natural/show ([] : List Natural)
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatSep ", " [ "ABC", "DEF", "GHI" ]
@@ -1,1 +0,0 @@-Text
@@ -1,1 +0,0 @@-../../../../../../Prelude/Text/concatSep ", " ([] : List Text)
@@ -1,1 +0,0 @@-Text
@@ -1,5 +0,0 @@-let types = { Scopes = < Public | Private > }--let prelude = { types = types }--in prelude.types.Scopes.Public
@@ -1,1 +0,0 @@-< Public | Private >
@@ -1,1 +0,0 @@-{ x = Text, y = List }
@@ -1,1 +0,0 @@-{ x : Type, y : Type → Type }
@@ -1,1 +0,0 @@-{ x = Text }.x
@@ -1,1 +0,0 @@-Type
@@ -1,1 +0,0 @@-< Foo : Text | Bar : Natural >.Foo
@@ -1,1 +0,0 @@-∀(Foo : Text) → < Bar : Natural | Foo : Text >
@@ -1,5 +0,0 @@- let anonymousFunction = λ(a : Type) → List a--in λ(HigherOrderType : (Type → Type) → Type)- → λ(x : HigherOrderType anonymousFunction)- → (x : HigherOrderType anonymousFunction)
@@ -1,4 +0,0 @@- ∀(HigherOrderType : (Type → Type) → Type)-→ ∀(x : HigherOrderType (λ(a : Type) → List a))-→ HigherOrderType (λ(a : Type) → List a)-
@@ -1,6 +0,0 @@-let x = Bool-let x = Natural-in \(x: x@1 {- Bool -})- -> \(x: x@1 {- Natural -})- -> let x = if x@1 then 0 else 1- in (x + x@1) : x@3
@@ -1,1 +0,0 @@-∀(x : Bool) → ∀(x : Natural) → Natural
@@ -1,1 +0,0 @@-{ x = Bool, y = Text, z = List }
@@ -1,1 +0,0 @@-{ x : Type, y : Type, z : Type → Type }
@@ -1,1 +0,0 @@-λ(k : Kind) → λ(a : k → k → Type) → λ(x : k) → a x
@@ -1,1 +0,0 @@-∀(k : Kind) → (k → k → Type) → k → k → Type
@@ -1,6 +0,0 @@-let Foo = < Bar : Natural | Baz : Natural >--in λ(a : Type)- → λ(f : Natural → a)- → λ(ts : Foo)- → merge { Bar = λ(a : Natural) → f a, Baz = f } ts
@@ -1,1 +0,0 @@-∀(a : Type) → ∀(f : Natural → a) → ∀(ts : < Bar : Natural | Baz : Natural >) → a
@@ -1,9 +0,0 @@--- Verify that users can use `.` to both access a record field and a union--- constructor within the same expression. This is a common idiom if a user--- provides a types package.--let Scope = < Public | Private >--let types = { Scope = Scope }--in types.Scope.Public
@@ -1,1 +0,0 @@-< Private | Public >
@@ -1,1 +0,0 @@-< Left : Type → Type | Right : Type >.Left List
@@ -1,1 +0,0 @@-< Left : Type → Type | Right : Type >
@@ -1,13 +1,12 @@+Cabal-Version: 2.4 Name: dhall-Version: 1.24.0-Cabal-Version: >=1.10+Version: 1.42.3 Build-Type: Simple-Tested-With: GHC == 7.10.3, GHC == 8.4.3, GHC == 8.6.1-License: BSD3+License: BSD-3-Clause License-File: LICENSE-Copyright: 2017 Gabriel Gonzalez-Author: Gabriel Gonzalez-Maintainer: Gabriel439@gmail.com+Copyright: 2017 Gabriella Gonzalez+Author: Gabriella Gonzalez+Maintainer: GenuineGabriella@gmail.com Bug-Reports: https://github.com/dhall-lang/dhall-haskell/issues Synopsis: A configuration language guaranteed to terminate Description:@@ -22,11 +21,13 @@ . Read "Dhall.Tutorial" to learn how to use this library Category: Compiler+Data-Files:+ man/dhall.1 Extra-Source-Files:- benchmark/deep-nested-large-record/*.dhall- benchmark/examples/*.dhall- benchmark/examples/normalize/*.dhall CHANGELOG.md+ benchmark/**/*.dhall+ benchmark/**/*.dhallb+ dhall-lang/Prelude/**/*.dhall dhall-lang/Prelude/Bool/and dhall-lang/Prelude/Bool/build dhall-lang/Prelude/Bool/even@@ -34,50 +35,105 @@ dhall-lang/Prelude/Bool/not dhall-lang/Prelude/Bool/odd dhall-lang/Prelude/Bool/or- dhall-lang/Prelude/Bool/package.dhall dhall-lang/Prelude/Bool/show- dhall-lang/Prelude/Double/package.dhall dhall-lang/Prelude/Double/show dhall-lang/Prelude/Function/compose- dhall-lang/Prelude/Function/package.dhall- dhall-lang/Prelude/Integer/package.dhall+ dhall-lang/Prelude/Function/identity+ dhall-lang/Prelude/Integer/abs+ dhall-lang/Prelude/Integer/add+ dhall-lang/Prelude/Integer/clamp+ dhall-lang/Prelude/Integer/equal+ dhall-lang/Prelude/Integer/greaterThan+ dhall-lang/Prelude/Integer/greaterThanEqual+ dhall-lang/Prelude/Integer/lessThan+ dhall-lang/Prelude/Integer/lessThanEqual+ dhall-lang/Prelude/Integer/multiply+ dhall-lang/Prelude/Integer/negate+ dhall-lang/Prelude/Integer/negative+ dhall-lang/Prelude/Integer/nonNegative+ dhall-lang/Prelude/Integer/nonPositive+ dhall-lang/Prelude/Integer/positive dhall-lang/Prelude/Integer/show+ dhall-lang/Prelude/Integer/subtract dhall-lang/Prelude/Integer/toDouble- dhall-lang/Prelude/JSON/keyText- dhall-lang/Prelude/JSON/keyValue+ dhall-lang/Prelude/Integer/toNatural+ dhall-lang/Prelude/JSON/Format dhall-lang/Prelude/JSON/Nesting- dhall-lang/Prelude/JSON/package.dhall dhall-lang/Prelude/JSON/Tagged+ dhall-lang/Prelude/JSON/Type+ dhall-lang/Prelude/JSON/array+ dhall-lang/Prelude/JSON/bool+ dhall-lang/Prelude/JSON/double+ dhall-lang/Prelude/JSON/integer+ dhall-lang/Prelude/JSON/keyText+ dhall-lang/Prelude/JSON/keyValue+ dhall-lang/Prelude/JSON/natural+ dhall-lang/Prelude/JSON/null+ dhall-lang/Prelude/JSON/number+ dhall-lang/Prelude/JSON/object+ dhall-lang/Prelude/JSON/omitNullFields+ dhall-lang/Prelude/JSON/render+ dhall-lang/Prelude/JSON/renderAs+ dhall-lang/Prelude/JSON/renderYAML+ dhall-lang/Prelude/JSON/string+ dhall-lang/Prelude/JSON/tagInline+ dhall-lang/Prelude/JSON/tagNested dhall-lang/Prelude/List/all dhall-lang/Prelude/List/any dhall-lang/Prelude/List/build dhall-lang/Prelude/List/concat dhall-lang/Prelude/List/concatMap+ dhall-lang/Prelude/List/default+ dhall-lang/Prelude/List/drop+ dhall-lang/Prelude/List/empty dhall-lang/Prelude/List/filter dhall-lang/Prelude/List/fold dhall-lang/Prelude/List/generate dhall-lang/Prelude/List/head+ dhall-lang/Prelude/List/index dhall-lang/Prelude/List/indexed dhall-lang/Prelude/List/iterate dhall-lang/Prelude/List/last dhall-lang/Prelude/List/length dhall-lang/Prelude/List/map dhall-lang/Prelude/List/null- dhall-lang/Prelude/List/package.dhall+ dhall-lang/Prelude/List/partition dhall-lang/Prelude/List/replicate dhall-lang/Prelude/List/reverse dhall-lang/Prelude/List/shifted+ dhall-lang/Prelude/List/take+ dhall-lang/Prelude/List/unpackOptionals dhall-lang/Prelude/List/unzip+ dhall-lang/Prelude/List/zip+ dhall-lang/Prelude/Location/Type+ dhall-lang/Prelude/Map/Entry+ dhall-lang/Prelude/Map/Type+ dhall-lang/Prelude/Map/empty+ dhall-lang/Prelude/Map/keyText+ dhall-lang/Prelude/Map/keyValue+ dhall-lang/Prelude/Map/keys+ dhall-lang/Prelude/Map/map+ dhall-lang/Prelude/Map/values dhall-lang/Prelude/Monoid dhall-lang/Prelude/Natural/build dhall-lang/Prelude/Natural/enumerate+ dhall-lang/Prelude/Natural/equal dhall-lang/Prelude/Natural/even dhall-lang/Prelude/Natural/fold+ dhall-lang/Prelude/Natural/greaterThan+ dhall-lang/Prelude/Natural/greaterThanEqual dhall-lang/Prelude/Natural/isZero+ dhall-lang/Prelude/Natural/lessThan+ dhall-lang/Prelude/Natural/lessThanEqual+ dhall-lang/Prelude/Natural/listMax+ dhall-lang/Prelude/Natural/listMin+ dhall-lang/Prelude/Natural/max+ dhall-lang/Prelude/Natural/min dhall-lang/Prelude/Natural/odd- dhall-lang/Prelude/Natural/package.dhall dhall-lang/Prelude/Natural/product dhall-lang/Prelude/Natural/show+ dhall-lang/Prelude/Natural/sort+ dhall-lang/Prelude/Natural/subtract dhall-lang/Prelude/Natural/sum dhall-lang/Prelude/Natural/toDouble dhall-lang/Prelude/Natural/toInteger@@ -85,6 +141,7 @@ dhall-lang/Prelude/Optional/any dhall-lang/Prelude/Optional/build dhall-lang/Prelude/Optional/concat+ dhall-lang/Prelude/Optional/default dhall-lang/Prelude/Optional/filter dhall-lang/Prelude/Optional/fold dhall-lang/Prelude/Optional/head@@ -92,285 +149,34 @@ dhall-lang/Prelude/Optional/length dhall-lang/Prelude/Optional/map dhall-lang/Prelude/Optional/null- dhall-lang/Prelude/Optional/package.dhall dhall-lang/Prelude/Optional/toList dhall-lang/Prelude/Optional/unzip- dhall-lang/Prelude/package.dhall dhall-lang/Prelude/Text/concat dhall-lang/Prelude/Text/concatMap dhall-lang/Prelude/Text/concatMapSep dhall-lang/Prelude/Text/concatSep- dhall-lang/Prelude/Text/package.dhall+ dhall-lang/Prelude/Text/default+ dhall-lang/Prelude/Text/defaultMap+ dhall-lang/Prelude/Text/replicate dhall-lang/Prelude/Text/show- dhall-lang/tests/binary-decode/success/unit/*.dhall- dhall-lang/tests/binary-decode/success/unit/*.dhallb- dhall-lang/tests/import/data/*.txt- dhall-lang/tests/import/data/*.dhall- dhall-lang/tests/import/data/fieldOrder/*.dhall- dhall-lang/tests/import/failure/*.dhall- dhall-lang/tests/import/success/*.dhall- dhall-lang/tests/normalization/success/*.dhall- dhall-lang/tests/normalization/success/haskell-tutorial/access/*.dhall- dhall-lang/tests/normalization/success/haskell-tutorial/combineTypes/*.dhall- dhall-lang/tests/normalization/success/haskell-tutorial/prefer/*.dhall- dhall-lang/tests/normalization/success/haskell-tutorial/projection/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/and/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/and/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/even/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/even/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/not/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/not/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/odd/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/odd/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/or/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/or/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Bool/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Double/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Double/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Integer/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Integer/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/*.dhall- dhall-lang/tests/normalization/success/prelude/Integer/toDouble/*.dhall- dhall-lang/tests/normalization/success/prelude/List/all/*.dhall- dhall-lang/tests/normalization/success/prelude/List/all/*.dhall- dhall-lang/tests/normalization/success/prelude/List/any/*.dhall- dhall-lang/tests/normalization/success/prelude/List/any/*.dhall- dhall-lang/tests/normalization/success/prelude/List/build/*.dhall- dhall-lang/tests/normalization/success/prelude/List/build/*.dhall- dhall-lang/tests/normalization/success/prelude/List/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/List/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/List/concatMap/*.dhall- dhall-lang/tests/normalization/success/prelude/List/concatMap/*.dhall- dhall-lang/tests/normalization/success/prelude/List/filter/*.dhall- dhall-lang/tests/normalization/success/prelude/List/filter/*.dhall- dhall-lang/tests/normalization/success/prelude/List/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/List/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/List/generate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/generate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/head/*.dhall- dhall-lang/tests/normalization/success/prelude/List/head/*.dhall- dhall-lang/tests/normalization/success/prelude/List/indexed/*.dhall- dhall-lang/tests/normalization/success/prelude/List/indexed/*.dhall- dhall-lang/tests/normalization/success/prelude/List/iterate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/iterate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/last/*.dhall- dhall-lang/tests/normalization/success/prelude/List/last/*.dhall- dhall-lang/tests/normalization/success/prelude/List/length/*.dhall- dhall-lang/tests/normalization/success/prelude/List/length/*.dhall- dhall-lang/tests/normalization/success/prelude/List/map/*.dhall- dhall-lang/tests/normalization/success/prelude/List/map/*.dhall- dhall-lang/tests/normalization/success/prelude/List/null/*.dhall- dhall-lang/tests/normalization/success/prelude/List/null/*.dhall- dhall-lang/tests/normalization/success/prelude/List/replicate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/replicate/*.dhall- dhall-lang/tests/normalization/success/prelude/List/reverse/*.dhall- dhall-lang/tests/normalization/success/prelude/List/reverse/*.dhall- dhall-lang/tests/normalization/success/prelude/List/shifted/*.dhall- dhall-lang/tests/normalization/success/prelude/List/shifted/*.dhall- dhall-lang/tests/normalization/success/prelude/List/unzip/*.dhall- dhall-lang/tests/normalization/success/prelude/List/unzip/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/enumerate/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/even/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/even/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/isZero/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/isZero/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/odd/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/odd/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/product/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/product/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/sum/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/sum/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/toDouble/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/*.dhall- dhall-lang/tests/normalization/success/prelude/Natural/toInteger/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/all/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/all/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/any/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/any/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/build/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/filter/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/filter/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/fold/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/head/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/head/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/last/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/last/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/length/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/length/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/map/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/map/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/null/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/null/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/toList/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/toList/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/unzip/*.dhall- dhall-lang/tests/normalization/success/prelude/Optional/unzip/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concat/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatMap/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatMap/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatMapSep/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatSep/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/concatSep/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/show/*.dhall- dhall-lang/tests/normalization/success/prelude/Text/show/*.dhall- dhall-lang/tests/normalization/success/simple/*.dhall- dhall-lang/tests/normalization/success/simplifications/*.dhall- dhall-lang/tests/normalization/success/unit/*.dhall- dhall-lang/tests/alpha-normalization/success/unit/*.dhall- dhall-lang/tests/parser/failure/*.dhall- dhall-lang/tests/parser/success/*.dhall- dhall-lang/tests/parser/success/*.dhallb- dhall-lang/tests/parser/success/unit/*.dhall- dhall-lang/tests/parser/success/unit/*.dhallb- dhall-lang/tests/parser/success/unit/import/*.dhall- dhall-lang/tests/parser/success/unit/import/*.dhallb- dhall-lang/tests/parser/success/text/*.dhall- dhall-lang/tests/parser/success/text/*.dhallb- dhall-lang/tests/typecheck/data/*.dhall- dhall-lang/tests/typecheck/failure/*.dhall- dhall-lang/tests/typecheck/success/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/and/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/and/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/even/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/even/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/not/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/not/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/odd/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/odd/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/or/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/or/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Bool/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Double/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Double/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Integer/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Integer/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/*.dhall- dhall-lang/tests/typecheck/success/prelude/Integer/toDouble/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/all/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/all/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/any/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/any/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/concatMap/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/concatMap/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/filter/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/filter/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/generate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/generate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/head/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/head/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/indexed/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/indexed/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/iterate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/iterate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/last/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/last/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/length/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/length/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/map/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/map/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/null/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/null/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/replicate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/replicate/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/reverse/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/reverse/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/shifted/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/shifted/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/unzip/*.dhall- dhall-lang/tests/typecheck/success/prelude/List/unzip/*.dhall- dhall-lang/tests/typecheck/success/prelude/Monoid/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/enumerate/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/even/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/even/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/isZero/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/odd/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/odd/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/product/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/product/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/show/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/sum/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/sum/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/toDouble/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/*.dhall- dhall-lang/tests/typecheck/success/prelude/Natural/toInteger/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/all/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/all/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/any/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/any/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/build/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/filter/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/filter/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/fold/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/head/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/head/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/last/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/last/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/length/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/length/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/map/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/map/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/null/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/null/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/toList/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/toList/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/*.dhall- dhall-lang/tests/typecheck/success/prelude/Optional/unzip/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concat/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatMap/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatMapSep/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/*.dhall- dhall-lang/tests/typecheck/success/prelude/Text/concatSep/*.dhall- dhall-lang/tests/typecheck/success/simple/access/*.dhall- dhall-lang/tests/typecheck/success/simple/*.dhall- tests/format/*.dhall- tests/lint/success/*.dhall- tests/regression/*.dhall- tests/tutorial/*.dhall+ dhall-lang/Prelude/Text/spaces+ dhall-lang/Prelude/XML/Type+ dhall-lang/Prelude/XML/attribute+ dhall-lang/Prelude/XML/element+ dhall-lang/Prelude/XML/emptyAttributes+ dhall-lang/Prelude/XML/leaf+ dhall-lang/Prelude/XML/render+ dhall-lang/Prelude/XML/text+ dhall-lang/tests/**/*.dhall+ dhall-lang/tests/**/*.dhallb+ dhall-lang/tests/**/*.hash+ dhall-lang/tests/**/*.txt+ dhall-lang/tests/**/*.bin+ dhall-lang/tests/import/cache/dhall/12203871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc+ dhall-lang/tests/import/cache/dhall/1220618f785ce8f3930a9144398f576f0a992544b51212bc9108c31b4e670dc6ed21+ tests/**/*.dhall+ tests/**/*.tags+ tests/**/*.txt Source-Repository head Type: git@@ -381,61 +187,112 @@ Default: True Manual: True +Flag use-http-client-tls+ Description: Use http-client-tls for resolving HTTP imports by default+ (requires with-http to be enabled)+ Default: True+ Manual: True+ Flag cross Description: Disable TemplateHaskell to make cross-compiling easier Default: False Manual: True -Library- Hs-Source-Dirs: src+Flag network-tests+ Description: Enable tests which depend on an internet connection+ Default: True+ Manual: True++Common common Build-Depends:- base >= 4.8.2.0 && < 5 ,- aeson >= 1.0.0.0 && < 1.5 ,+ base >= 4.11.0.0 && < 5 ,+ aeson >= 1.0.0.0 && < 2.3 , aeson-pretty < 0.9 ,- ansi-terminal >= 0.6.3.1 && < 0.10,- bytestring < 0.11,+ ansi-terminal >= 0.6.3.1 && < 1.2 ,+ atomic-write >= 0.2.0.7 && < 0.3 ,+ base16-bytestring >= 1.0.0.0 ,+ bytestring < 0.13, case-insensitive < 1.3 , cborg >= 0.2.0.0 && < 0.3 ,- cborg-json < 0.3 ,- containers >= 0.5.0.0 && < 0.7 ,+ cborg-json >= 0.2.2.0 && < 0.3 ,+ containers >= 0.5.8.0 && < 0.9 , contravariant < 1.6 ,- cryptonite >= 0.23 && < 1.0 ,- Diff >= 0.2 && < 0.4 ,- directory >= 1.2.2.0 && < 1.4 ,+ data-fix < 0.4 ,+ deepseq < 1.6 ,+ Diff >= 0.2 && < 1.1 ,+ directory >= 1.3.0.0 && < 1.4 , dotgen >= 0.4.2 && < 0.5 ,+ either >= 5 && < 5.1, exceptions >= 0.8.3 && < 0.11,- filepath >= 1.4 && < 1.5 ,- haskeline >= 0.7.2.1 && < 0.8 ,- lens-family-core >= 1.0.0 && < 1.3 ,- megaparsec >= 6.5.0 && < 7.1 ,- memory >= 0.14 && < 0.15,- mtl >= 2.2.1 && < 2.3 ,- optparse-applicative >= 0.14.0.0 && < 0.15,+ filepath >= 1.4 && < 1.6 ,+ half >= 0.2.2.3 && < 0.4 ,+ haskeline >= 0.7.2.1 && < 0.9 ,+ hashable >= 1.2 && < 1.6 ,+ indexed-traversable < 0.2 ,+ microlens >= 0.4.14.0 && < 0.5 ,+ microlens-mtl >= 0.1 && < 0.3 ,+ -- megaparsec follows SemVer: https://github.com/mrkkrp/megaparsec/issues/469#issuecomment-927918469+ megaparsec >= 8 && < 10 ,+ mmorph < 1.3 ,+ mtl >= 2.2.1 && < 2.4 ,+ network-uri >= 2.6 && < 2.7 ,+ optparse-applicative >= 0.14.0.0 && < 0.20, parsers >= 0.12.4 && < 0.13,- prettyprinter >= 1.2.0.1 && < 1.3 ,- prettyprinter-ansi-terminal >= 1.1.1 && < 1.2 ,- profunctors >= 3.1.2 && < 5.5 ,- repline >= 0.2.1.0 && < 0.3 ,+ parser-combinators ,+ prettyprinter >= 1.7.0 && < 1.8 ,+ prettyprinter-ansi-terminal >= 1.1.2 && < 1.2 ,+ pretty-simple < 4.2 ,+ repline >= 0.4.0.0 && < 0.5 , serialise >= 0.2.0.0 && < 0.3 , scientific >= 0.3.0.0 && < 0.4 ,- template-haskell < 2.15,- text >= 0.11.1.0 && < 1.3 ,- transformers >= 0.2.0.0 && < 0.6 ,- transformers-compat >= 0.6.2 && < 0.7 ,+ template-haskell >= 2.13.0.0 && < 2.24,+ text >= 0.11.1.0 && < 2.2 ,+ text-manipulate >= 0.2.0.1 && < 0.4 ,+ text-short >= 0.1 && < 0.2 ,+ th-lift-instances >= 0.1.13 && < 0.2 ,+ time >= 1.9 && < 1.15,+ transformers >= 0.5.2.0 && < 0.7 ,+ unix-compat >= 0.4.2 && < 0.8 , unordered-containers >= 0.1.3.0 && < 0.3 ,- uri-encode < 1.6 ,- vector >= 0.11.0.0 && < 0.13- if flag(with-http)+ vector >= 0.11.0.0 && < 0.14++ if !os(windows) Build-Depends:- http-types >= 0.7.0 && < 0.13,- http-client >= 0.4.30 && < 0.7 ,- http-client-tls >= 0.2.0 && < 0.4- if !impl(ghc >= 8.0) && !impl(eta >= 0.8.4)- Build-Depends: semigroups == 0.18.*- Build-Depends: transformers == 0.4.2.*- Build-Depends: fail == 4.9.*+ unix >= 2.7 && < 2.9 ,++ if flag(with-http)+ CPP-Options:+ -DWITH_HTTP+ if flag(use-http-client-tls)+ CPP-Options:+ -DUSE_HTTP_CLIENT_TLS+ if flag(network-tests)+ CPP-Options:+ -DNETWORK_TESTS+ if flag(cross)+ CPP-Options: -DCROSS++ GHC-Options: -Wall -Wcompat -Wincomplete-uni-patterns -optP-Wno-unicode-homoglyph++Library+ Import: common+ Hs-Source-Dirs: src if impl(ghcjs)- Build-Depends: ghcjs-xhr+ Hs-Source-Dirs: ghcjs-src+ Build-Depends:+ ghcjs-base ,+ ghcjs-xhr+ else+ Hs-Source-Dirs: ghc-src+ Build-Depends:+ cryptohash-sha256+ if flag(with-http)+ Build-Depends:+ http-types >= 0.7.0 && < 0.13,+ http-client >= 0.5.0 && < 0.8+ if flag(use-http-client-tls)+ Build-Depends:+ http-client-tls >= 0.2.0 && < 0.4 Other-Extensions: BangPatterns@@ -466,157 +323,175 @@ TemplateHaskell Exposed-Modules:- Dhall,- Dhall.Binary,- Dhall.Context,- Dhall.Core,- Dhall.Diff,- Dhall.Format,- Dhall.Freeze,- Dhall.Hash,- Dhall.Import,- Dhall.Lint,- Dhall.Main,- Dhall.Map,- Dhall.Optics,- Dhall.Set,- Dhall.Src,- Dhall.Parser,- Dhall.Pretty,- Dhall.Repl,- Dhall.Tutorial,+ Dhall+ Dhall.Binary+ Dhall.Context+ Dhall.Core+ Dhall.Crypto+ Dhall.Diff+ Dhall.DirectoryTree+ Dhall.Format+ Dhall.Freeze+ Dhall.Import+ Dhall.Lint+ Dhall.Main+ Dhall.Marshal.Decode+ Dhall.Marshal.Encode+ Dhall.Map+ Dhall.Optics+ Dhall.Package+ Dhall.Parser+ Dhall.Parser.Expression+ Dhall.Parser.Token+ Dhall.Pretty+ Dhall.Repl+ Dhall.Schemas+ Dhall.Set+ Dhall.Src+ Dhall.Substitution+ Dhall.Tags+ Dhall.Tutorial Dhall.TypeCheck+ Dhall.Util+ Dhall.Version if !flag(cross) Exposed-Modules: Dhall.TH+ if impl(ghc >= 8.6.1)+ Exposed-Modules:+ Dhall.Deriving Other-Modules:- Dhall.Pretty.Internal,- Dhall.Parser.Expression,- Dhall.Parser.Combinators,- Dhall.Parser.Token,- Dhall.Import.Types,- Dhall.Eval,- Dhall.Util,+ Dhall.DirectoryTree.Types+ Dhall.Eval+ Dhall.Import.Types+ Dhall.Import.Headers+ Dhall.Marshal.Internal+ Dhall.Normalize+ Dhall.Parser.Combinators+ Dhall.Pretty.Internal+ Dhall.Syntax+ Dhall.Syntax.Binding+ Dhall.Syntax.Chunks+ Dhall.Syntax.Const+ Dhall.Syntax.Expr+ Dhall.Syntax.FunctionBinding+ Dhall.Syntax.Import+ Dhall.Syntax.Instances.Applicative+ Dhall.Syntax.Instances.Bifunctor+ Dhall.Syntax.Instances.Data+ Dhall.Syntax.Instances.Eq+ Dhall.Syntax.Instances.Foldable+ Dhall.Syntax.Instances.Functor+ Dhall.Syntax.Instances.Lift+ Dhall.Syntax.Instances.Monad+ Dhall.Syntax.Instances.NFData+ Dhall.Syntax.Instances.Ord+ Dhall.Syntax.Instances.Pretty+ Dhall.Syntax.Instances.Show+ Dhall.Syntax.Instances.Traversable+ Dhall.Syntax.MultiLet+ Dhall.Syntax.Operations+ Dhall.Syntax.RecordField+ Dhall.Syntax.Types+ Dhall.Syntax.Var+ Dhall.URL Paths_dhall+ Autogen-Modules:+ Paths_dhall if flag(with-http) Other-Modules: Dhall.Import.HTTP+ Dhall.Import.Manager - GHC-Options: -Wall -fwarn-incomplete-uni-patterns Default-Language: Haskell2010 Executable dhall+ Import: common Hs-Source-Dirs: dhall Main-Is: Main.hs- Build-Depends: base, dhall- GHC-Options: -Wall -rtsopts+ Build-Depends: dhall+ GHC-Options: -rtsopts Default-Language: Haskell2010 Test-Suite tasty+ Import: common Type: exitcode-stdio-1.0 Hs-Source-Dirs: tests Main-Is: Dhall/Test/Main.hs- GHC-Options: -Wall Other-Modules: Dhall.Test.Dhall+ Dhall.Test.Diff+ Dhall.Test.DirectoryTree+ Dhall.Test.Tags Dhall.Test.Format+ Dhall.Test.Freeze Dhall.Test.Import Dhall.Test.Lint Dhall.Test.Normalization+ Dhall.Test.Package Dhall.Test.Parser Dhall.Test.QuickCheck Dhall.Test.Regression+ Dhall.Test.Schemas+ Dhall.Test.SemanticHash+ Dhall.Test.Substitution Dhall.Test.Tutorial- Dhall.Test.TypeCheck+ Dhall.Test.TypeInference Dhall.Test.Util+ if !flag(cross)+ Other-Modules:+ Dhall.Test.TH Build-Depends:- base >= 4 && < 5 ,- bytestring < 0.11,- cborg >= 0.2.0.0 && < 0.3 ,- containers ,- deepseq >= 1.2.0.1 && < 1.5 , dhall ,- directory ,- filepath , foldl < 1.5 ,- megaparsec ,- prettyprinter ,- QuickCheck >= 2.10 && < 2.14,+ generic-random >= 1.3.0.0 && < 1.6 ,+ http-client ,+ http-client-tls ,+ QuickCheck >= 2.14 && < 2.17, quickcheck-instances >= 0.3.12 && < 0.4 ,- serialise ,- tasty >= 0.11.2 && < 1.3 ,- tasty-hunit >= 0.9.2 && < 0.11,- tasty-quickcheck >= 0.9.2 && < 0.11,- text >= 0.11.1.0 && < 1.3 ,- transformers ,- turtle < 1.6 ,- vector >= 0.11.0.0 && < 0.13+ special-values < 0.2 ,+ spoon < 0.4 ,+ tasty >= 0.11.2 && < 1.6 ,+ tasty-expected-failure < 0.13,+ tasty-hunit >= 0.10 && < 0.11,+ tasty-quickcheck >= 0.9.2 && < 0.12,+ tasty-silver < 3.4 ,+ temporary >= 1.2.1 && < 1.4 ,+ turtle >= 1.6 && < 1.7 , Default-Language: Haskell2010 Test-Suite doctest+ Import: common Type: exitcode-stdio-1.0 Hs-Source-Dirs: doctest Main-Is: Main.hs- GHC-Options: -Wall Build-Depends:- base ,- directory ,- filepath < 1.5 , mockery < 0.4 ,- doctest >= 0.7.0 && < 0.17- Default-Language: Haskell2010- -- `doctest` doesn't work with `MIN_VERSION` macros before GHC 8- --- -- See: https://ghc.haskell.org/trac/ghc/ticket/10970- if impl(ghc < 8.0)+ doctest >= 0.7.0+ if os(windows)+ -- https://github.com/dhall-lang/dhall-haskell/issues/2237 Buildable: False+ Default-Language: Haskell2010 Benchmark dhall-parser+ Import: common Type: exitcode-stdio-1.0 Hs-Source-Dirs: benchmark/parser Main-Is: Main.hs Build-Depends:- base >= 4 && < 5 ,- bytestring ,- containers >= 0.5.0.0 && < 0.7,- criterion >= 1.1 && < 1.6, dhall ,- directory ,- serialise ,- text >= 0.11.1.0 && < 1.3+ tasty-bench >= 0.4 && < 0.5, Default-Language: Haskell2010 Other-Extensions: TypeApplications- ghc-options: -rtsopts+ Ghc-Options: -rtsopts Benchmark deep-nested-large-record+ Import: common Type: exitcode-stdio-1.0 Hs-Source-Dirs: benchmark/deep-nested-large-record Main-Is: Main.hs Build-Depends:- base >= 4 && < 5 ,- containers >= 0.5.0.0 && < 0.7,- criterion >= 1.1 && < 1.6,- dhall- Default-Language: Haskell2010--Benchmark dhall-command- Type: exitcode-stdio-1.0- Main-Is: Main.hs- Hs-Source-Dirs: benchmark/dhall-command- Build-Depends:- base >= 4 && < 5 ,- dhall- Default-Language: Haskell2010- ghc-options: -rtsopts -O2--Benchmark map-operations- Type: exitcode-stdio-1.0- Main-Is: Main.hs- Hs-Source-Dirs: benchmark/map- Build-Depends:- base >= 4 && < 5 ,- criterion >= 1.1 && < 1.6,- dhall+ dhall ,+ tasty-bench >= 0.4 && < 0.5, Default-Language: Haskell2010- ghc-options: -rtsopts -O2
@@ -1,33 +1,59 @@-module Main where+{-# LANGUAGE CPP #-} -import Data.Monoid ((<>))+module Main (main) where+ import System.FilePath ((</>)) import qualified GHC.IO.Encoding import qualified System.Directory+import qualified System.Environment import qualified System.IO-import qualified Test.Mockery.Directory import qualified Test.DocTest+import qualified Test.Mockery.Directory main :: IO () main = do- - GHC.IO.Encoding.setLocaleEncoding System.IO.utf8 - pwd <- System.Directory.getCurrentDirectory+ GHC.IO.Encoding.setLocaleEncoding System.IO.utf8+ args <- System.Environment.getArgs+ pwd <- System.Directory.getCurrentDirectory prefix <- System.Directory.makeAbsolute pwd+ let src = prefix </> "src" + System.Environment.setEnv "XDG_CACHE_HOME" (pwd </> ".cache")+ Test.Mockery.Directory.inTempDirectory $ do- writeFile "makeBools" "λ(n : Bool) → [ n && True, n && False, n || True, n || False ]"+ writeFile "makeBools.dhall" "λ(n : Bool) → [ n && True, n && False, n || True, n || False ]" writeFile "bool1" "True" writeFile "bool2" "False" writeFile "both" "./bool1 && ./bool2" writeFile "file2" "./file1" writeFile "file1" "./file2"+ writeFile "simon.dhall" $ unlines+ [ "let Name = Text"+ , "let Font = < Arial | `Comic Sans` | Helvetica | `Times New Roman` >"+ , "let Person = { name : Name, favoriteFont : Font }"+ , "in { name = \"Simon\", favoriteFont = Font.`Comic Sans` } : Person"+ ] - Test.DocTest.doctest- [ "--fast"- , "-i" <> (prefix </> "src")- , prefix </> "src/Dhall.hs"- , prefix </> "src/Dhall/Import.hs"- , prefix </> "src/Dhall/Tutorial.hs"+ Test.DocTest.doctest $+ [ "-DWITH_HTTP"+ , "-DUSE_HTTP_CLIENT_TLS"+ , "--fast"+ ] <> args <>+ [ prefix </> "ghc-src"++ -- Unfortunately we cannot target the entire @src@ directory.+ -- The reason is that src/Dhall/Version.hs depends on+ -- the generated Paths_dhall module which is "out-of-scope"+ -- when running the testsuite with cabal v1-test.+ -- Instead, we target a selection of modules whose combined module+ -- dependency tree covers all modules that contain doctests.++ -- , src+ , "-i" <> src+#if __GLASGOW_HASKELL__ >= 806+ , src </> "Dhall/Deriving.hs"+#endif+ , src </> "Dhall/Tags.hs"+ , src </> "Dhall/Tutorial.hs" ]
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++{-| This module provides implementations of cryptographic utilities that only+ work for GHC (as opposed to GHCJS)+-}++module Dhall.Crypto (+ SHA256Digest(..)+ , sha256DigestFromByteString+ , sha256Hash+ , toString+ ) where++import Control.DeepSeq (NFData)+import Data.ByteString (ByteString)+import Data.Data (Data)+import GHC.Generics (Generic)++import qualified Crypto.Hash.SHA256+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Base16 as Base16+import qualified Data.ByteString.Char8 as ByteString.Char8++-- | A SHA256 digest+newtype SHA256Digest = SHA256Digest { unSHA256Digest :: ByteString }+ deriving (Data, Eq, Generic, Ord, NFData)++instance Show SHA256Digest where+ show = toString++{-| Attempt to interpret a `ByteString` as a `SHA256Digest`, returning+ `Nothing` if the conversion fails+-}+sha256DigestFromByteString :: ByteString -> Maybe SHA256Digest+sha256DigestFromByteString bytes+ | ByteString.length bytes == 32 = Just (SHA256Digest bytes)+ | otherwise = Nothing++-- | Hash a `ByteString` and return the hash as a `SHA256Digest`+sha256Hash :: ByteString -> SHA256Digest+sha256Hash = SHA256Digest . Crypto.Hash.SHA256.hash++-- | 'String' representation of a 'SHA256Digest'+toString :: SHA256Digest -> String+toString (SHA256Digest bytes) = ByteString.Char8.unpack $ Base16.encode bytes
@@ -0,0 +1,320 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Dhall.Import.HTTP+ ( fetchFromHttpUrl+ , fetchFromHttpUrlBytes+ , originHeadersFileExpr+ ) where++import Control.Exception (Exception)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.State.Strict (StateT)+import Data.ByteString (ByteString)+import Data.CaseInsensitive (CI)+import Data.Dynamic (toDyn)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Text.Encoding (decodeUtf8)+import Dhall.Core+ ( Expr (..)+ , Directory (..)+ , File (..)+ , FilePrefix (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , Scheme (..)+ , URL (..)+ )+import Dhall.Import.Types+import Dhall.Parser (Src)+import Dhall.URL (renderURL)+import System.Directory (getXdgDirectory, XdgDirectory(XdgConfig))+import System.FilePath (splitDirectories)+++import Network.HTTP.Client (HttpException (..), HttpExceptionContent (..))++import qualified Control.Exception+import qualified Control.Monad.Trans.State.Strict as State+import qualified Data.ByteString.Lazy as ByteString.Lazy+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Data.Text.Encoding+import qualified Dhall.Util+import qualified Network.HTTP.Client as HTTP+import qualified Network.HTTP.Types++mkPrettyHttpException :: String -> HttpException -> PrettyHttpException+mkPrettyHttpException url ex =+ PrettyHttpException (renderPrettyHttpException url ex) (toDyn ex)++renderPrettyHttpException :: String -> HttpException -> String+renderPrettyHttpException _ (InvalidUrlException _ r) =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Invalid URL\n"+ <> "\n"+ <> "URL: " <> show r <> "\n"+renderPrettyHttpException url (HttpExceptionRequest _ e) =+ case e of+ ConnectionFailure _ ->+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Remote host not found\n"+ <> "\n"+ <> "URL: " <> url <> "\n"+ InvalidDestinationHost host ->+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Invalid remote host name:\n"+ <> "\n"+ <> "Host: " <> show host <> "\n"+ ResponseTimeout ->+ "\n"+ <> "\ESC[1;31mError\ESC[0m: The remote host took too long to respond\n"+ <> "\n"+ <> "URL: " <> url <> "\n"+ ConnectionTimeout ->+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Connection establishment took too long\n"+ <> "\n"+ <> "URL: " <> url <> "\n"+ StatusCodeException response body -> prefix <> suffix+ where+ prefix+ | statusCode == 401 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Access unauthorized\n"+ | statusCode == 403 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Access forbidden\n"+ | statusCode == 404 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Remote file not found\n"+ | statusCode == 500 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Server-side failure\n"+ | statusCode == 502 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Upstream failure\n"+ | statusCode == 503 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Server temporarily unavailable\n"+ | statusCode == 504 =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Upstream timeout\n"+ | otherwise =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: HTTP request failure\n"++ suffix =+ "\n"+ <> "HTTP status code: " <> show statusCode <> "\n"+ <> "\n"+ <> "URL: " <> url <> "\n"+ <> message++ statusCode =+ Network.HTTP.Types.statusCode+ (HTTP.responseStatus response)++ message =+ case Data.Text.Encoding.decodeUtf8' body of+ Left _ ->+ "\n"+ <> "Message (non-UTF8 bytes):\n"+ <> "\n"+ <> truncatedBodyString <> "\n"+ where+ bodyString = show body++ dots = "…"++ truncatedLength = 80 - length dots++ truncatedBodyString+ | truncatedLength < length bodyString =+ take truncatedLength bodyString <> dots+ | otherwise =+ bodyString+ Right "" ->+ ""+ Right bodyText ->+ "\n"+ <> "Message:\n"+ <> "\n"+ <> Text.unpack prefixedText+ where+ prefixedLines =+ zipWith combine prefixes (Text.lines bodyText)+ where+ prefixes =+ map (Text.pack . show) [(1 ::Int)..7] ++ [ "…" ]++ combine n line = n <> "│ " <> line++ prefixedText = Text.unlines prefixedLines++ e' -> "\n"+ <> "\ESC[1;31mError\ESC[0m: " <> show e'+ <> "\n"+ <> "URL: " <> url <> "\n"++newManager :: StateT Status IO Manager+newManager = do+ Status { _manager = oldManager, ..} <- State.get++ case oldManager of+ Nothing -> do+ manager <- liftIO _newManager++ State.put (Status { _manager = Just manager , ..})++ return manager++ Just manager ->+ return manager++data NotCORSCompliant = NotCORSCompliant+ { expectedOrigins :: [ByteString]+ , actualOrigin :: ByteString+ }++instance Exception NotCORSCompliant++instance Show NotCORSCompliant where+ show (NotCORSCompliant {..}) =+ Dhall.Util._ERROR <> ": Not CORS compliant\n"+ <> "\n"+ <> "Dhall supports transitive imports, meaning that an imported expression can\n"+ <> "import other expressions. However, a remote import (the \"parent\" import)\n"+ <> "cannot import another remote import (the \"child\" import) unless the child\n"+ <> "import grants permission to do using CORS. The child import must respond with\n"+ <> "an `Access-Control-Allow-Origin` response header that matches the parent\n"+ <> "import, otherwise Dhall rejects the import.\n"+ <> "\n" <> prologue+ where+ prologue =+ case expectedOrigins of+ [ expectedOrigin ] ->+ "The following parent import:\n"+ <> "\n"+ <> "↳ " <> show actualOrigin <> "\n"+ <> "\n"+ <> "... did not match the expected origin:\n"+ <> "\n"+ <> "↳ " <> show expectedOrigin <> "\n"+ <> "\n"+ <> "... so import resolution failed.\n"+ [] ->+ "The child response did not include any `Access-Control-Allow-Origin` header,\n"+ <> "so import resolution failed.\n"+ _:_:_ ->+ "The child response included more than one `Access-Control-Allow-Origin` header,\n"+ <> "when only one such header should have been present, so import resolution\n"+ <> "failed.\n"+ <> "\n"+ <> "This may indicate that the server for the child import is misconfigured.\n"++corsCompliant+ :: MonadIO io+ => ImportType -> URL -> [(CI ByteString, ByteString)] -> io ()+corsCompliant (Remote parentURL) childURL responseHeaders = liftIO $ do+ let toOrigin (URL {..}) =+ Data.Text.Encoding.encodeUtf8 (prefix <> "://" <> authority)+ where+ prefix =+ case scheme of+ HTTP -> "http"+ HTTPS -> "https"++ let actualOrigin = toOrigin parentURL++ let childOrigin = toOrigin childURL++ let predicate (header, _) = header == "Access-Control-Allow-Origin"++ let originHeaders = filter predicate responseHeaders++ let expectedOrigins = map snd originHeaders++ case expectedOrigins of+ [expectedOrigin]+ | expectedOrigin == "*" ->+ return ()+ | expectedOrigin == actualOrigin ->+ return ()+ _ | actualOrigin == childOrigin ->+ return ()+ | otherwise ->+ Control.Exception.throwIO (NotCORSCompliant {..})+corsCompliant _ _ _ = return ()++addHeaders :: OriginHeaders -> Maybe [HTTPHeader] -> HTTP.Request -> HTTP.Request+addHeaders originHeaders urlHeaders request =+ request { HTTP.requestHeaders = (filterHeaders urlHeaders) <> perOriginHeaders }+ where+ origin = decodeUtf8 (HTTP.host request) <> ":" <> Text.pack (show (HTTP.port request))+ + perOriginHeaders = HashMap.lookupDefault [] origin originHeaders++ filterHeaders = foldMap (filter (not . overridden))++ overridden :: HTTPHeader -> Bool+ overridden (key, _value) = any (matchesKey key) perOriginHeaders++ matchesKey :: CI ByteString -> HTTPHeader -> Bool+ matchesKey key (candidate, _value) = key == candidate++fetchFromHttpUrlBytes+ :: URL -> Maybe [HTTPHeader] -> StateT Status IO ByteString+fetchFromHttpUrlBytes childURL mheaders = do+ Status { _loadOriginHeaders } <- State.get++ originHeaders <- _loadOriginHeaders++ manager <- newManager++ let childURLString = Text.unpack (renderURL childURL)++ baseRequest <- liftIO (HTTP.parseUrlThrow childURLString)++ let requestWithHeaders = addHeaders originHeaders mheaders baseRequest++ let io = HTTP.httpLbs requestWithHeaders manager++ let handler e = do+ let _ = e :: HttpException+ Control.Exception.throwIO (mkPrettyHttpException childURLString e)++ response <- liftIO (Control.Exception.handle handler io)++ Status {..} <- State.get++ case _stack of+ -- We ignore the first import in the stack since that is the same import+ -- as the `childUrl`+ _ :| Chained parentImport : _ -> do+ let parentImportType = importType (importHashed parentImport)++ corsCompliant parentImportType childURL (HTTP.responseHeaders response)+ _ -> do+ return ()++ return (ByteString.Lazy.toStrict (HTTP.responseBody response))++fetchFromHttpUrl :: URL -> Maybe [HTTPHeader] -> StateT Status IO Text.Text+fetchFromHttpUrl childURL mheaders = do+ bytes <- fetchFromHttpUrlBytes childURL mheaders++ case Data.Text.Encoding.decodeUtf8' bytes of+ Left err -> liftIO (Control.Exception.throwIO err)+ Right text -> return text++originHeadersFileExpr :: IO (Expr Src Import)+originHeadersFileExpr = do+ directoryStr <- getXdgDirectory XdgConfig "dhall"+ let components = map Text.pack (splitDirectories directoryStr)+ let directory = Directory (reverse components)+ let file = (File directory "headers.dhall")+ return (Embed (Import (ImportHashed Nothing (Local Absolute file)) Code))
@@ -0,0 +1,33 @@+{-# LANGUAGE CPP #-}++{-| Both the GHC and GHCJS implementations of 'Dhall.Import.Manager.Manager'+ export a `Dhall.Import.Manager.Manager` type suitable for use within the+ "Dhall.Import" module++ For the GHC implementation the `Dhall.Import.Manager` type is a real+ `Network.HTTP.Client.Manager` from the @http-client@ package. For the+ GHCJS implementation the `Dhall.Import.Manager.Manager` type is+ a synonym for @`Data.Void.Void`@ since GHCJS does not use a+ `Network.HTTP.Client.Manager` for HTTP requests.+-}+module Dhall.Import.Manager+ ( -- * Manager+ Manager+ , defaultNewManager+ ) where++import Network.HTTP.Client (Manager, newManager)+import qualified Network.HTTP.Client as HTTP++#ifdef USE_HTTP_CLIENT_TLS+import Network.HTTP.Client.TLS (tlsManagerSettings)+#endif++defaultNewManager :: IO Manager+defaultNewManager = newManager+#ifdef USE_HTTP_CLIENT_TLS+ tlsManagerSettings+#else+ HTTP.defaultManagerSettings+#endif+ { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro (30 * 1000 * 1000) } -- 30 seconds
@@ -0,0 +1,75 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE JavaScriptFFI #-}++{-| This module provides implementations of cryptographic utilities that only+ work for GHCJS+-}++module Dhall.Crypto (+ SHA256Digest(..)+ , sha256DigestFromByteString+ , sha256Hash+ ) where++import Control.DeepSeq (NFData)+import Data.ByteString (ByteString)+import Data.Data (Data)+import GHC.Generics (Generic)+import JavaScript.TypedArray.ArrayBuffer (ArrayBuffer)+import System.IO.Unsafe (unsafePerformIO)++import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Base16 as Base16+import qualified Data.ByteString.Char8 as ByteString.Char8+import qualified GHCJS.Buffer as Buffer++-- | A SHA256 digest+newtype SHA256Digest = SHA256Digest { unSHA256Digest :: ByteString }+ deriving (Data, Eq, Generic, Ord, NFData)++instance Show SHA256Digest where+ show (SHA256Digest bytes) = ByteString.Char8.unpack $ Base16.encode bytes++{-| Attempt to interpret a `ByteString` as a `SHA256Digest`, returning+ `Nothing` if the conversion fails+-}+sha256DigestFromByteString :: ByteString -> Maybe SHA256Digest+sha256DigestFromByteString bytes+ | ByteString.length bytes == 32 = Just (SHA256Digest bytes)+ | otherwise = Nothing++-- Use NodeJS' crypto module if there's a 'process' module, e.g. we're running+-- inside GHCJS' THRunner. If we're running in the browser, use the WebCrypto+-- interface.+foreign import javascript interruptible+ "if (typeof process === 'undefined') { \+ \ crypto.subtle.digest('SHA-256', $1).then($c) \+ \} else { \+ \ $c(require('crypto').createHash('sha256').update(Buffer.from($1)).digest().buffer) \+ \}"+ js_sha256Hash :: ArrayBuffer -> IO ArrayBuffer++byteStringToArrayBuffer :: ByteString -> ArrayBuffer+byteStringToArrayBuffer b =+ js_arrayBufferSlice offset len $ Buffer.getArrayBuffer buffer+ where+ (buffer, offset, len) = Buffer.fromByteString b++foreign import javascript unsafe "$3.slice($1, $1 + $2)"+ js_arrayBufferSlice :: Int -> Int -> ArrayBuffer -> ArrayBuffer++arrayBufferToByteString :: ArrayBuffer -> ByteString+arrayBufferToByteString =+ Buffer.toByteString 0 Nothing . Buffer.createFromArrayBuffer++-- | Hash a `ByteString` and return the hash as a `SHA256Digest`+sha256Hash :: ByteString -> SHA256Digest+sha256Hash bytes+ | ByteString.length out == 32 = SHA256Digest out+ | otherwise = error "sha256Hash: didn't produce 32 bytes"+ where+ out =+ arrayBufferToByteString $+ unsafePerformIO $ js_sha256Hash (byteStringToArrayBuffer bytes)
@@ -0,0 +1,52 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Import.HTTP+ ( fetchFromHttpUrl+ , fetchFromHttpUrlBytes+ , originHeadersFileExpr+ ) where++import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.State.Strict (StateT)+import Data.ByteString (ByteString)+import Data.CaseInsensitive (CI)+import Dhall.Core (URL (..), Expr (..))+import Dhall.Import.Types (Import, Status)+import Dhall.Parser (Src)+import Dhall.URL (renderURL)++import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text.Encoding+import qualified JavaScript.XHR++fetchFromHttpUrl+ :: URL+ -> Maybe [(CI ByteString, ByteString)]+ -> StateT Status IO Text.Text+fetchFromHttpUrl childURL Nothing = do+ let childURLText = renderURL childURL++ let childURLString = Text.unpack childURLText++ -- No need to add a CORS compliance check when using GHCJS. The browser+ -- will already check the CORS compliance of the following XHR+ (statusCode, body) <- liftIO (JavaScript.XHR.get childURLText)++ case statusCode of+ 200 -> return ()+ _ -> fail (childURLString <> " returned a non-200 status code: " <> show statusCode)++ return body+fetchFromHttpUrl _ _ =+ fail "Dhall does not yet support custom headers when built using GHCJS"++fetchFromHTTPUrlBytes+ :: URL+ -> Maybe [(CI ByteString, ByteString)]+ -> StateT Status IO ByteString+fetchFromHTTPUrlBytes childUrl mheader = do+ text <- fetchFromHTTPUrl childUrl mheader+ return (Text.Encoding.encodeUtf8 text)++originHeadersFileExpr :: IO (Expr Src Import)+originHeadersFileExpr = return Missing
@@ -0,0 +1,26 @@+{-| Both the GHC and GHCJS implementations of `Dhall.Import.Manager.Manager`+ export a `Dhall.Import.Manager.Manager` type suitable for use within the+ "Dhall.Import" module++ For the GHC implementation the `Dhall.Import.Manager.Manager` type is a real+ `Network.HTTP.Client.Manager` from the @http-client@ package. For the GHCJS+ implementation the `Dhall.Import.Manager.Manager` type is a synonym for+ @`Data.Void.Void`@ since GHCJS does not use a+ `Network.HTTP.Client.Manager` for HTTP requests.+-}+module Dhall.Import.Manager+ ( -- * Manager+ Manager+ , defaultNewManager+ ) where++{-| The GHCJS implementation does not require a `Network.HTTP.Client.Manager`++ The purpose of this synonym is so that "Dhall.Import.Types" can import a+ `Dhall.Import.Manager.Manager` type from "Dhall.Import.HTTP" that does the+ correct thing for both the GHC and GHCJS implementations+-}+type Manager = ()++defaultNewManager :: IO Manager+defaultNewManager = pure ()
@@ -0,0 +1,100 @@+.\" Automatically generated by Pandoc 2.9.2+.\"+.TH "dhall (1)" "" "" "" ""+.hy+.SH NAME+.PP+dhall - a programmable configuration language+.SH DESCRIPTION+.PP+\f[B]dhall\f[R] is the command-line interface to the Dhall language+.SH SYNOPSIS+.PP+dhall --file check.dhall+.PP+dhall --file error.dhall --explain+.PP+dhall hash --file to-hash.dhall+.PP+dhall freeze --file with-imports.dhall+.PP+dhall repl+.PP+dhall diff \[aq]./file1.dhall\[cq] \[aq]./file2.dhall\[cq]+.PP+dhall type --quiet --file check-ci.dhall+.SH SUBCOMMANDS+.PP+\f[B]version\f[R] - Display version information+.PP+\f[B]resolve\f[R] - Resolve imports+.PP+\f[B]type\f[R] - Infer type of expression+.PP+\f[B]normalize\f[R] - Normalize an expression+.PP+\f[B]repl\f[R] - Open a REPL+.PP+\f[B]diff\f[R] - Show difference between two expressions+.PP+\f[B]hash\f[R] - Compute hash of expression+.PP+\f[B]lint\f[R] - Lint an expression, removing dead code+.PP+\f[B]tags\f[R] - Generate etags (Emacs) file+.PP+\f[B]format\f[R] - Format an expression+.PP+\f[B]freeze\f[R] - Add hashes to import statements+.PP+\f[B]encode\f[R] - Encode a Dhall expression (CBOR)+.PP+\f[B]decode\f[R] - Decode a Dhall expression+.PP+\f[B]text\f[R] - Render a Dhall expression to text+.PP+\f[B]to-directory-tree\f[R] - Convert nested record of Text into a+directory+.SH OPTIONS+.TP+\f[B]-h\f[R] \f[B]--help\f[R]+Display help+.TP+\f[B]--file\f[R]+Name of file containing Dhall source+.TP+\f[B]--output\f[R]+Output file+.TP+\f[B]--annotate\f[R]+Add type annotation to output+.TP+\f[B]--alpha\f[R]+alpha-normalize output+.TP+\f[B]--no-cache\f[R]+Don\[cq]t use cache to resolve imports+.TP+\f[B]--explain\f[R]+Explain error messages in detail+.TP+\f[B]--version\f[R]+Display version information+.TP+\f[B]--plain\f[R]+Disable syntax highlighting in output+.TP+\f[B]--ascii\f[R]+Format code using only ASCII syntax+.TP+\f[B]--censor\f[R]+Hide source code from error messages+.SH EDITOR INTEGRATION+.PP+Up-to-date information on editor integration is available at:+.PP+https://docs.dhall-lang.org/howtos/Text-Editor-Configuration.html+.SH BUGS+.PP+Please report any bugs you may come across to+https://github.com/dhall-lang/dhall-haskell/issues.
@@ -1,1811 +1,579 @@-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TupleSections #-}--{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining- how to use the language, the compiler, and this library--}--module Dhall- (- -- * Input- input- , inputWithSettings- , inputFile- , inputFileWithSettings- , inputExpr- , inputExprWithSettings- , rootDirectory- , sourceName- , startingContext- , normalizer- , standardVersion- , defaultInputSettings- , InputSettings- , defaultEvaluateSettings- , EvaluateSettings- , HasEvaluateSettings- , detailed-- -- * Types- , Type(..)- , RecordType(..)- , UnionType(..)- , InputType(..)- , Interpret(..)- , InvalidType(..)- , auto- , genericAuto- , InterpretOptions(..)- , defaultInterpretOptions- , bool- , natural- , integer- , scientific- , double- , lazyText- , strictText- , maybe- , sequence- , list- , vector- , unit- , string- , pair- , record- , field- , union- , constructor- , GenericInterpret(..)- , GenericInject(..)-- , Inject(..)- , inject- , genericInject- , RecordInputType(..)- , inputFieldWith- , inputField- , inputRecord- , UnionInputType(..)- , inputConstructorWith- , inputConstructor- , inputUnion- , (>|<)-- -- * Miscellaneous- , rawInput- , (>$<)- , (>*<)-- -- * Re-exports- , Natural- , Seq- , Text- , Vector- , Generic- ) where--import Control.Applicative (empty, liftA2, (<|>), Alternative)-import Control.Exception (Exception)-import Control.Monad.Trans.State.Strict-import Control.Monad (guard)-import Data.Coerce (coerce)-import Data.Functor.Contravariant (Contravariant(..), (>$<), Op(..))-import Data.Functor.Contravariant.Divisible (Divisible(..), divided)-import Data.Monoid ((<>))-import Data.Scientific (Scientific)-import Data.Sequence (Seq)-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Pretty)-import Data.Typeable (Typeable)-import Data.Vector (Vector)-import Data.Word (Word8, Word16, Word32, Word64)-import Dhall.Binary (StandardVersion(..))-import Dhall.Core (Expr(..), Chunks(..))-import Dhall.Import (Imported(..))-import Dhall.Parser (Src(..))-import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)-import GHC.Generics-import Lens.Family (LensLike', set, view)-import Numeric.Natural (Natural)-import Prelude hiding (maybe, sequence)-import System.FilePath (takeDirectory)--import qualified Control.Applicative-import qualified Control.Exception-import qualified Control.Monad.Trans.State.Strict as State-import qualified Data.Foldable-import qualified Data.Functor.Compose-import qualified Data.Functor.Product-import qualified Data.Semigroup-import qualified Data.Scientific-import qualified Data.Sequence-import qualified Data.Set-import qualified Data.Text-import qualified Data.Text.IO-import qualified Data.Text.Lazy-import qualified Data.Vector-import qualified Dhall.Binary-import qualified Dhall.Context-import qualified Dhall.Core-import qualified Dhall.Import-import qualified Dhall.Map-import qualified Dhall.Parser-import qualified Dhall.Pretty.Internal-import qualified Dhall.TypeCheck-import qualified Dhall.Util---- $setup--- >>> :set -XOverloadedStrings--- >>> :set -XRecordWildCards--{-| Every `Type` must obey the contract that if an expression's type matches the- the `expected` type then the `extract` function must succeed. If not, then- this exception is thrown-- This exception indicates that an invalid `Type` was provided to the `input`- function--}-data InvalidType s a = InvalidType- { invalidTypeExpected :: Expr s a- , invalidTypeExpression :: Expr s a- }- deriving (Typeable)--_ERROR :: String-_ERROR = "\ESC[1;31mError\ESC[0m"--instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (InvalidType s a) where- show InvalidType { .. } =- _ERROR <> ": Invalid Dhall.Type \n\- \ \n\- \Every Type must provide an extract function that succeeds if an expression \n\- \matches the expected type. You provided a Type that disobeys this contract \n\- \ \n\- \The Type provided has the expected dhall type: \n\- \ \n\- \" <> show txt0 <> "\n\- \ \n\- \and it couldn't extract a value from the well-typed expression: \n\- \ \n\- \" <> show txt1 <> "\n\- \ \n"- where- txt0 = Dhall.Util.insert invalidTypeExpected- txt1 = Dhall.Util.insert invalidTypeExpression---instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (InvalidType s a)---- | @since 1.16-data InputSettings = InputSettings- { _rootDirectory :: FilePath- , _sourceName :: FilePath- , _evaluateSettings :: EvaluateSettings- }---- | Default input settings: resolves imports relative to @.@ (the--- current working directory), report errors as coming from @(input)@,--- and default evaluation settings from 'defaultEvaluateSettings'.------ @since 1.16-defaultInputSettings :: InputSettings-defaultInputSettings = InputSettings- { _rootDirectory = "."- , _sourceName = "(input)"- , _evaluateSettings = defaultEvaluateSettings- }---- | Access the directory to resolve imports relative to.------ @since 1.16-rootDirectory- :: (Functor f)- => LensLike' f InputSettings FilePath-rootDirectory k s =- fmap (\x -> s { _rootDirectory = x }) (k (_rootDirectory s))---- | Access the name of the source to report locations from; this is--- only used in error messages, so it's okay if this is a best guess--- or something symbolic.------ @since 1.16-sourceName- :: (Functor f)- => LensLike' f InputSettings FilePath-sourceName k s =- fmap (\x -> s { _sourceName = x}) (k (_sourceName s))---- | @since 1.16-data EvaluateSettings = EvaluateSettings- { _startingContext :: Dhall.Context.Context (Expr Src X)- , _normalizer :: Maybe (Dhall.Core.ReifiedNormalizer X)- , _standardVersion :: StandardVersion- }---- | Default evaluation settings: no extra entries in the initial--- context, and no special normalizer behaviour.------ @since 1.16-defaultEvaluateSettings :: EvaluateSettings-defaultEvaluateSettings = EvaluateSettings- { _startingContext = Dhall.Context.empty- , _normalizer = Nothing- , _standardVersion = Dhall.Binary.defaultStandardVersion- }---- | Access the starting context used for evaluation and type-checking.------ @since 1.16-startingContext- :: (Functor f, HasEvaluateSettings s)- => LensLike' f s (Dhall.Context.Context (Expr Src X))-startingContext = evaluateSettings . l- where- l :: (Functor f)- => LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src X))- l k s = fmap (\x -> s { _startingContext = x}) (k (_startingContext s))---- | Access the custom normalizer.------ @since 1.16-normalizer- :: (Functor f, HasEvaluateSettings s)- => LensLike' f s (Maybe (Dhall.Core.ReifiedNormalizer X))-normalizer = evaluateSettings . l- where- l :: (Functor f)- => LensLike' f EvaluateSettings (Maybe (Dhall.Core.ReifiedNormalizer X))- l k s = fmap (\x -> s { _normalizer = x }) (k (_normalizer s))---- | Access the standard version (used primarily when encoding or decoding--- Dhall expressions to and from a binary representation)------ @since 1.17-standardVersion- :: (Functor f, HasEvaluateSettings s)- => LensLike' f s StandardVersion-standardVersion = evaluateSettings . l- where- l k s = fmap (\x -> s { _standardVersion = x}) (k (_standardVersion s))---- | @since 1.16-class HasEvaluateSettings s where- evaluateSettings- :: (Functor f)- => LensLike' f s EvaluateSettings--instance HasEvaluateSettings InputSettings where- evaluateSettings k s =- fmap (\x -> s { _evaluateSettings = x }) (k (_evaluateSettings s))--instance HasEvaluateSettings EvaluateSettings where- evaluateSettings = id--{-| Type-check and evaluate a Dhall program, decoding the result into Haskell-- The first argument determines the type of value that you decode:-->>> input integer "+2"-2->>> input (vector double) "[1.0, 2.0]"-[1.0,2.0]-- Use `auto` to automatically select which type to decode based on the- inferred return type:-->>> input auto "True" :: IO Bool-True-- This uses the settings from 'defaultInputSettings'.--}-input- :: Type a- -- ^ The type of value to decode from Dhall to Haskell- -> Text- -- ^ The Dhall program- -> IO a- -- ^ The decoded value in Haskell-input =- inputWithSettings defaultInputSettings--{-| Extend 'input' with a root directory to resolve imports relative- to, a file to mention in errors as the source, a custom typing- context, and a custom normalization process.--@since 1.16--}-inputWithSettings- :: InputSettings- -> Type a- -- ^ The type of value to decode from Dhall to Haskell- -> Text- -- ^ The Dhall program- -> IO a- -- ^ The decoded value in Haskell-inputWithSettings settings (Type {..}) txt = do- expr <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)-- let InputSettings {..} = settings-- let EvaluateSettings {..} = _evaluateSettings-- let transform =- set Dhall.Import.standardVersion _standardVersion- . set Dhall.Import.normalizer _normalizer- . set Dhall.Import.startingContext _startingContext-- let status = transform (Dhall.Import.emptyStatus _rootDirectory)-- expr' <- State.evalStateT (Dhall.Import.loadWith expr) status-- let suffix = Dhall.Pretty.Internal.prettyToStrictText expected- let annot = case expr' of- Note (Src begin end bytes) _ ->- Note (Src begin end bytes') (Annot expr' expected)- where- bytes' = bytes <> " : " <> suffix- _ ->- Annot expr' expected- _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)- let normExpr = Dhall.Core.normalizeWith (view normalizer settings) expr'-- case extract normExpr of- Just x -> return x- Nothing -> Control.Exception.throwIO- (InvalidType expected expr')--{-| Type-check and evaluate a Dhall program that is read from the- file-system.-- This uses the settings from 'defaultEvaluateSettings'.-- @since 1.16--}-inputFile- :: Type a- -- ^ The type of value to decode from Dhall to Haskell- -> FilePath- -- ^ The path to the Dhall program.- -> IO a- -- ^ The decoded value in Haskell.-inputFile =- inputFileWithSettings defaultEvaluateSettings--{-| Extend 'inputFile' with a custom typing context and a custom- normalization process.--@since 1.16--}-inputFileWithSettings- :: EvaluateSettings- -> Type a- -- ^ The type of value to decode from Dhall to Haskell- -> FilePath- -- ^ The path to the Dhall program.- -> IO a- -- ^ The decoded value in Haskell.-inputFileWithSettings settings ty path = do- text <- Data.Text.IO.readFile path- let inputSettings = InputSettings- { _rootDirectory = takeDirectory path- , _sourceName = path- , _evaluateSettings = settings- }- inputWithSettings inputSettings ty text--{-| Similar to `input`, but without interpreting the Dhall `Expr` into a Haskell- type.-- Uses the settings from 'defaultInputSettings'.--}-inputExpr- :: Text- -- ^ The Dhall program- -> IO (Expr Src X)- -- ^ The fully normalized AST-inputExpr =- inputExprWithSettings defaultInputSettings--{-| Extend 'inputExpr' with a root directory to resolve imports relative- to, a file to mention in errors as the source, a custom typing- context, and a custom normalization process.--@since 1.16--}-inputExprWithSettings- :: InputSettings- -> Text- -- ^ The Dhall program- -> IO (Expr Src X)- -- ^ The fully normalized AST-inputExprWithSettings settings txt = do- expr <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)-- let InputSettings {..} = settings-- let EvaluateSettings {..} = _evaluateSettings-- let transform =- set Dhall.Import.standardVersion _standardVersion- . set Dhall.Import.normalizer _normalizer- . set Dhall.Import.startingContext _startingContext-- let status = transform (Dhall.Import.emptyStatus _rootDirectory)-- expr' <- State.evalStateT (Dhall.Import.loadWith expr) status-- _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) expr')- pure (Dhall.Core.normalizeWith (view normalizer settings) expr')---- | Use this function to extract Haskell values directly from Dhall AST.--- The intended use case is to allow easy extraction of Dhall values for--- making the function `Dhall.Core.normalizeWith` easier to use.------ For other use cases, use `input` from `Dhall` module. It will give you--- a much better user experience.-rawInput- :: Alternative f- => Type a- -- ^ The type of value to decode from Dhall to Haskell- -> Expr s X- -- ^ a closed form Dhall program, which evaluates to the expected type- -> f a- -- ^ The decoded value in Haskell-rawInput (Type {..}) expr = do- case extract (Dhall.Core.normalize expr) of- Just x -> pure x- Nothing -> empty--{-| Use this to provide more detailed error messages-->> input auto "True" :: IO Integer-> *** Exception: Error: Expression doesn't match annotation->-> True : Integer->-> (input):1:1-->> detailed (input auto "True") :: IO Integer-> *** Exception: Error: Expression doesn't match annotation->-> Explanation: You can annotate an expression with its type or kind using the-> ❰:❱ symbol, like this:->->-> ┌───────┐-> │ x : t │ ❰x❱ is an expression and ❰t❱ is the annotated type or kind of ❰x❱-> └───────┘->-> The type checker verifies that the expression's type or kind matches the-> provided annotation->-> For example, all of the following are valid annotations that the type checker-> accepts:->->-> ┌─────────────┐-> │ 1 : Natural │ ❰1❱ is an expression that has type ❰Natural❱, so the type-> └─────────────┘ checker accepts the annotation->->-> ┌───────────────────────┐-> │ Natural/even 2 : Bool │ ❰Natural/even 2❱ has type ❰Bool❱, so the type-> └───────────────────────┘ checker accepts the annotation->->-> ┌────────────────────┐-> │ List : Type → Type │ ❰List❱ is an expression that has kind ❰Type → Type❱,-> └────────────────────┘ so the type checker accepts the annotation->->-> ┌──────────────────┐-> │ List Text : Type │ ❰List Text❱ is an expression that has kind ❰Type❱, so-> └──────────────────┘ the type checker accepts the annotation->->-> However, the following annotations are not valid and the type checker will-> reject them:->->-> ┌──────────┐-> │ 1 : Text │ The type checker rejects this because ❰1❱ does not have type-> └──────────┘ ❰Text❱->->-> ┌─────────────┐-> │ List : Type │ ❰List❱ does not have kind ❰Type❱-> └─────────────┘->->-> You or the interpreter annotated this expression:->-> ↳ True->-> ... with this type or kind:->-> ↳ Integer->-> ... but the inferred type or kind of the expression is actually:->-> ↳ Bool->-> Some common reasons why you might get this error:->-> ● The Haskell Dhall interpreter implicitly inserts a top-level annotation-> matching the expected type->-> For example, if you run the following Haskell code:->->-> ┌───────────────────────────────┐-> │ >>> input auto "1" :: IO Text │-> └───────────────────────────────┘->->-> ... then the interpreter will actually type check the following annotated-> expression:->->-> ┌──────────┐-> │ 1 : Text │-> └──────────┘->->-> ... and then type-checking will fail->-> ────────────────────────────────────────────────────────────────────────────────->-> True : Integer->-> (input):1:1---}-detailed :: IO a -> IO a-detailed =- Control.Exception.handle handler1 . Control.Exception.handle handler0- where- handler0 :: Imported (TypeError Src X) -> IO a- handler0 (Imported ps e) =- Control.Exception.throwIO (Imported ps (DetailedTypeError e))-- handler1 :: TypeError Src X -> IO a- handler1 e = Control.Exception.throwIO (DetailedTypeError e)--{-| A @(Type a)@ represents a way to marshal a value of type @\'a\'@ from Dhall- into Haskell-- You can produce `Type`s either explicitly:--> example :: Type (Vector Text)-> example = vector text-- ... or implicitly using `auto`:--> example :: Type (Vector Text)-> example = auto-- You can consume `Type`s using the `input` function:--> input :: Type a -> Text -> IO a--}-data Type a = Type- { extract :: Expr Src X -> Maybe a- -- ^ Extracts Haskell value from the Dhall expression- , expected :: Expr Src X- -- ^ Dhall type of the Haskell value- }- deriving (Functor)--{-| Decode a `Bool`-->>> input bool "True"-True--}-bool :: Type Bool-bool = Type {..}- where- extract (BoolLit b) = pure b- extract _ = Nothing-- expected = Bool--{-| Decode a `Natural`-->>> input natural "42"-42--}-natural :: Type Natural-natural = Type {..}- where- extract (NaturalLit n) = pure n- extract _ = empty-- expected = Natural--{-| Decode an `Integer`-->>> input integer "+42"-42--}-integer :: Type Integer-integer = Type {..}- where- extract (IntegerLit n) = pure n- extract _ = empty-- expected = Integer--{-| Decode a `Scientific`-->>> input scientific "1e100"-1.0e100--}-scientific :: Type Scientific-scientific = fmap Data.Scientific.fromFloatDigits double--{-| Decode a `Double`-->>> input double "42.0"-42.0--}-double :: Type Double-double = Type {..}- where- extract (DoubleLit n) = pure n- extract _ = empty-- expected = Double--{-| Decode lazy `Text`-->>> input lazyText "\"Test\""-"Test"--}-lazyText :: Type Data.Text.Lazy.Text-lazyText = Type {..}- where- extract (TextLit (Chunks [] t)) = pure (Data.Text.Lazy.fromStrict t)- extract _ = empty-- expected = Text--{-| Decode strict `Text`-->>> input strictText "\"Test\""-"Test"--}-strictText :: Type Text-strictText = fmap Data.Text.Lazy.toStrict lazyText--{-| Decode a `Maybe`-->>> input (maybe natural) "Some 1"-Just 1--}-maybe :: Type a -> Type (Maybe a)-maybe (Type extractIn expectedIn) = Type extractOut expectedOut- where- extractOut (Some e ) = fmap Just (extractIn e)- extractOut (App None _) = return Nothing- extractOut _ = empty-- expectedOut = App Optional expectedIn--{-| Decode a `Seq`-->>> input (sequence natural) "[1, 2, 3]"-fromList [1,2,3]--}-sequence :: Type a -> Type (Seq a)-sequence (Type extractIn expectedIn) = Type extractOut expectedOut- where- extractOut (ListLit _ es) = traverse extractIn es- extractOut _ = Nothing-- expectedOut = App List expectedIn--{-| Decode a list-->>> input (list natural) "[1, 2, 3]"-[1,2,3]--}-list :: Type a -> Type [a]-list = fmap Data.Foldable.toList . sequence--{-| Decode a `Vector`-->>> input (vector natural) "[1, 2, 3]"-[1,2,3]--}-vector :: Type a -> Type (Vector a)-vector = fmap Data.Vector.fromList . list--{-| Decode @()@ from an empty record.-->>> input unit "{=}" -- GHC doesn't print the result if it is ()---}-unit :: Type ()-unit = Type extractOut expectedOut- where- extractOut (RecordLit fields)- | Data.Foldable.null fields = return ()- extractOut _ = Nothing-- expectedOut = Record mempty--{-| Decode a `String`-->>> input string "\"ABC\""-"ABC"---}-string :: Type String-string = Data.Text.Lazy.unpack <$> lazyText--{-| Given a pair of `Type`s, decode a tuple-record into their pairing.-->>> input (pair natural bool) "{ _1 = 42, _2 = False }"-(42,False)--}-pair :: Type a -> Type b -> Type (a, b)-pair l r = Type extractOut expectedOut- where- extractOut (RecordLit fields) =- (,) <$> ( Dhall.Map.lookup "_1" fields >>= extract l )- <*> ( Dhall.Map.lookup "_2" fields >>= extract r )- extractOut _ = Nothing-- expectedOut =- Record- (Dhall.Map.fromList- [ ("_1", expected l)- , ("_2", expected r)- ]- )--{-| Any value that implements `Interpret` can be automatically decoded based on- the inferred return type of `input`-->>> input auto "[1, 2, 3]" :: IO (Vector Natural)-[1,2,3]-- This class auto-generates a default implementation for records that- implement `Generic`. This does not auto-generate an instance for recursive- types.--}-class Interpret a where- autoWith:: InterpretOptions -> Type a- default autoWith- :: (Generic a, GenericInterpret (Rep a)) => InterpretOptions -> Type a- autoWith options = fmap GHC.Generics.to (evalState (genericAutoWith options) 1)--instance Interpret Bool where- autoWith _ = bool--instance Interpret Natural where- autoWith _ = natural--instance Interpret Integer where- autoWith _ = integer--instance Interpret Scientific where- autoWith _ = scientific--instance Interpret Double where- autoWith _ = double--instance {-# OVERLAPS #-} Interpret [Char] where- autoWith _ = string--instance Interpret Data.Text.Lazy.Text where- autoWith _ = lazyText--instance Interpret Text where- autoWith _ = strictText--instance Interpret a => Interpret (Maybe a) where- autoWith opts = maybe (autoWith opts)--instance Interpret a => Interpret (Seq a) where- autoWith opts = sequence (autoWith opts)--instance Interpret a => Interpret [a] where- autoWith = fmap (fmap Data.Vector.toList) autoWith--instance Interpret a => Interpret (Vector a) where- autoWith opts = vector (autoWith opts)--instance (Inject a, Interpret b) => Interpret (a -> b) where- autoWith opts = Type extractOut expectedOut- where- normalizer_ = Just (inputNormalizer opts)-- extractOut e = Just (\i -> case extractIn (Dhall.Core.normalizeWith normalizer_ (App e (embed i))) of- Just o -> o- Nothing -> error "Interpret: You cannot decode a function if it does not have the correct type" )-- expectedOut = Pi "_" declared expectedIn-- InputType {..} = inject-- Type extractIn expectedIn = autoWith opts--instance (Interpret a, Interpret b) => Interpret (a, b)--{-| Use the default options for interpreting a configuration file--> auto = autoWith defaultInterpretOptions--}-auto :: Interpret a => Type a-auto = autoWith defaultInterpretOptions--{-| `genericAuto` is the default implementation for `auto` if you derive- `Interpret`. The difference is that you can use `genericAuto` without- having to explicitly provide an `Interpret` instance for a type as long as- the type derives `Generic`--}-genericAuto :: (Generic a, GenericInterpret (Rep a)) => Type a-genericAuto = fmap to (evalState (genericAutoWith defaultInterpretOptions) 1)--{-| Use these options to tweak how Dhall derives a generic implementation of- `Interpret`--}-data InterpretOptions = InterpretOptions- { fieldModifier :: Text -> Text- -- ^ Function used to transform Haskell field names into their corresponding- -- Dhall field names- , constructorModifier :: Text -> Text- -- ^ Function used to transform Haskell constructor names into their- -- corresponding Dhall alternative names- , inputNormalizer :: Dhall.Core.ReifiedNormalizer X- -- ^ This is only used by the `Interpret` instance for functions in order- -- to normalize the function input before marshaling the input into a- -- Dhall expression- }--{-| Default interpret options, which you can tweak or override, like this:--> autoWith-> (defaultInterpretOptions { fieldModifier = Data.Text.Lazy.dropWhile (== '_') })--}-defaultInterpretOptions :: InterpretOptions-defaultInterpretOptions = InterpretOptions- { fieldModifier = id- , constructorModifier = id- , inputNormalizer = Dhall.Core.ReifiedNormalizer (const (pure Nothing))- }--{-| This is the underlying class that powers the `Interpret` class's support- for automatically deriving a generic implementation--}-class GenericInterpret f where- genericAutoWith :: InterpretOptions -> State Int (Type (f a))--instance GenericInterpret f => GenericInterpret (M1 D d f) where- genericAutoWith options = do- res <- genericAutoWith options- pure (fmap M1 res)--instance GenericInterpret V1 where- genericAutoWith _ = pure Type {..}- where- extract _ = Nothing-- expected = Union mempty--unsafeExpectUnion- :: Text -> Expr Src X -> Dhall.Map.Map Text (Maybe (Expr Src X))-unsafeExpectUnion _ (Union kts) =- kts-unsafeExpectUnion name expression =- Dhall.Core.internalError- (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)--unsafeExpectRecord :: Text -> Expr Src X -> Dhall.Map.Map Text (Expr Src X)-unsafeExpectRecord _ (Record kts) =- kts-unsafeExpectRecord name expression =- Dhall.Core.internalError- (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)--unsafeExpectUnionLit- :: Text- -> Expr Src X- -> (Text, Maybe (Expr Src X))-unsafeExpectUnionLit _ (Field (Union _) k) =- (k, Nothing)-unsafeExpectUnionLit _ (App (Field (Union _) k) v) =- (k, Just v)-unsafeExpectUnionLit name expression =- Dhall.Core.internalError- (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)--unsafeExpectRecordLit :: Text -> Expr Src X -> Dhall.Map.Map Text (Expr Src X)-unsafeExpectRecordLit _ (RecordLit kvs) =- kvs-unsafeExpectRecordLit name expression =- Dhall.Core.internalError- (name <> ": Unexpected constructor: " <> Dhall.Core.pretty expression)--notEmptyRecordLit :: Expr s a -> Maybe (Expr s a)-notEmptyRecordLit e = case e of- RecordLit m | null m -> Nothing- _ -> Just e--notEmptyRecord :: Expr s a -> Maybe (Expr s a)-notEmptyRecord e = case e of- Record m | null m -> Nothing- _ -> Just e-extractUnionConstructor- :: Expr s a -> Maybe (Text, Expr s a, Dhall.Map.Map Text (Maybe (Expr s a)))-extractUnionConstructor (UnionLit fld e rest) =- return (fld, e, rest)-extractUnionConstructor (App (Field (Union kts) fld) e) =- return (fld, e, Dhall.Map.delete fld kts)-extractUnionConstructor (Field (Union kts) fld) =- return (fld, RecordLit mempty, Dhall.Map.delete fld kts)-extractUnionConstructor _ =- empty--instance (Constructor c1, Constructor c2, GenericInterpret f1, GenericInterpret f2) => GenericInterpret (M1 C c1 f1 :+: M1 C c2 f2) where- genericAutoWith options@(InterpretOptions {..}) = pure (Type {..})- where- nL :: M1 i c1 f1 a- nL = undefined-- nR :: M1 i c2 f2 a- nR = undefined-- nameL = constructorModifier (Data.Text.pack (conName nL))- nameR = constructorModifier (Data.Text.pack (conName nR))-- extract e0 = do- (name, e1, _) <- extractUnionConstructor e0- if- | name == nameL -> fmap (L1 . M1) (extractL e1)- | name == nameR -> fmap (R1 . M1) (extractR e1)- | otherwise -> Nothing-- expected =- Union- (Dhall.Map.fromList- [ (nameL, notEmptyRecord expectedL)- , (nameR, notEmptyRecord expectedR)- ]- )-- Type extractL expectedL = evalState (genericAutoWith options) 1- Type extractR expectedR = evalState (genericAutoWith options) 1--instance (Constructor c, GenericInterpret (f :+: g), GenericInterpret h) => GenericInterpret ((f :+: g) :+: M1 C c h) where- genericAutoWith options@(InterpretOptions {..}) = pure (Type {..})- where- n :: M1 i c h a- n = undefined-- name = constructorModifier (Data.Text.pack (conName n))-- extract u = do- (name', e, _) <- extractUnionConstructor u- if- | name == name' -> fmap (R1 . M1) (extractR e)- | otherwise -> fmap L1 (extractL u)-- expected =- Union (Dhall.Map.insert name (notEmptyRecord expectedR) ktsL)-- Type extractL expectedL = evalState (genericAutoWith options) 1- Type extractR expectedR = evalState (genericAutoWith options) 1-- ktsL = unsafeExpectUnion "genericAutoWith (:+:)" expectedL--instance (Constructor c, GenericInterpret f, GenericInterpret (g :+: h)) => GenericInterpret (M1 C c f :+: (g :+: h)) where- genericAutoWith options@(InterpretOptions {..}) = pure (Type {..})- where- n :: M1 i c f a- n = undefined-- name = constructorModifier (Data.Text.pack (conName n))-- extract u = do- (name', e, _) <- extractUnionConstructor u- if- | name == name' -> fmap (L1 . M1) (extractL e)- | otherwise -> fmap R1 (extractR u)-- expected =- Union (Dhall.Map.insert name (notEmptyRecord expectedL) ktsR)-- Type extractL expectedL = evalState (genericAutoWith options) 1- Type extractR expectedR = evalState (genericAutoWith options) 1-- ktsR = unsafeExpectUnion "genericAutoWith (:+:)" expectedR--instance (GenericInterpret (f :+: g), GenericInterpret (h :+: i)) => GenericInterpret ((f :+: g) :+: (h :+: i)) where- genericAutoWith options = pure (Type {..})- where- extract e = fmap L1 (extractL e) <|> fmap R1 (extractR e)-- expected = Union (Dhall.Map.union ktsL ktsR)-- Type extractL expectedL = evalState (genericAutoWith options) 1- Type extractR expectedR = evalState (genericAutoWith options) 1-- ktsL = unsafeExpectUnion "genericAutoWith (:+:)" expectedL- ktsR = unsafeExpectUnion "genericAutoWith (:+:)" expectedR--instance GenericInterpret f => GenericInterpret (M1 C c f) where- genericAutoWith options = do- res <- genericAutoWith options- pure (fmap M1 res)--instance GenericInterpret U1 where- genericAutoWith _ = pure (Type {..})- where- extract _ = Just U1-- expected = Record (Dhall.Map.fromList [])--instance (GenericInterpret f, GenericInterpret g) => GenericInterpret (f :*: g) where- genericAutoWith options = do- Type extractL expectedL <- genericAutoWith options- Type extractR expectedR <- genericAutoWith options- let ktsL = unsafeExpectRecord "genericAutoWith (:*:)"expectedL- let ktsR = unsafeExpectRecord "genericAutoWith (:*:)"expectedR- pure- (Type- { extract = liftA2 (liftA2 (:*:)) extractL extractR- , expected = Record (Dhall.Map.union ktsL ktsR)- }- )--getSelName :: Selector s => M1 i s f a -> State Int String-getSelName n = case selName n of- "" -> do i <- get- put (i + 1)- pure ("_" ++ show i)- nn -> pure nn--instance (Selector s, Interpret a) => GenericInterpret (M1 S s (K1 i a)) where- genericAutoWith opts@(InterpretOptions {..}) = do- name <- getSelName n- let extract (RecordLit m) = do- let name' = fieldModifier (Data.Text.pack name)- e <- Dhall.Map.lookup name' m- fmap (M1 . K1) (extract' e)- extract _ = Nothing- let expected =- Record (Dhall.Map.fromList [(key, expected')])- where- key = fieldModifier (Data.Text.pack name)- pure (Type {..})- where- n :: M1 i s f a- n = undefined-- Type extract' expected' = autoWith opts--{-| An @(InputType a)@ represents a way to marshal a value of type @\'a\'@ from- Haskell into Dhall--}-data InputType a = InputType- { embed :: a -> Expr Src X- -- ^ Embeds a Haskell value as a Dhall expression- , declared :: Expr Src X- -- ^ Dhall type of the Haskell value- }--instance Contravariant InputType where- contramap f (InputType embed declared) = InputType embed' declared- where- embed' x = embed (f x)--{-| This class is used by `Interpret` instance for functions:--> instance (Inject a, Interpret b) => Interpret (a -> b)-- You can convert Dhall functions with "simple" inputs (i.e. instances of this- class) into Haskell functions. This works by:-- * Marshaling the input to the Haskell function into a Dhall expression (i.e.- @x :: Expr Src X@)- * Applying the Dhall function (i.e. @f :: Expr Src X@) to the Dhall input- (i.e. @App f x@)- * Normalizing the syntax tree (i.e. @normalize (App f x)@)- * Marshaling the resulting Dhall expression back into a Haskell value--}-class Inject a where- injectWith :: InterpretOptions -> InputType a- default injectWith- :: (Generic a, GenericInject (Rep a)) => InterpretOptions -> InputType a- injectWith options- = contramap GHC.Generics.from (evalState (genericInjectWith options) 1)--{-| Use the default options for injecting a value--> inject = inject defaultInterpretOptions--}-inject :: Inject a => InputType a-inject = injectWith defaultInterpretOptions--{-| Use the default options for injecting a value, whose structure is-determined generically.--This can be used when you want to use 'Inject' on types that you don't-want to define orphan instances for.--}-genericInject- :: (Generic a, GenericInject (Rep a)) => InputType a-genericInject- = contramap GHC.Generics.from (evalState (genericInjectWith defaultInterpretOptions) 1)--instance Inject Bool where- injectWith _ = InputType {..}- where- embed = BoolLit-- declared = Bool--instance Inject Data.Text.Lazy.Text where- injectWith _ = InputType {..}- where- embed text =- TextLit (Chunks [] (Data.Text.Lazy.toStrict text))-- declared = Text--instance Inject Text where- injectWith _ = InputType {..}- where- embed text = TextLit (Chunks [] text)-- declared = Text--instance Inject Natural where- injectWith _ = InputType {..}- where- embed = NaturalLit-- declared = Natural--instance Inject Integer where- injectWith _ = InputType {..}- where- embed = IntegerLit-- declared = Integer--instance Inject Int where- injectWith _ = InputType {..}- where- embed = IntegerLit . toInteger-- declared = Integer--instance Inject Word8 where- injectWith _ = InputType {..}- where- embed = IntegerLit . toInteger-- declared = Integer--instance Inject Word16 where- injectWith _ = InputType {..}- where- embed = IntegerLit . toInteger-- declared = Integer--instance Inject Word32 where- injectWith _ = InputType {..}- where- embed = IntegerLit . toInteger-- declared = Integer--instance Inject Word64 where- injectWith _ = InputType {..}- where- embed = IntegerLit . toInteger-- declared = Integer--instance Inject Double where- injectWith _ = InputType {..}- where- embed = DoubleLit-- declared = Double--instance Inject () where- injectWith _ = InputType {..}- where- embed = const (RecordLit mempty)-- declared = Record mempty--instance Inject a => Inject (Maybe a) where- injectWith options = InputType embedOut declaredOut- where- embedOut (Just x) =- OptionalLit declaredIn (pure (embedIn x))- embedOut Nothing =- OptionalLit declaredIn empty-- InputType embedIn declaredIn = injectWith options-- declaredOut = App Optional declaredIn--instance Inject a => Inject (Seq a) where- injectWith options = InputType embedOut declaredOut- where- embedOut xs = ListLit (Just declaredIn) (fmap embedIn xs)-- declaredOut = App List declaredIn-- InputType embedIn declaredIn = injectWith options--instance Inject a => Inject [a] where- injectWith = fmap (contramap Data.Sequence.fromList) injectWith--instance Inject a => Inject (Vector a) where- injectWith = fmap (contramap Data.Vector.toList) injectWith--instance Inject a => Inject (Data.Set.Set a) where- injectWith = fmap (contramap Data.Set.toList) injectWith--instance (Inject a, Inject b) => Inject (a, b)--{-| This is the underlying class that powers the `Interpret` class's support- for automatically deriving a generic implementation--}-class GenericInject f where- genericInjectWith :: InterpretOptions -> State Int (InputType (f a))--instance GenericInject f => GenericInject (M1 D d f) where- genericInjectWith options = do- res <- genericInjectWith options- pure (contramap unM1 res)--instance GenericInject f => GenericInject (M1 C c f) where- genericInjectWith options = do- res <- genericInjectWith options- pure (contramap unM1 res)--instance (Constructor c1, Constructor c2, GenericInject f1, GenericInject f2) => GenericInject (M1 C c1 f1 :+: M1 C c2 f2) where- genericInjectWith options@(InterpretOptions {..}) = pure (InputType {..})- where- embed (L1 (M1 l)) =- case notEmptyRecordLit (embedL l) of- Nothing ->- Field declared keyL- Just valL ->- App (Field declared keyL) valL-- embed (R1 (M1 r)) =- case notEmptyRecordLit (embedR r) of- Nothing ->- Field declared keyR- Just valR ->- App (Field declared keyR) valR-- declared =- Union- (Dhall.Map.fromList- [ (keyL, notEmptyRecord declaredL)- , (keyR, notEmptyRecord declaredR)- ]- )-- nL :: M1 i c1 f1 a- nL = undefined-- nR :: M1 i c2 f2 a- nR = undefined-- keyL = constructorModifier (Data.Text.pack (conName nL))- keyR = constructorModifier (Data.Text.pack (conName nR))-- InputType embedL declaredL = evalState (genericInjectWith options) 1- InputType embedR declaredR = evalState (genericInjectWith options) 1--instance (Constructor c, GenericInject (f :+: g), GenericInject h) => GenericInject ((f :+: g) :+: M1 C c h) where- genericInjectWith options@(InterpretOptions {..}) = pure (InputType {..})- where- embed (L1 l) =- case maybeValL of- Nothing -> Field declared keyL- Just valL -> App (Field declared keyL) valL- where- (keyL, maybeValL) =- unsafeExpectUnionLit "genericInjectWith (:+:)" (embedL l)- embed (R1 (M1 r)) =- case notEmptyRecordLit (embedR r) of- Nothing -> Field declared keyR- Just valR -> App (Field declared keyR) valR-- nR :: M1 i c h a- nR = undefined-- keyR = constructorModifier (Data.Text.pack (conName nR))-- declared = Union (Dhall.Map.insert keyR (notEmptyRecord declaredR) ktsL)-- InputType embedL declaredL = evalState (genericInjectWith options) 1- InputType embedR declaredR = evalState (genericInjectWith options) 1-- ktsL = unsafeExpectUnion "genericInjectWith (:+:)" declaredL--instance (Constructor c, GenericInject f, GenericInject (g :+: h)) => GenericInject (M1 C c f :+: (g :+: h)) where- genericInjectWith options@(InterpretOptions {..}) = pure (InputType {..})- where- embed (L1 (M1 l)) =- case notEmptyRecordLit (embedL l) of- Nothing -> Field declared keyL- Just valL -> App (Field declared keyL) valL- embed (R1 r) =- case maybeValR of- Nothing -> Field declared keyR- Just valR -> App (Field declared keyR) valR- where- (keyR, maybeValR) =- unsafeExpectUnionLit "genericInjectWith (:+:)" (embedR r)-- nL :: M1 i c f a- nL = undefined-- keyL = constructorModifier (Data.Text.pack (conName nL))-- declared = Union (Dhall.Map.insert keyL (notEmptyRecord declaredL) ktsR)-- InputType embedL declaredL = evalState (genericInjectWith options) 1- InputType embedR declaredR = evalState (genericInjectWith options) 1-- ktsR = unsafeExpectUnion "genericInjectWith (:+:)" declaredR--instance (GenericInject (f :+: g), GenericInject (h :+: i)) => GenericInject ((f :+: g) :+: (h :+: i)) where- genericInjectWith options = pure (InputType {..})- where- embed (L1 l) =- case maybeValL of- Nothing -> Field declared keyL- Just valL -> App (Field declared keyL) valL- where- (keyL, maybeValL) =- unsafeExpectUnionLit "genericInjectWith (:+:)" (embedL l)- embed (R1 r) =- case maybeValR of- Nothing -> Field declared keyR- Just valR -> App (Field declared keyR) valR- where- (keyR, maybeValR) =- unsafeExpectUnionLit "genericInjectWith (:+:)" (embedR r)-- declared = Union (Dhall.Map.union ktsL ktsR)-- InputType embedL declaredL = evalState (genericInjectWith options) 1- InputType embedR declaredR = evalState (genericInjectWith options) 1-- ktsL = unsafeExpectUnion "genericInjectWith (:+:)" declaredL- ktsR = unsafeExpectUnion "genericInjectWith (:+:)" declaredR--instance (GenericInject f, GenericInject g) => GenericInject (f :*: g) where- genericInjectWith options = do- InputType embedInL declaredInL <- genericInjectWith options- InputType embedInR declaredInR <- genericInjectWith options-- let embed (l :*: r) =- RecordLit (Dhall.Map.union mapL mapR)- where- mapL =- unsafeExpectRecordLit "genericInjectWith (:*:)" (embedInL l)-- mapR =- unsafeExpectRecordLit "genericInjectWith (:*:)" (embedInR r)-- let declared = Record (Dhall.Map.union mapL mapR)- where- mapL = unsafeExpectRecord "genericInjectWith (:*:)" declaredInL- mapR = unsafeExpectRecord "genericInjectWith (:*:)" declaredInR-- pure (InputType {..})--instance GenericInject U1 where- genericInjectWith _ = pure (InputType {..})- where- embed _ = RecordLit mempty-- declared = Record mempty--instance (Selector s, Inject a) => GenericInject (M1 S s (K1 i a)) where- genericInjectWith opts@(InterpretOptions {..}) = do- name <- fieldModifier . Data.Text.pack <$> getSelName n- let embed (M1 (K1 x)) =- RecordLit (Dhall.Map.singleton name (embedIn x))- let declared =- Record (Dhall.Map.singleton name declaredIn)- pure (InputType {..})- where- n :: M1 i s f a- n = undefined-- InputType embedIn declaredIn = injectWith opts--{-| The 'RecordType' applicative functor allows you to build a 'Type' parser- from a Dhall record.-- For example, let's take the following Haskell data type:-->>> :{-data Project = Project- { projectName :: Text- , projectDescription :: Text- , projectStars :: Natural- }-:}-- And assume that we have the following Dhall record that we would like to- parse as a @Project@:--> { name =-> "dhall-haskell"-> , description =-> "A configuration language guaranteed to terminate"-> , stars =-> 289-> }-- Our parser has type 'Type' @Project@, but we can't build that out of any- smaller parsers, as 'Type's cannot be combined (they are only 'Functor's).- However, we can use a 'RecordType' to build a 'Type' for @Project@:-->>> :{-project :: Type Project-project =- record- ( Project <$> field "name" strictText- <*> field "description" strictText- <*> field "stars" natural- )-:}--}--newtype RecordType a =- RecordType- ( Data.Functor.Product.Product- ( Control.Applicative.Const- ( Dhall.Map.Map- Text- ( Expr Src X )- )- )- ( Data.Functor.Compose.Compose- ( (->) ( Expr Src X ) )- Maybe- )- a- )- deriving (Functor, Applicative)----- | Run a 'RecordType' parser to build a 'Type' parser.-record :: RecordType a -> Dhall.Type a-record ( RecordType ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Data.Functor.Compose.Compose extractF ) ) ) =- Type- { extract =- extractF- , expected =- Record fields- }----- | Parse a single field of a record.-field :: Text -> Type a -> RecordType a-field key valueType =- let- extractBody expr = do- RecordLit fields <-- return expr-- Dhall.Map.lookup key fields- >>= extract valueType-- in- RecordType- ( Data.Functor.Product.Pair- ( Control.Applicative.Const- ( Dhall.Map.singleton- key- ( Dhall.expected valueType )- )- )- ( Data.Functor.Compose.Compose extractBody )- )--{-| The 'UnionType' monoid allows you to build a 'Type' parser- from a Dhall union-- For example, let's take the following Haskell data type:-->>> :{-data Status = Queued Natural- | Result Text- | Errored Text-:}-- And assume that we have the following Dhall union that we would like to- parse as a @Status@:--> < Result = "Finish succesfully"-> | Queued : Natural-> | Errored : Text-> >-- Our parser has type 'Type' @Status@, but we can't build that out of any- smaller parsers, as 'Type's cannot be combined (they are only 'Functor's).- However, we can use a 'UnionType' to build a 'Type' for @Status@:-->>> :{-status :: Type Status-status = union- ( ( Queued <$> constructor "Queued" natural )- <> ( Result <$> constructor "Result" strictText )- <> ( Errored <$> constructor "Errored" strictText )- )-:}---}-newtype UnionType a =- UnionType- ( Data.Functor.Compose.Compose (Dhall.Map.Map Text) Type a )- deriving (Functor)--instance Data.Semigroup.Semigroup (UnionType a) where- (<>) = coerce ((<>) :: Dhall.Map.Map Text (Type a) -> Dhall.Map.Map Text (Type a) -> Dhall.Map.Map Text (Type a))--instance Monoid (UnionType a) where- mempty = coerce (mempty :: Dhall.Map.Map Text (Type a))- mappend = (Data.Semigroup.<>)---- | Run a 'UnionType' parser to build a 'Type' parser.-union :: UnionType a -> Type a-union (UnionType (Data.Functor.Compose.Compose mp)) = Type- { extract = extractF- , expected = Union expect- }- where- expect = (notEmptyRecord . Dhall.expected) <$> mp-- extractF e0 = do- (fld, e1, rest) <- extractUnionConstructor e0-- t <- Dhall.Map.lookup fld mp-- guard $ Dhall.Core.Union rest `Dhall.Core.judgmentallyEqual`- Dhall.Core.Union (Dhall.Map.delete fld expect)-- extract t e1---- | Parse a single constructor of a union-constructor :: Text -> Type a -> UnionType a-constructor key valueType = UnionType- ( Data.Functor.Compose.Compose (Dhall.Map.singleton key valueType) )--{-| The 'RecordInputType' divisible (contravariant) functor allows you to build- an 'InputType' injector for a Dhall record.-- For example, let's take the following Haskell data type:-->>> :{-data Project = Project- { projectName :: Text- , projectDescription :: Text- , projectStars :: Natural- }-:}-- And assume that we have the following Dhall record that we would like to- parse as a @Project@:--> { name =-> "dhall-haskell"-> , description =-> "A configuration language guaranteed to terminate"-> , stars =-> 289-> }-- Our injector has type 'InputType' @Project@, but we can't build that out of any- smaller injectors, as 'InputType's cannot be combined (they are only 'Contravariant's).- However, we can use an 'InputRecordType' to build an 'InputType' for @Project@:-->>> :{-injectProject :: InputType Project-injectProject =- inputRecord- ( adapt >$< inputFieldWith "name" inject- >*< inputFieldWith "description" inject- >*< inputFieldWith "stars" inject- )- where- adapt (Project{..}) = (projectName, (projectDescription, projectStars))-:}-- Or, since we are simply using the `Inject` instance to inject each field, we could write-->>> :{-injectProject :: InputType Project-injectProject =- inputRecord- ( adapt >$< inputField "name"- >*< inputField "description"- >*< inputField "stars"- )- where- adapt (Project{..}) = (projectName, (projectDescription, projectStars))-:}---}---- | Infix 'divided'-(>*<) :: Divisible f => f a -> f b -> f (a, b)-(>*<) = divided--infixr 5 >*<--newtype RecordInputType a- = RecordInputType (Dhall.Map.Map Text (InputType a))--instance Contravariant RecordInputType where- contramap f (RecordInputType inputTypeRecord) = RecordInputType $ contramap f <$> inputTypeRecord--instance Divisible RecordInputType where- divide f (RecordInputType bInputTypeRecord) (RecordInputType cInputTypeRecord) =- RecordInputType- $ Dhall.Map.union- ((contramap $ fst . f) <$> bInputTypeRecord)- ((contramap $ snd . f) <$> cInputTypeRecord)- conquer = RecordInputType mempty--inputFieldWith :: Text -> InputType a -> RecordInputType a-inputFieldWith name inputType = RecordInputType $ Dhall.Map.singleton name inputType--inputField :: Inject a => Text -> RecordInputType a-inputField name = inputFieldWith name inject--inputRecord :: RecordInputType a -> InputType a-inputRecord (RecordInputType inputTypeRecord) = InputType makeRecordLit recordType- where- recordType = Record $ declared <$> inputTypeRecord- makeRecordLit x = RecordLit $ (($ x) . embed) <$> inputTypeRecord--{-| The 'UnionInputType' monoid allows you to build- an 'InputType' injector for a Dhall record.-- For example, let's take the following Haskell data type:-->>> :{-data Status = Queued Natural- | Result Text- | Errored Text-:}-- And assume that we have the following Dhall union that we would like to- parse as a @Status@:--> < Result = "Finish succesfully"-> | Queued : Natural-> | Errored : Text-> >-- Our injector has type 'InputType' @Status@, but we can't build that out of any- smaller injectors, as 'InputType's cannot be combined.- However, we can use an 'UnionInputType' to build an 'InputType' for @Status@:-->>> :{-injectStatus :: InputType Status-injectStatus = adapt >$< inputUnion- ( inputConstructorWith "Queued" inject- >|< inputConstructorWith "Result" inject- >|< inputConstructorWith "Errored" inject- )- where- adapt (Queued n) = Left n- adapt (Result t) = Right (Left t)- adapt (Errored e) = Right (Right e)-:}-- Or, since we are simply using the `Inject` instance to inject each branch, we could write-->>> :{-injectStatus :: InputType Status-injectStatus = adapt >$< inputUnion- ( inputConstructor "Queued"- >|< inputConstructor "Result"- >|< inputConstructor "Errored"- )- where- adapt (Queued n) = Left n- adapt (Result t) = Right (Left t)- adapt (Errored e) = Right (Right e)-:}---}-newtype UnionInputType a =- UnionInputType- ( Data.Functor.Product.Product- ( Control.Applicative.Const- ( Dhall.Map.Map- Text- ( Expr Src X )- )- )- ( Op (Text, Expr Src X) )- a- )- deriving (Contravariant)---- | Combines two 'UnionInputType' values. See 'UnionInputType' for usage--- notes.------ Ideally, this matches 'Data.Functor.Contravariant.Divisible.chosen';--- however, this allows 'UnionInputType' to not need a 'Divisible' instance--- itself (since no instance is possible).-(>|<) :: UnionInputType a -> UnionInputType b -> UnionInputType (Either a b)-UnionInputType (Data.Functor.Product.Pair (Control.Applicative.Const mx) (Op fx))- >|< UnionInputType (Data.Functor.Product.Pair (Control.Applicative.Const my) (Op fy)) =- UnionInputType- ( Data.Functor.Product.Pair- ( Control.Applicative.Const (mx <> my) )- ( Op (either fx fy) )- )--infixr 5 >|<--inputUnion :: UnionInputType a -> InputType a-inputUnion ( UnionInputType ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Op embedF ) ) ) =- InputType- { embed = \x ->- let (name, y) = embedF x- in case notEmptyRecordLit y of- Nothing -> Field (Union fields') name- Just val -> App (Field (Union fields') name) val- , declared =- Union fields'- }- where- fields' = fmap notEmptyRecord fields--inputConstructorWith- :: Text- -> InputType a- -> UnionInputType a-inputConstructorWith name inputType = UnionInputType $- Data.Functor.Product.Pair- ( Control.Applicative.Const- ( Dhall.Map.singleton- name- ( declared inputType )- )- )- ( Op ( (name,) . embed inputType )- )--inputConstructor- :: Inject a- => Text- -> UnionInputType a-inputConstructor name = inputConstructorWith name inject+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining+ how to use the language, the compiler, and this library+-}++module Dhall+ (+ -- * Input+ input+ , inputWithSettings+ , inputFile+ , inputFileWithSettings+ , inputExpr+ , inputExprWithSettings+ , interpretExpr+ , interpretExprWithSettings+ , fromExpr+ , fromExprWithSettings+ , rootDirectory+ , sourceName+ , startingContext+ , substitutions+ , normalizer+ , newManager+ , defaultInputSettings+ , InputSettings+ , defaultEvaluateSettings+ , EvaluateSettings+ , HasEvaluateSettings(..)+ , detailed++ -- * Decoders+ , module Dhall.Marshal.Decode++ -- * Encoders+ , module Dhall.Marshal.Encode++ -- * Individual phases+ , parseWithSettings+ , resolveWithSettings+ , resolveAndStatusWithSettings+ , typecheckWithSettings+ , checkWithSettings+ , expectWithSettings+ , normalizeWithSettings++ -- * Miscellaneous+ , rawInput+ ) where++import Control.Applicative (Alternative, empty)+import Control.Monad.Catch (MonadThrow, throwM)+import Data.Either.Validation (Validation (..))+import Data.Void (Void)+import Dhall.Import (Imported (..), Status)+import Dhall.Parser (Src (..))+import Dhall.Syntax (Expr (..), Import)+import Dhall.TypeCheck (DetailedTypeError (..), TypeError)+import GHC.Generics+import Lens.Micro (Lens', lens)+import Lens.Micro.Extras (view)+import Prelude hiding (maybe, sequence)+import System.FilePath (takeDirectory)++import qualified Control.Exception+import qualified Control.Monad.Trans.State.Strict as State+import qualified Data.Text.IO+import qualified Dhall.Context+import qualified Dhall.Core as Core+import qualified Dhall.Import+import qualified Dhall.Parser+import qualified Dhall.Pretty.Internal+import qualified Dhall.Substitution+import qualified Dhall.TypeCheck+import qualified Lens.Micro as Lens++import Dhall.Marshal.Decode+import Dhall.Marshal.Encode++-- | @since 1.16+data InputSettings = InputSettings+ { _rootDirectory :: FilePath+ , _sourceName :: FilePath+ , _evaluateSettings :: EvaluateSettings+ }++-- | Default input settings: resolves imports relative to @.@ (the+-- current working directory), report errors as coming from @(input)@,+-- and default evaluation settings from 'defaultEvaluateSettings'.+--+-- @since 1.16+defaultInputSettings :: InputSettings+defaultInputSettings = InputSettings+ { _rootDirectory = "."+ , _sourceName = "(input)"+ , _evaluateSettings = defaultEvaluateSettings+ }+++-- | Access the directory to resolve imports relative to.+--+-- @since 1.16+rootDirectory :: Lens' InputSettings FilePath+rootDirectory = lens _rootDirectory (\s x -> s { _rootDirectory = x })++-- | Access the name of the source to report locations from; this is+-- only used in error messages, so it's okay if this is a best guess+-- or something symbolic.+--+-- @since 1.16+sourceName :: Lens' InputSettings FilePath+sourceName = lens _sourceName (\s x -> s { _sourceName = x})++-- | @since 1.16+data EvaluateSettings = EvaluateSettings+ { _substitutions :: Dhall.Substitution.Substitutions Src Void+ , _startingContext :: Dhall.Context.Context (Expr Src Void)+ , _normalizer :: Maybe (Core.ReifiedNormalizer Void)+ , _newManager :: IO Dhall.Import.Manager+ }++-- | Default evaluation settings: no extra entries in the initial+-- context, and no special normalizer behaviour.+--+-- @since 1.16+defaultEvaluateSettings :: EvaluateSettings+defaultEvaluateSettings = EvaluateSettings+ { _substitutions = Dhall.Substitution.empty+ , _startingContext = Dhall.Context.empty+ , _normalizer = Nothing+ , _newManager = Dhall.Import.defaultNewManager+ }++-- | Access the starting context used for evaluation and type-checking.+--+-- @since 1.16+startingContext+ :: (HasEvaluateSettings s)+ => Lens' s (Dhall.Context.Context (Expr Src Void))+startingContext =+ evaluateSettings+ . lens _startingContext (\s x -> s { _startingContext = x})++-- | Access the custom substitutions.+--+-- @since 1.30+substitutions+ :: (HasEvaluateSettings s)+ => Lens' s (Dhall.Substitution.Substitutions Src Void)+substitutions =+ evaluateSettings+ . lens _substitutions (\s x -> s { _substitutions = x })++-- | Access the custom normalizer.+--+-- @since 1.16+normalizer+ :: (HasEvaluateSettings s)+ => Lens' s (Maybe (Core.ReifiedNormalizer Void))+normalizer =+ evaluateSettings+ . lens _normalizer (\s x -> s { _normalizer = x })++-- | Access the HTTP manager initializer.+--+-- @since 1.36+newManager+ :: (HasEvaluateSettings s)+ => Lens' s (IO Dhall.Import.Manager)+newManager =+ evaluateSettings+ . lens _newManager (\s x -> s { _newManager = x })++-- | @since 1.16+class HasEvaluateSettings s where+ evaluateSettings :: Lens' s EvaluateSettings++instance HasEvaluateSettings InputSettings where+ evaluateSettings =+ lens _evaluateSettings (\s x -> s { _evaluateSettings = x })++instance HasEvaluateSettings EvaluateSettings where+ evaluateSettings = id++-- | Parse an expression, using the supplied `InputSettings`+parseWithSettings :: MonadThrow m => InputSettings -> Text -> m (Expr Src Import)+parseWithSettings settings text =+ either throwM return (Dhall.Parser.exprFromText (view sourceName settings) text)++-- | Type-check an expression, using the supplied `InputSettings`+typecheckWithSettings :: MonadThrow m => InputSettings -> Expr Src Void -> m ()+typecheckWithSettings settings expression =+ either throwM (return . const ()) (Dhall.TypeCheck.typeWith (view startingContext settings) expression)++{-| Type-check an expression against a type provided as a Dhall expreession,+ using the supplied `InputSettings`+-}+checkWithSettings ::+ MonadThrow m =>+ -- | The input settings+ InputSettings ->+ -- | The expected type of the expression+ Expr Src Void ->+ -- | The expression to check+ Expr Src Void ->+ m ()+checkWithSettings settings type_ expression = do+ let suffix = Dhall.Pretty.Internal.prettyToStrictText type_++ let annotated = case expression of+ Note (Src begin end bytes) _ ->+ Note (Src begin end bytes') (Annot expression type_)+ where+ bytes' = bytes <> " : " <> suffix+ _ ->+ Annot expression type_++ typecheckWithSettings settings annotated++{-| Type-check an expression against a `Decoder`'s expected type, using the+ supplied `InputSettings`.+ This is equivalent of using the 'expected' type of a @Decoder@ as the second+ argument to 'checkWithSettings'.+-}+expectWithSettings :: MonadThrow m => InputSettings -> Decoder a -> Expr Src Void -> m ()+expectWithSettings settings Decoder{..} expression = do+ expected' <- case expected of+ Success x -> return x+ Failure e -> throwM e++ checkWithSettings settings expected' expression++{-| Resolve an expression, using the supplied `InputSettings`++ Note that this also applies any substitutions specified in the+ `InputSettings`+-}+resolveWithSettings :: InputSettings -> Expr Src Import -> IO (Expr Src Void)+resolveWithSettings settings expression =+ fst <$> resolveAndStatusWithSettings settings expression++-- | A version of 'resolveWithSettings' that also returns the import 'Status'+-- together with the resolved expression.+resolveAndStatusWithSettings+ :: InputSettings+ -> Expr Src Import+ -> IO (Expr Src Void, Status)+resolveAndStatusWithSettings settings expression = do+ let InputSettings{..} = settings++ let EvaluateSettings{..} = _evaluateSettings++ let transform =+ Lens.set Dhall.Import.substitutions _substitutions+ . Lens.set Dhall.Import.normalizer _normalizer+ . Lens.set Dhall.Import.startingContext _startingContext++ let status = transform (Dhall.Import.emptyStatusWithManager _newManager _rootDirectory)++ (resolved, status') <- State.runStateT (Dhall.Import.loadWith expression) status++ let substituted = Dhall.Substitution.substitute resolved (view substitutions settings)++ pure (substituted, status')++-- | Normalize an expression, using the supplied `InputSettings`+normalizeWithSettings :: InputSettings -> Expr Src Void -> Expr Src Void+normalizeWithSettings settings =+ Core.normalizeWith (view normalizer settings)++{-| Type-check and evaluate a Dhall program, decoding the result into Haskell++ The first argument determines the type of value that you decode:++>>> input integer "+2"+2+>>> input (vector double) "[1.0, 2.0]"+[1.0,2.0]++ Use `auto` to automatically select which type to decode based on the+ inferred return type:++>>> input auto "True" :: IO Bool+True++ This uses the settings from 'defaultInputSettings'.+-}+input+ :: Decoder a+ -- ^ The decoder for the Dhall value+ -> Text+ -- ^ The Dhall program+ -> IO a+ -- ^ The decoded value in Haskell+input =+ inputWithSettings defaultInputSettings++{-| Extend 'input' with a root directory to resolve imports relative+ to, a file to mention in errors as the source, a custom typing+ context, and a custom normalization process.++@since 1.16+-}+inputWithSettings+ :: InputSettings+ -> Decoder a+ -- ^ The decoder for the Dhall value+ -> Text+ -- ^ The Dhall program+ -> IO a+ -- ^ The decoded value in Haskell+inputWithSettings settings decoder@Decoder{..} text = do+ parsed <- parseWithSettings settings text++ resolved <- resolveWithSettings settings parsed++ expectWithSettings settings decoder resolved++ let normalized = normalizeWithSettings settings resolved++ case extract normalized of+ Success x -> return x+ Failure e -> Control.Exception.throwIO e++{-| Type-check and evaluate a Dhall program that is read from the+ file-system.++ This uses the settings from 'defaultEvaluateSettings'.++ @since 1.16+-}+inputFile+ :: Decoder a+ -- ^ The decoder for the Dhall value+ -> FilePath+ -- ^ The path to the Dhall program.+ -> IO a+ -- ^ The decoded value in Haskell.+inputFile =+ inputFileWithSettings defaultEvaluateSettings++{-| Extend 'inputFile' with a custom typing context and a custom+ normalization process.++@since 1.16+-}+inputFileWithSettings+ :: EvaluateSettings+ -> Decoder a+ -- ^ The decoder for the Dhall value+ -> FilePath+ -- ^ The path to the Dhall program.+ -> IO a+ -- ^ The decoded value in Haskell.+inputFileWithSettings settings ty path = do+ text <- Data.Text.IO.readFile path+ let inputSettings = InputSettings+ { _rootDirectory = takeDirectory path+ , _sourceName = path+ , _evaluateSettings = settings+ }+ inputWithSettings inputSettings ty text++{-| Similar to `input`, but without interpreting the Dhall `Expr` into a Haskell+ type.++ Uses the settings from 'defaultInputSettings'.+-}+inputExpr+ :: Text+ -- ^ The Dhall program+ -> IO (Expr Src Void)+ -- ^ The fully normalized AST+inputExpr =+ inputExprWithSettings defaultInputSettings++{-| Extend 'inputExpr' with a root directory to resolve imports relative+ to, a file to mention in errors as the source, a custom typing+ context, and a custom normalization process.++@since 1.16+-}+inputExprWithSettings+ :: InputSettings+ -> Text+ -- ^ The Dhall program+ -> IO (Expr Src Void)+ -- ^ The fully normalized AST+inputExprWithSettings settings text = do+ parsed <- parseWithSettings settings text++ resolved <- resolveWithSettings settings parsed++ _ <- typecheckWithSettings settings resolved++ pure (Core.normalizeWith (view normalizer settings) resolved)++{-| Interpret a Dhall Expression++ This takes care of import resolution, type-checking, and normalization+-}+interpretExpr :: Expr Src Import -> IO (Expr Src Void)+interpretExpr = interpretExprWithSettings defaultInputSettings++-- | Like `interpretExpr`, but customizable using `InputSettings`+interpretExprWithSettings+ :: InputSettings -> Expr Src Import -> IO (Expr Src Void)+interpretExprWithSettings settings parsed = do+ resolved <- resolveWithSettings settings parsed++ typecheckWithSettings settings resolved++ pure (Core.normalizeWith (view normalizer settings) resolved)++{- | Decode a Dhall expression++ This takes care of import resolution, type-checking and normalization+-}+fromExpr :: Decoder a -> Expr Src Import -> IO a+fromExpr = fromExprWithSettings defaultInputSettings++-- | Like `fromExpr`, but customizable using `InputSettings`+fromExprWithSettings :: InputSettings -> Decoder a -> Expr Src Import -> IO a+fromExprWithSettings settings decoder@Decoder{..} expression = do+ resolved <- resolveWithSettings settings expression++ expectWithSettings settings decoder resolved++ let normalized = Core.normalizeWith (view normalizer settings) resolved++ case extract normalized of+ Success x -> return x+ Failure e -> Control.Exception.throwIO e++-- | Use this function to extract Haskell values directly from Dhall AST.+-- The intended use case is to allow easy extraction of Dhall values for+-- making the function `Core.normalizeWith` easier to use.+--+-- For other use cases, use `input` from "Dhall" module. It will give you+-- a much better user experience.+rawInput+ :: Alternative f+ => Decoder a+ -- ^ The decoder for the Dhall value+ -> Expr s Void+ -- ^ a closed form Dhall program, which evaluates to the expected type+ -> f a+ -- ^ The decoded value in Haskell+rawInput (Decoder {..}) expr =+ case extract (Core.normalize expr) of+ Success x -> pure x+ Failure _e -> empty++{-| Use this to provide more detailed error messages++>> input auto "True" :: IO Integer+> *** Exception: Error: Expression doesn't match annotation+>+> True : Integer+>+> (input):1:1++>> detailed (input auto "True") :: IO Integer+> *** Exception: Error: Expression doesn't match annotation+>+> Explanation: You can annotate an expression with its type or kind using the+> ❰:❱ symbol, like this:+>+>+> ┌───────┐+> │ x : t │ ❰x❱ is an expression and ❰t❱ is the annotated type or kind of ❰x❱+> └───────┘+>+> The type checker verifies that the expression's type or kind matches the+> provided annotation+>+> For example, all of the following are valid annotations that the type checker+> accepts:+>+>+> ┌─────────────┐+> │ 1 : Natural │ ❰1❱ is an expression that has type ❰Natural❱, so the type+> └─────────────┘ checker accepts the annotation+>+>+> ┌───────────────────────┐+> │ Natural/even 2 : Bool │ ❰Natural/even 2❱ has type ❰Bool❱, so the type+> └───────────────────────┘ checker accepts the annotation+>+>+> ┌────────────────────┐+> │ List : Type → Type │ ❰List❱ is an expression that has kind ❰Type → Type❱,+> └────────────────────┘ so the type checker accepts the annotation+>+>+> ┌──────────────────┐+> │ List Text : Type │ ❰List Text❱ is an expression that has kind ❰Type❱, so+> └──────────────────┘ the type checker accepts the annotation+>+>+> However, the following annotations are not valid and the type checker will+> reject them:+>+>+> ┌──────────┐+> │ 1 : Text │ The type checker rejects this because ❰1❱ does not have type+> └──────────┘ ❰Text❱+>+>+> ┌─────────────┐+> │ List : Type │ ❰List❱ does not have kind ❰Type❱+> └─────────────┘+>+>+> You or the interpreter annotated this expression:+>+> ↳ True+>+> ... with this type or kind:+>+> ↳ Integer+>+> ... but the inferred type or kind of the expression is actually:+>+> ↳ Bool+>+> Some common reasons why you might get this error:+>+> ● The Haskell Dhall interpreter implicitly inserts a top-level annotation+> matching the expected type+>+> For example, if you run the following Haskell code:+>+>+> ┌───────────────────────────────┐+> │ >>> input auto "1" :: IO Text │+> └───────────────────────────────┘+>+>+> ... then the interpreter will actually type check the following annotated+> expression:+>+>+> ┌──────────┐+> │ 1 : Text │+> └──────────┘+>+>+> ... and then type-checking will fail+>+> ────────────────────────────────────────────────────────────────────────────────+>+> True : Integer+>+> (input):1:1++-}+detailed :: IO a -> IO a+detailed =+ Control.Exception.handle handler1 . Control.Exception.handle handler0+ where+ handler0 :: Imported (TypeError Src Void) -> IO a+ handler0 (Imported ps e) =+ Control.Exception.throwIO (Imported ps (DetailedTypeError e))++ handler1 :: TypeError Src Void -> IO a+ handler1 e = Control.Exception.throwIO (DetailedTypeError e)
@@ -1,958 +1,1437 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE OverloadedStrings #-}--{-| This module contains logic for converting Dhall expressions to and from- CBOR expressions which can in turn be converted to and from a binary- representation--}--module Dhall.Binary- ( -- * Standard versions- StandardVersion(..)- , defaultStandardVersion- , parseStandardVersion- , renderStandardVersion-- -- * Encoding and decoding- , ToTerm(..)- , FromTerm(..)- , encodeExpression- , decodeExpression-- -- * Exceptions- , DecodingFailure(..)- ) where--import Codec.CBOR.Term (Term(..))-import Control.Applicative (empty, (<|>))-import Control.Exception (Exception)-import Dhall.Core- ( Binding(..)- , Chunks(..)- , Const(..)- , Directory(..)- , Expr(..)- , File(..)- , FilePrefix(..)- , Import(..)- , ImportHashed(..)- , ImportMode(..)- , ImportType(..)- , Scheme(..)- , URL(..)- , Var(..)- )--import Data.Foldable (toList)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Monoid ((<>))-import Data.Text (Text)-import Options.Applicative (Parser)-import Prelude hiding (exponent)-import GHC.Float (double2Float, float2Double)--import qualified Crypto.Hash-import qualified Data.ByteArray-import qualified Data.ByteString-import qualified Data.Sequence-import qualified Dhall.Map-import qualified Dhall.Set-import qualified Options.Applicative---- | Supported version strings-data StandardVersion- = NoVersion- -- ^ No version string- | V_5_0_0- -- ^ Version "5.0.0"- | V_4_0_0- -- ^ Version "4.0.0"- | V_3_0_0- -- ^ Version "3.0.0"- | V_2_0_0- -- ^ Version "2.0.0"- | V_1_0_0- -- ^ Version "1.0.0"- deriving (Enum, Bounded)--defaultStandardVersion :: StandardVersion-defaultStandardVersion = NoVersion--parseStandardVersion :: Parser StandardVersion-parseStandardVersion =- Options.Applicative.option readVersion- ( Options.Applicative.long "standard-version"- <> Options.Applicative.metavar "X.Y.Z"- <> Options.Applicative.help "The standard version to use"- <> Options.Applicative.value defaultStandardVersion- )- where- readVersion = do- string <- Options.Applicative.str- case string :: Text of- "none" -> return NoVersion- "1.0.0" -> return V_1_0_0- "2.0.0" -> return V_2_0_0- "3.0.0" -> return V_3_0_0- "4.0.0" -> return V_4_0_0- "5.0.0" -> return V_5_0_0- _ -> fail "Unsupported version"--renderStandardVersion :: StandardVersion -> Text-renderStandardVersion NoVersion = "none"-renderStandardVersion V_1_0_0 = "1.0.0"-renderStandardVersion V_2_0_0 = "2.0.0"-renderStandardVersion V_3_0_0 = "3.0.0"-renderStandardVersion V_4_0_0 = "4.0.0"-renderStandardVersion V_5_0_0 = "5.0.0"--{-| Convert a function applied to multiple arguments to the base function and- the list of arguments--}-unApply :: Expr s a -> (Expr s a, [Expr s a])-unApply e₀ = (baseFunction₀, diffArguments₀ [])- where- ~(baseFunction₀, diffArguments₀) = go e₀-- go (App f a) = (baseFunction, diffArguments . (a :))- where- ~(baseFunction, diffArguments) = go f-- go (Note _ e) = go e-- go baseFunction = (baseFunction, id)---- | Types that can be encoded as a CBOR `Term`-class ToTerm a where- encode :: a -> Term--instance ToTerm a => ToTerm (Expr s a) where- encode (Var (V "_" n)) =- TInteger n- encode (Var (V x n)) =- TList [ TString x, TInteger n ]- encode NaturalBuild =- TString "Natural/build"- encode NaturalFold =- TString "Natural/fold"- encode NaturalIsZero =- TString "Natural/isZero"- encode NaturalEven =- TString "Natural/even"- encode NaturalOdd =- TString "Natural/odd"- encode NaturalToInteger =- TString "Natural/toInteger"- encode NaturalShow =- TString "Natural/show"- encode IntegerToDouble =- TString "Integer/toDouble"- encode IntegerShow =- TString "Integer/show"- encode DoubleShow =- TString "Double/show"- encode ListBuild =- TString "List/build"- encode ListFold =- TString "List/fold"- encode ListLength =- TString "List/length"- encode ListHead =- TString "List/head"- encode ListLast =- TString "List/last"- encode ListIndexed =- TString "List/indexed"- encode ListReverse =- TString "List/reverse"- encode OptionalFold =- TString "Optional/fold"- encode OptionalBuild =- TString "Optional/build"- encode Bool =- TString "Bool"- encode Optional =- TString "Optional"- encode None =- TString "None"- encode Natural =- TString "Natural"- encode Integer =- TString "Integer"- encode Double =- TString "Double"- encode Text =- TString "Text"- encode TextShow =- TString "Text/show"- encode List =- TString "List"- encode (Const Type) =- TString "Type"- encode (Const Kind) =- TString "Kind"- encode (Const Sort) =- TString "Sort"- encode e@(App _ _) =- TList ([ TInt 0, f₁ ] ++ map encode arguments)- where- (f₀, arguments) = unApply e-- f₁ = encode f₀- encode (Lam "_" _A₀ b₀) =- TList [ TInt 1, _A₁, b₁ ]- where- _A₁ = encode _A₀- b₁ = encode b₀- encode (Lam x _A₀ b₀) =- TList [ TInt 1, TString x, _A₁, b₁ ]- where- _A₁ = encode _A₀- b₁ = encode b₀- encode (Pi "_" _A₀ _B₀) =- TList [ TInt 2, _A₁, _B₁ ]- where- _A₁ = encode _A₀- _B₁ = encode _B₀- encode (Pi x _A₀ _B₀) =- TList [ TInt 2, TString x, _A₁, _B₁ ]- where- _A₁ = encode _A₀- _B₁ = encode _B₀- encode (BoolOr l₀ r₀) =- TList [ TInt 3, TInt 0, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (BoolAnd l₀ r₀) =- TList [ TInt 3, TInt 1, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (BoolEQ l₀ r₀) =- TList [ TInt 3, TInt 2, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (BoolNE l₀ r₀) =- TList [ TInt 3, TInt 3, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (NaturalPlus l₀ r₀) =- TList [ TInt 3, TInt 4, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (NaturalTimes l₀ r₀) =- TList [ TInt 3, TInt 5, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (TextAppend l₀ r₀) =- TList [ TInt 3, TInt 6, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (ListAppend l₀ r₀) =- TList [ TInt 3, TInt 7, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (Combine l₀ r₀) =- TList [ TInt 3, TInt 8, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (Prefer l₀ r₀) =- TList [ TInt 3, TInt 9, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (CombineTypes l₀ r₀) =- TList [ TInt 3, TInt 10, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (ImportAlt l₀ r₀) =- TList [ TInt 3, TInt 11, l₁, r₁ ]- where- l₁ = encode l₀- r₁ = encode r₀- encode (ListLit _T₀ xs₀)- | null xs₀ = TList [ TInt 4, _T₁ ]- | otherwise = TList ([ TInt 4, TNull ] ++ xs₁)- where- _T₁ = case _T₀ of- Nothing -> TNull- Just t -> encode t-- xs₁ = map encode (Data.Foldable.toList xs₀)- encode (OptionalLit _T₀ Nothing) =- TList [ TInt 5, _T₁ ]- where- _T₁ = encode _T₀- encode (OptionalLit _T₀ (Just t₀)) =- TList [ TInt 5, _T₁, t₁ ]- where- _T₁ = encode _T₀- t₁ = encode t₀- encode (Some t₀) =- TList [ TInt 5, TNull, t₁ ]- where- t₁ = encode t₀- encode (Merge t₀ u₀ Nothing) =- TList [ TInt 6, t₁, u₁ ]- where- t₁ = encode t₀- u₁ = encode u₀- encode (Merge t₀ u₀ (Just _T₀)) =- TList [ TInt 6, t₁, u₁, _T₁ ]- where- t₁ = encode t₀- u₁ = encode u₀- _T₁ = encode _T₀- encode (Record xTs₀) =- TList [ TInt 7, TMap xTs₁ ]- where- xTs₁ = do- (x₀, _T₀) <- Dhall.Map.toList (Dhall.Map.sort xTs₀)- let x₁ = TString x₀- let _T₁ = encode _T₀- return (x₁, _T₁)- encode (RecordLit xts₀) =- TList [ TInt 8, TMap xts₁ ]- where- xts₁ = do- (x₀, t₀) <- Dhall.Map.toList (Dhall.Map.sort xts₀)- let x₁ = TString x₀- let t₁ = encode t₀- return (x₁, t₁)- encode (Field t₀ x) =- TList [ TInt 9, t₁, TString x ]- where- t₁ = encode t₀- encode (Project t₀ (Left xs₀)) =- TList ([ TInt 10, t₁ ] ++ xs₁)- where- t₁ = encode t₀- xs₁ = map TString (Dhall.Set.toList xs₀)- encode (Project t₀ (Right _T₀)) =- TList [ TInt 10, t₁, TList [ _T₁ ] ]- where- _T₁ = encode _T₀- t₁ = encode t₀- encode (Union xTs₀) =- TList [ TInt 11, TMap xTs₁ ]- where- xTs₁ = do- (x₀, mT₀) <- Dhall.Map.toList (Dhall.Map.sort xTs₀)-- let x₁ = TString x₀-- let _T₁ = case mT₀ of- Nothing -> TNull- Just _T₀ -> encode _T₀-- return (x₁, _T₁)- encode (UnionLit x t₀ yTs₀) =- TList [ TInt 12, TString x, t₁, TMap yTs₁ ]- where- t₁ = encode t₀-- yTs₁ = do- (y₀, mT₀) <- Dhall.Map.toList (Dhall.Map.sort yTs₀)- let y₁ = TString y₀- let _T₁ = case mT₀ of- Just _T₀ -> encode _T₀- Nothing -> TNull- return (y₁, _T₁)- encode (BoolLit b) =- TBool b- encode (BoolIf t₀ l₀ r₀) =- TList [ TInt 14, t₁, l₁, r₁ ]- where- t₁ = encode t₀- l₁ = encode l₀- r₁ = encode r₀- encode (NaturalLit n) =- TList [ TInt 15, TInteger (fromIntegral n) ]- encode (IntegerLit n) =- TList [ TInt 16, TInteger n ]- encode (DoubleLit n64)- -- cborg always encodes NaN as "7e00"- | isNaN n64 = THalf n32- | useHalf = THalf n32- | useFloat = TFloat n32- | otherwise = TDouble n64- where- n32 = double2Float n64- useFloat = n64 == float2Double n32- -- the other three cases for Half-floats are 0.0 and the infinities- useHalf = or $ fmap (n64 ==) [0.0, infinity, -infinity]- infinity = 1/0 :: Double- encode (TextLit (Chunks xys₀ z₀)) =- TList ([ TInt 18 ] ++ xys₁ ++ [ z₁ ])- where- xys₁ = do- (x₀, y₀) <- xys₀- let x₁ = TString x₀- let y₁ = encode y₀- [ x₁, y₁ ]-- z₁ = TString z₀- encode (Embed x) =- encode x- encode (Let as₀ b₀) =- TList ([ TInt 25 ] ++ as₁ ++ [ b₁ ])- where- as₁ = do- Binding x mA₀ a₀ <- toList as₀-- let mA₁ = case mA₀ of- Nothing -> TNull- Just _A₀ -> encode _A₀-- let a₁ = encode a₀-- [ TString x, mA₁, a₁ ]-- b₁ = encode b₀- encode (Annot t₀ _T₀) =- TList [ TInt 26, t₁, _T₁ ]- where- t₁ = encode t₀- _T₁ = encode _T₀- encode (Note _ e) =- encode e--instance ToTerm Import where- encode import_ =- case importType of- Remote (URL { scheme = scheme₀, ..}) ->- TList- ( prefix- ++ [ TInt scheme₁, using, TString authority ]- ++ map TString (reverse components)- ++ [ TString file ]- ++ (case query of Nothing -> [ TNull ]; Just q -> [ TString q ])- )- where- using = case headers of- Nothing ->- TNull- Just h ->- encode h-- scheme₁ = case scheme₀ of- HTTP -> 0- HTTPS -> 1- File {..} = path-- Directory {..} = directory-- Local prefix₀ path ->- TList- ( prefix- ++ [ TInt prefix₁ ]- ++ map TString components₁- ++ [ TString file ]- )- where- File {..} = path-- Directory {..} = directory-- prefix₁ = case prefix₀ of- Absolute -> 2- Here -> 3- Parent -> 4- Home -> 5-- components₁ = reverse components-- Env x ->- TList (prefix ++ [ TInt 6, TString x ])-- Missing ->- TList (prefix ++ [ TInt 7 ])- where- prefix = [ TInt 24, h, m ]- where- h = case hash of- Nothing ->- TNull- Just digest ->- TBytes ("\x12\x20" <> Data.ByteArray.convert digest)-- m = TInt (case importMode of Code -> 0; RawText -> 1)-- Import {..} = import_-- ImportHashed {..} = importHashed---- | Types that can be decoded from a CBOR `Term`-class FromTerm a where- decode :: Term -> Maybe a--instance FromTerm a => FromTerm (Expr s a) where- decode (TInt n) =- return (Var (V "_" (fromIntegral n)))- decode (TInteger n) =- return (Var (V "_" n))- decode (TString "Natural/build") =- return NaturalBuild- decode (TString "Natural/fold") =- return NaturalFold- decode (TString "Natural/isZero") =- return NaturalIsZero- decode (TString "Natural/even") =- return NaturalEven- decode (TString "Natural/odd") =- return NaturalOdd- decode (TString "Natural/toInteger") =- return NaturalToInteger- decode (TString "Natural/show") =- return NaturalShow- decode (TString "Integer/toDouble") =- return IntegerToDouble- decode (TString "Integer/show") =- return IntegerShow- decode (TString "Double/show") =- return DoubleShow- decode (TString "List/build") =- return ListBuild- decode (TString "List/fold") =- return ListFold- decode (TString "List/length") =- return ListLength- decode (TString "List/head") =- return ListHead- decode (TString "List/last") =- return ListLast- decode (TString "List/indexed") =- return ListIndexed- decode (TString "List/reverse") =- return ListReverse- decode (TString "Optional/fold") =- return OptionalFold- decode (TString "Optional/build") =- return OptionalBuild- decode (TString "Bool") =- return Bool- decode (TString "Optional") =- return Optional- decode (TString "None") =- return None- decode (TString "Natural") =- return Natural- decode (TString "Integer") =- return Integer- decode (TString "Double") =- return Double- decode (TString "Text") =- return Text- decode (TString "Text/show") =- return TextShow- decode (TString "List") =- return List- decode (TString "Type") =- return (Const Type)- decode (TString "Kind") =- return (Const Kind)- decode (TString "Sort") =- return (Const Sort)- decode (TString "_") =- empty- decode (TList [ TString x, TInt n ]) =- return (Var (V x (fromIntegral n)))- decode (TList [ TString x, TInteger n ]) =- return (Var (V x n))- decode (TList (TInt 0 : f₁ : xs₁)) = do- f₀ <- decode f₁- xs₀ <- traverse decode xs₁- return (foldl App f₀ xs₀)- decode (TList [ TInt 1, _A₁, b₁ ]) = do- _A₀ <- decode _A₁- b₀ <- decode b₁- return (Lam "_" _A₀ b₀)- decode (TList [ TInt 1, TString x, _A₁, b₁ ]) = do- _A₀ <- decode _A₁- b₀ <- decode b₁- return (Lam x _A₀ b₀)- decode (TList [ TInt 2, _A₁, _B₁ ]) = do- _A₀ <- decode _A₁- _B₀ <- decode _B₁- return (Pi "_" _A₀ _B₀)- decode (TList [ TInt 2, TString x, _A₁, _B₁ ]) = do- _A₀ <- decode _A₁- _B₀ <- decode _B₁- return (Pi x _A₀ _B₀)- decode (TList [ TInt 3, TInt n, l₁, r₁ ]) = do- l₀ <- decode l₁- r₀ <- decode r₁- op <- case n of- 0 -> return BoolOr- 1 -> return BoolAnd- 2 -> return BoolEQ- 3 -> return BoolNE- 4 -> return NaturalPlus- 5 -> return NaturalTimes- 6 -> return TextAppend- 7 -> return ListAppend- 8 -> return Combine- 9 -> return Prefer- 10 -> return CombineTypes- 11 -> return ImportAlt- _ -> empty- return (op l₀ r₀)- decode (TList [ TInt 4, _T₁ ]) = do- _T₀ <- decode _T₁- return (ListLit (Just _T₀) empty)- decode (TList (TInt 4 : TNull : xs₁ )) = do- xs₀ <- traverse decode xs₁- return (ListLit Nothing (Data.Sequence.fromList xs₀))- decode (TList [ TInt 5, _T₁ ]) = do- _T₀ <- decode _T₁- return (OptionalLit _T₀ Nothing)- decode (TList [ TInt 5, TNull, t₁ ]) = do- t₀ <- decode t₁- return (Some t₀)- decode (TList [ TInt 5, _T₁, t₁ ]) = do- _T₀ <- decode _T₁- t₀ <- decode t₁- return (OptionalLit _T₀ (Just t₀))- decode (TList [ TInt 6, t₁, u₁ ]) = do- t₀ <- decode t₁- u₀ <- decode u₁- return (Merge t₀ u₀ Nothing)- decode (TList [ TInt 6, t₁, u₁, _T₁ ]) = do- t₀ <- decode t₁- u₀ <- decode u₁- _T₀ <- decode _T₁- return (Merge t₀ u₀ (Just _T₀))- decode (TList [ TInt 7, TMap xTs₁ ]) = do- let process (TString x, _T₁) = do- _T₀ <- decode _T₁-- return (x, _T₀)- process _ =- empty-- xTs₀ <- traverse process xTs₁-- return (Record (Dhall.Map.fromList xTs₀))- decode (TList [ TInt 8, TMap xts₁ ]) = do- let process (TString x, t₁) = do- t₀ <- decode t₁-- return (x, t₀)- process _ =- empty-- xts₀ <- traverse process xts₁-- return (RecordLit (Dhall.Map.fromList xts₀))- decode (TList [ TInt 9, t₁, TString x ]) = do- t₀ <- decode t₁-- return (Field t₀ x)- decode (TList (TInt 10 : t₁ : xs₁)) = do- t₀ <- decode t₁-- let expectString (TString x) = return x- expectString _ = empty-- let decodeLeft = do- strings <- traverse expectString xs₁-- return (Left (Dhall.Set.fromList strings))-- let decodeRight =- case xs₁ of- [ TList [ _T₁ ] ] -> do- _T₀ <- decode _T₁-- return (Right _T₀)- _ -> do- empty-- xs₀ <- decodeLeft <|> decodeRight-- return (Project t₀ xs₀)- decode (TList [ TInt 11, TMap xTs₁ ]) = do- let process (TString x, _T₁) = do- mT₀ <- case _T₁ of- TNull -> return Nothing- _ -> fmap Just (decode _T₁)-- return (x, mT₀)- process _ =- empty-- xTs₀ <- traverse process xTs₁-- return (Union (Dhall.Map.fromList xTs₀))- decode (TList [ TInt 12, TString x, t₁, TMap yTs₁ ]) = do- t₀ <- decode t₁-- let process (TString y, _T₁) = do- _T₀ <- case _T₁ of- TNull -> return Nothing- _ -> fmap Just (decode _T₁)-- return (y, _T₀)- process _ =- empty-- yTs₀ <- traverse process yTs₁-- return (UnionLit x t₀ (Dhall.Map.fromList yTs₀))- decode (TBool b) = do- return (BoolLit b)- decode (TList [ TInt 14, t₁, l₁, r₁ ]) = do- t₀ <- decode t₁- l₀ <- decode l₁- r₀ <- decode r₁-- return (BoolIf t₀ l₀ r₀)- decode (TList [ TInt 15, TInt n ]) = do- return (NaturalLit (fromIntegral n))- decode (TList [ TInt 15, TInteger n ]) = do- return (NaturalLit (fromInteger n))- decode (TList [ TInt 16, TInt n ]) = do- return (IntegerLit (fromIntegral n))- decode (TList [ TInt 16, TInteger n ]) = do- return (IntegerLit n)- decode (THalf n) = do- return (DoubleLit (float2Double n))- decode (TFloat n) = do- return (DoubleLit (float2Double n))- decode (TDouble n) = do- return (DoubleLit n)- decode (TList (TInt 18 : xs)) = do- let process (TString x : y₁ : zs) = do- y₀ <- decode y₁-- ~(xys, z) <- process zs-- return ((x, y₀) : xys, z)- process [ TString z ] = do- return ([], z)- process _ = do- empty-- (xys, z) <- process xs-- return (TextLit (Chunks xys z))- decode e@(TList (TInt 24 : _)) = fmap Embed (decode e)- decode (TList (TInt 25 : xs)) = do- let process (TString x : _A₁ : a₁ : ls₁) = do- mA₀ <- case _A₁ of- TNull -> return Nothing- _ -> fmap Just (decode _A₁)-- a₀ <- decode a₁-- let binding = Binding x mA₀ a₀-- case ls₁ of- [ b₁ ] -> do- b₀ <- decode b₁-- return (Let (binding :| []) b₀)- _ -> do- Let (l₀ :| ls₀) b₀ <- process ls₁-- return (Let (binding :| (l₀ : ls₀)) b₀)- process _ = do- empty-- process xs- decode (TList [ TInt 26, t₁, _T₁ ]) = do- t₀ <- decode t₁- _T₀ <- decode _T₁- return (Annot t₀ _T₀)- decode _ =- empty--instance FromTerm Import where- decode (TList (TInt 24 : h : TInt mode : TInt n : xs)) = do- hash <- case h of- TNull -> do- return Nothing-- TBytes bytes -> do- let (prefix, suffix) = Data.ByteString.splitAt 2 bytes-- case prefix of- "\x12\x20" -> return ()- _ -> empty-- digest <- case Crypto.Hash.digestFromByteString suffix of- Nothing -> empty- Just digest -> return digest-- return (Just digest)-- _ -> do- empty-- importMode <- case mode of- 0 -> return Code- 1 -> return RawText- _ -> empty-- let remote scheme = do- let process [ TString file, q ] = do- query <- case q of- TNull -> return Nothing- TString x -> return (Just x)- _ -> empty- return ([], file, query)- process (TString path : ys) = do- (paths, file, query) <- process ys- return (path : paths, file, query)- process _ = do- empty-- (headers, authority, paths, file, query) <- case xs of- headers₀ : TString authority : ys -> do- headers₁ <- case headers₀ of- TNull -> do- return Nothing- _ -> do- headers <- decode headers₀-- return (Just headers)- (paths, file, query) <- process ys- return (headers₁, authority, paths, file, query)- _ -> do- empty-- let components = reverse paths- let directory = Directory {..}- let path = File {..}-- return (Remote (URL {..}))-- let local prefix = do- let process [ TString file ] = do- return ([], file)- process (TString path : ys) = do- (paths, file) <- process ys- return (path : paths, file)- process _ =- empty-- (paths, file) <- process xs-- let components = reverse paths- let directory = Directory {..}-- return (Local prefix (File {..}))-- let env = do- case xs of- [ TString x ] -> return (Env x)- _ -> empty-- let missing = return Missing-- importType <- case n of- 0 -> remote HTTP- 1 -> remote HTTPS- 2 -> local Absolute- 3 -> local Here- 4 -> local Parent- 5 -> local Home- 6 -> env- 7 -> missing- _ -> empty-- let importHashed = ImportHashed {..}-- return (Import {..})-- decode _ = empty--strip55799Tag :: Term -> Term-strip55799Tag term =- case term of- TInt a ->- TInt a- TInteger a ->- TInteger a- TBytes a ->- TBytes a- TBytesI a ->- TBytesI a- TString a ->- TString a- TStringI a ->- TStringI a- TList as ->- TList (fmap strip55799Tag as)- TListI as ->- TListI (fmap strip55799Tag as)- TMap as ->- TMap (fmap adapt as)- where- adapt (a, b) = (strip55799Tag a, strip55799Tag b)- TMapI as ->- TMapI (fmap adapt as)- where- adapt (a, b) = (strip55799Tag a, strip55799Tag b)- TTagged 55799 b ->- strip55799Tag b- TTagged a b->- TTagged a (strip55799Tag b)- TBool a ->- TBool a- TNull ->- TNull- TSimple a ->- TSimple a- THalf a ->- THalf a- TFloat a ->- TFloat a- TDouble a ->- TDouble a---- | Encode a Dhall expression as a CBOR `Term`-encodeExpression :: Expr s Import -> Term-encodeExpression = encode---- | Decode a Dhall expression from a CBOR `Term`-decodeExpression :: Term -> Either DecodingFailure (Expr s Import)-decodeExpression term =- case decodeWithoutVersion <|> decodeWithVersion of- Just expression -> Right expression- Nothing -> Left (CBORIsNotDhall term)- where- strippedTerm = strip55799Tag term- -- This is the behavior specified by the standard- decodeWithoutVersion = decode strippedTerm-- -- For backwards compatibility with older expressions that have a version- -- tag to ease the migration- decodeWithVersion = do- TList [ TString _, taggedTerm ] <- return strippedTerm- decode taggedTerm--data DecodingFailure = CBORIsNotDhall Term- deriving (Eq)--instance Exception DecodingFailure--_ERROR :: String-_ERROR = "\ESC[1;31mError\ESC[0m"--instance Show DecodingFailure where- show (CBORIsNotDhall term) =- _ERROR <> ": Cannot decode CBOR to Dhall\n"- <> "\n"- <> "The following CBOR expression does not encode a valid Dhall expression\n"- <> "\n"- <> "↳ " <> show term <> "\n"+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++{-| This module contains logic for converting Dhall expressions to and from+ CBOR expressions which can in turn be converted to and from a binary+ representation+-}++module Dhall.Binary+ ( -- * Encoding and decoding+ encodeExpression+ , decodeExpression++ -- * Exceptions+ , DecodingFailure(..)+ ) where++import Codec.CBOR.Decoding (Decoder, TokenType (..))+import Codec.CBOR.Encoding (Encoding)+import Codec.Serialise (Serialise (decode, encode))+import Control.Applicative (empty, (<|>))+import Control.Exception (Exception)+import Data.ByteString.Lazy (ByteString)+import Dhall.Syntax+ ( Binding (..)+ , Chunks (..)+ , Const (..)+ , DhallDouble (..)+ , Directory (..)+ , Expr (..)+ , File (..)+ , FilePrefix (..)+ , FunctionBinding (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , MultiLet (..)+ , PreferAnnotation (..)+ , RecordField (..)+ , Scheme (..)+ , URL (..)+ , Var (..)+ , WithComponent (..)+ )++import Data.Foldable (toList)+import Data.Ratio ((%))+import Data.Void (Void, absurd)+import GHC.Float (double2Float, float2Double)+import Numeric.Half (fromHalf, toHalf)+import Prelude hiding (exponent)++import qualified Codec.CBOR.ByteArray+import qualified Codec.CBOR.Decoding as Decoding+import qualified Codec.CBOR.Encoding as Encoding+import qualified Codec.CBOR.Read as Read+import qualified Codec.Serialise as Serialise+import qualified Data.ByteString+import qualified Data.ByteString.Lazy+import qualified Data.ByteString.Short+import qualified Data.Foldable as Foldable+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Sequence+import qualified Data.Time as Time+import qualified Dhall.Crypto+import qualified Dhall.Map+import qualified Dhall.Syntax as Syntax+import qualified Text.Printf as Printf++{-| Convert a function applied to multiple arguments to the base function and+ the list of arguments+-}+unApply :: Expr s a -> (Expr s a, [Expr s a])+unApply e₀ = (baseFunction₀, diffArguments₀ [])+ where+ ~(baseFunction₀, diffArguments₀) = go e₀++ go (App f a) = (baseFunction, diffArguments . (a :))+ where+ ~(baseFunction, diffArguments) = go f++ go (Note _ e) = go e++ go baseFunction = (baseFunction, id)++decodeExpressionInternal :: (Int -> Decoder s a) -> Decoder s (Expr t a)+decodeExpressionInternal decodeEmbed = go+ where+ go = do+ let die message = fail ("Dhall.Binary.decodeExpressionInternal: " <> message)++ tokenType₀ <- Decoding.peekTokenType++ case tokenType₀ of+ TypeUInt -> do+ !n <- fromIntegral <$> Decoding.decodeWord++ return (Var (V "_" n))++ TypeUInt64 -> do+ !n <- fromIntegral <$> Decoding.decodeWord64++ return (Var (V "_" n))++ TypeFloat16 -> do+ !n <- float2Double <$> Decoding.decodeFloat++ return (DoubleLit (DhallDouble n))++ TypeFloat32 -> do+ !n <- float2Double <$> Decoding.decodeFloat++ return (DoubleLit (DhallDouble n))++ TypeFloat64 -> do+ !n <- Decoding.decodeDouble++ return (DoubleLit (DhallDouble n))++ TypeBool -> do+ !b <- Decoding.decodeBool++ return (BoolLit b)++ TypeString -> do+ !ba <- Decoding.decodeUtf8ByteArray++ let sb = Codec.CBOR.ByteArray.toShortByteString ba++ case Data.ByteString.Short.length sb of+ 4 | sb == "Bool" -> return Bool+ | sb == "Date" -> return Date+ | sb == "List" -> return List+ | sb == "None" -> return None+ | sb == "Text" -> return Text+ | sb == "Time" -> return Time+ | sb == "Type" -> return (Const Type)+ | sb == "Kind" -> return (Const Kind)+ | sb == "Sort" -> return (Const Sort)+ 5 | sb == "Bytes" -> return Bytes+ 6 | sb == "Double" -> return Double+ 7 | sb == "Integer" -> return Integer+ | sb == "Natural" -> return Natural+ 8 | sb == "Optional" -> return Optional+ | sb == "TimeZone" -> return TimeZone+ 9 | sb == "Date/show" -> return DateShow+ | sb == "List/fold" -> return ListFold+ | sb == "List/head" -> return ListHead+ | sb == "List/last" -> return ListLast+ | sb == "Text/show" -> return TextShow+ | sb == "Time/show" -> return TimeShow+ 10 | sb == "List/build" -> return ListBuild+ 11 | sb == "Double/show" -> return DoubleShow+ | sb == "List/length" -> return ListLength+ | sb == "Natural/odd" -> return NaturalOdd+ 12 | sb == "Integer/show" -> return IntegerShow+ | sb == "List/indexed" -> return ListIndexed+ | sb == "List/reverse" -> return ListReverse+ | sb == "Natural/even" -> return NaturalEven+ | sb == "Natural/fold" -> return NaturalFold+ | sb == "Natural/show" -> return NaturalShow+ | sb == "Text/replace" -> return TextReplace+ 13 | sb == "Integer/clamp" -> return IntegerClamp+ | sb == "Natural/build" -> return NaturalBuild+ | sb == "TimeZone/show" -> return TimeZoneShow+ 14 | sb == "Integer/negate" -> return IntegerNegate+ | sb == "Natural/isZero" -> return NaturalIsZero+ 16 | sb == "Integer/toDouble" -> return IntegerToDouble+ | sb == "Natural/subtract" -> return NaturalSubtract+ 17 | sb == "Natural/toInteger" -> return NaturalToInteger+ _ -> die ("Unrecognized built-in: " <> show sb)++ TypeListLen -> do+ len <- Decoding.decodeListLen++ case len of+ 0 -> die "Missing tag"+ _ -> return ()++ tokenType₁ <- Decoding.peekTokenType++ case tokenType₁ of+ TypeString -> do+ x <- Decoding.decodeString++ if x == "_"+ then die "Non-standard encoding of an α-normalized variable"+ else return ()++ tokenType₂ <- Decoding.peekTokenType++ case tokenType₂ of+ TypeUInt -> do+ !n <- fromIntegral <$> Decoding.decodeWord++ return (Var (V x n))++ TypeUInt64 -> do+ !n <- fromIntegral <$> Decoding.decodeWord64++ return (Var (V x n))++ _ ->+ die ("Unexpected token type for variable index: " <> show tokenType₂)++ TypeUInt -> do+ tag <- Decoding.decodeWord++ case tag of+ 0 -> do+ !f <- go++ let loop n !acc+ | n <= 0 = return acc+ | otherwise = do+ !x <- go+ loop (n - 1) (App acc x)++ let nArgs = len - 2++ if nArgs <= 0+ then die "Non-standard encoding of a function with no arguments"+ else loop nArgs f++ 1 ->+ case len of+ 3 -> do+ _A <- go++ b <- go++ return (Lam mempty (Syntax.makeFunctionBinding "_" _A) b)++ 4 -> do+ x <- Decoding.decodeString++ if x == "_"+ then die "Non-standard encoding of a λ expression"+ else return ()++ _A <- go++ b <- go++ return (Lam mempty (Syntax.makeFunctionBinding x _A) b)++ _ ->+ die ("Incorrect number of tokens used to encode a λ expression: " <> show len)++ 2 ->+ case len of+ 3 -> do+ _A <- go++ _B <- go++ return (Pi mempty "_" _A _B)++ 4 -> do+ x <- Decoding.decodeString++ if x == "_"+ then die "Non-standard encoding of a ∀ expression"+ else return ()++ _A <- go++ _B <- go++ return (Pi mempty x _A _B)++ _ ->+ die ("Incorrect number of tokens used to encode a ∀ expression: " <> show len)++ 3 -> do+ opcode <- Decoding.decodeWord++ op <- case opcode of+ 0 -> return BoolOr+ 1 -> return BoolAnd+ 2 -> return BoolEQ+ 3 -> return BoolNE+ 4 -> return NaturalPlus+ 5 -> return NaturalTimes+ 6 -> return TextAppend+ 7 -> return ListAppend+ 8 -> return (Combine mempty Nothing)+ 9 -> return (Prefer mempty PreferFromSource)+ 10 -> return (CombineTypes mempty)+ 11 -> return ImportAlt+ 12 -> return (Equivalent mempty)+ 13 -> return RecordCompletion+ _ -> die ("Unrecognized operator code: " <> show opcode)++ l <- go++ r <- go++ return (op l r)++ 4 ->+ case len of+ 2 -> do+ _T <- go++ return (ListLit (Just (App List _T)) empty)++ _ -> do+ Decoding.decodeNull++ xs <- Data.Sequence.replicateA (len - 2) go+ return (ListLit Nothing xs)++ 5 -> do+ Decoding.decodeNull++ t <- go++ return (Some t)++ 6 -> do+ t <- go++ u <- go++ case len of+ 3 ->+ return (Merge t u Nothing)++ 4 -> do+ _T <- go++ return (Merge t u (Just _T))++ _ ->+ die ("Incorrect number of tokens used to encode a `merge` expression: " <> show len)++ 7 -> do+ mapLength <- Decoding.decodeMapLen++ xTs <- replicateDecoder mapLength $ do+ x <- Decoding.decodeString++ _T <- go++ return (x, Syntax.makeRecordField _T)++ return (Record (Dhall.Map.fromList xTs))++ 8 -> do+ mapLength <- Decoding.decodeMapLen++ xts <- replicateDecoder mapLength $ do+ x <- Decoding.decodeString++ t <- go++ return (x, Syntax.makeRecordField t)++ return (RecordLit (Dhall.Map.fromList xts))++ 9 -> do+ t <- go++ x <- Decoding.decodeString++ return (Field t (Syntax.makeFieldSelection x))++ 10 -> do+ t <- go++ xs <- case len of+ 3 -> do+ tokenType₂ <- Decoding.peekTokenType++ case tokenType₂ of+ TypeListLen -> do+ _ <- Decoding.decodeListLen++ _T <- go++ return (Right _T)++ TypeString -> do+ x <- Decoding.decodeString+ return (Left [x])++ _ ->+ die ("Unexpected token type for projection: " <> show tokenType₂)++ _ -> do+ xs <- replicateDecoder (len - 2) Decoding.decodeString++ return (Left xs)++ return (Project t xs)++ 11 -> do+ mapLength <- Decoding.decodeMapLen++ xTs <- replicateDecoder mapLength $ do+ x <- Decoding.decodeString++ tokenType₂ <- Decoding.peekTokenType++ mT <- case tokenType₂ of+ TypeNull -> do+ Decoding.decodeNull++ return Nothing++ _ -> do+ _T <- go++ return (Just _T)++ return (x, mT)++ return (Union (Dhall.Map.fromList xTs))++ 14 -> do+ t <- go++ l <- go++ r <- go++ return (BoolIf t l r)++ 15 -> do+ tokenType₂ <- Decoding.peekTokenType++ case tokenType₂ of+ TypeUInt -> do+ !n <- fromIntegral <$> Decoding.decodeWord++ return (NaturalLit n)++ TypeUInt64 -> do+ !n <- fromIntegral <$> Decoding.decodeWord64++ return (NaturalLit n)++ TypeInteger -> do+ !n <- fromIntegral <$> Decoding.decodeInteger+ return (NaturalLit n)++ _ ->+ die ("Unexpected token type for Natural literal: " <> show tokenType₂)++ 16 -> do+ tokenType₂ <- Decoding.peekTokenType++ case tokenType₂ of+ TypeUInt -> do+ !n <- fromIntegral <$> Decoding.decodeWord++ return (IntegerLit n)++ TypeUInt64 -> do+ !n <- fromIntegral <$> Decoding.decodeWord64++ return (IntegerLit n)++ TypeNInt -> do+ !n <- fromIntegral <$> Decoding.decodeNegWord++ return (IntegerLit $! (-1 - n))++ TypeNInt64 -> do+ !n <- fromIntegral <$> Decoding.decodeNegWord64++ return (IntegerLit $! (-1 - n))+ TypeInteger -> do+ n <- Decoding.decodeInteger+ return (IntegerLit n)++ _ ->+ die ("Unexpected token type for Integer literal: " <> show tokenType₂)++ 18 -> do+ xys <- replicateDecoder ((len - 2) `quot` 2) $ do+ x <- Decoding.decodeString++ y <- go++ return (x, y)++ z <- Decoding.decodeString++ return (TextLit (Chunks xys z))++ 19 -> do+ t <- go++ return (Assert t)++ 24 ->+ fmap Embed (decodeEmbed len)++ 25 -> do+ bindings <- replicateDecoder ((len - 2) `quot` 3) $ do+ x <- Decoding.decodeString++ tokenType₂ <- Decoding.peekTokenType++ mA <- case tokenType₂ of+ TypeNull -> do+ Decoding.decodeNull++ return Nothing++ _ -> do+ _A <- go++ return (Just (Nothing, _A))++ a <- go++ return (Binding Nothing x Nothing mA Nothing a)++ b <- go++ return (foldr Let b bindings)++ 26 -> do+ t <- go++ _T <- go++ return (Annot t _T)++ 27 -> do+ t <- go++ mT <- case len of+ 2 ->+ return Nothing++ 3 -> do+ _T <- go++ return (Just _T)++ _ ->+ die ("Incorrect number of tokens used to encode a type annotation: " <> show len)++ return (ToMap t mT)++ 28 -> do+ _T <- go++ return (ListLit (Just _T) empty)++ 29 -> do+ l <- go++ n <- Decoding.decodeListLen++ let decodeWithComponent = do+ tokenType₂ <- Decoding.peekTokenType+ case tokenType₂ of+ TypeString -> do+ fmap WithLabel Decoding.decodeString+ _ -> do+ m <- Decoding.decodeInt++ case m of+ 0 -> return WithQuestion+ _ -> die ("Unexpected integer encoding a with expression: " <> show n)+ ks₀ <- replicateDecoder n decodeWithComponent++ ks₁ <- case NonEmpty.nonEmpty ks₀ of+ Nothing ->+ die "0 field labels in decoded with expression"+ Just ks₁ ->+ return ks₁++ r <- go++ return (With l ks₁ r)++ 30 -> do+ _YYYY <- Decoding.decodeInt+ _MM <- Decoding.decodeInt+ _HH <- Decoding.decodeInt++ case Time.fromGregorianValid (fromIntegral _YYYY) _MM _HH of+ Nothing ->+ die "Invalid date"+ Just day ->+ return (DateLiteral day)+ 31 -> do+ hh <- Decoding.decodeInt+ mm <- Decoding.decodeInt+ tag₂ <- Decoding.decodeTag++ case tag₂ of+ 4 -> do+ return ()+ _ -> do+ die ("Unexpected tag for decimal fraction: " <> show tag)+ n <- Decoding.decodeListLen++ case n of+ 2 -> do+ return ()+ _ -> do+ die ("Invalid list length for decimal fraction: " <> show n)++ exponent <- Decoding.decodeInt++ tokenType₂ <- Decoding.peekTokenType++ mantissa <- case tokenType₂ of+ TypeUInt -> do+ fromIntegral <$> Decoding.decodeWord++ TypeUInt64 -> do+ fromIntegral <$> Decoding.decodeWord64++ TypeNInt -> do+ !i <- fromIntegral <$> Decoding.decodeNegWord++ return (-1 - i)++ TypeNInt64 -> do+ !i <- fromIntegral <$> Decoding.decodeNegWord64++ return (-1 - i)+ TypeInteger -> do+ Decoding.decodeInteger+ _ ->+ die ("Unexpected token type for mantissa: " <> show tokenType₂)+ let precision = fromIntegral (negate exponent)++ let ss = fromRational (mantissa % (10 ^ precision))++ return (TimeLiteral (Time.TimeOfDay hh mm ss) precision)+ 32 -> do+ b <- Decoding.decodeBool+ _HH <- Decoding.decodeInt+ _MM <- Decoding.decodeInt++ let sign = if b then id else negate++ let minutes = sign (_HH * 60 + _MM)++ return (TimeZoneLiteral (Time.TimeZone minutes False ""))++ 33 -> do+ b <- Decoding.decodeBytes++ return (BytesLit b)++ 34 -> do+ t <- go+ return (ShowConstructor t)+ _ ->+ die ("Unexpected tag: " <> show tag)++ _ ->+ die ("Unexpected tag type: " <> show tokenType₁)++ _ ->+ die ("Unexpected initial token: " <> show tokenType₀)++encodeExpressionInternal :: (a -> Encoding) -> Expr Void a -> Encoding+encodeExpressionInternal encodeEmbed = go+ where+ go e = case e of+ Var (V "_" n) ->+ Encoding.encodeInt n++ Var (V x n) ->+ Encoding.encodeListLen 2+ <> Encoding.encodeString x+ <> Encoding.encodeInt n++ NaturalBuild ->+ Encoding.encodeUtf8ByteArray "Natural/build"++ NaturalFold ->+ Encoding.encodeUtf8ByteArray "Natural/fold"++ NaturalIsZero ->+ Encoding.encodeUtf8ByteArray "Natural/isZero"++ NaturalEven ->+ Encoding.encodeUtf8ByteArray "Natural/even"++ NaturalOdd ->+ Encoding.encodeUtf8ByteArray "Natural/odd"++ NaturalToInteger ->+ Encoding.encodeUtf8ByteArray "Natural/toInteger"++ NaturalShow ->+ Encoding.encodeUtf8ByteArray "Natural/show"++ NaturalSubtract ->+ Encoding.encodeUtf8ByteArray "Natural/subtract"++ IntegerToDouble ->+ Encoding.encodeUtf8ByteArray "Integer/toDouble"++ IntegerClamp ->+ Encoding.encodeUtf8ByteArray "Integer/clamp"++ IntegerNegate ->+ Encoding.encodeUtf8ByteArray "Integer/negate"++ IntegerShow ->+ Encoding.encodeUtf8ByteArray "Integer/show"++ DoubleShow ->+ Encoding.encodeUtf8ByteArray "Double/show"++ ListBuild ->+ Encoding.encodeUtf8ByteArray "List/build"++ ListFold ->+ Encoding.encodeUtf8ByteArray "List/fold"++ ListLength ->+ Encoding.encodeUtf8ByteArray "List/length"++ ListHead ->+ Encoding.encodeUtf8ByteArray "List/head"++ ListLast ->+ Encoding.encodeUtf8ByteArray "List/last"++ ListIndexed ->+ Encoding.encodeUtf8ByteArray "List/indexed"++ ListReverse ->+ Encoding.encodeUtf8ByteArray "List/reverse"++ Bool ->+ Encoding.encodeUtf8ByteArray "Bool"++ Bytes ->+ Encoding.encodeUtf8ByteArray "Bytes"++ Optional ->+ Encoding.encodeUtf8ByteArray "Optional"++ None ->+ Encoding.encodeUtf8ByteArray "None"++ Natural ->+ Encoding.encodeUtf8ByteArray "Natural"++ Integer ->+ Encoding.encodeUtf8ByteArray "Integer"++ Double ->+ Encoding.encodeUtf8ByteArray "Double"++ Text ->+ Encoding.encodeUtf8ByteArray "Text"++ TextReplace ->+ Encoding.encodeUtf8ByteArray "Text/replace"++ TextShow ->+ Encoding.encodeUtf8ByteArray "Text/show"++ Date ->+ Encoding.encodeUtf8ByteArray "Date"++ DateShow ->+ Encoding.encodeUtf8ByteArray "Date/show"++ Time ->+ Encoding.encodeUtf8ByteArray "Time"++ TimeShow ->+ Encoding.encodeUtf8ByteArray "Time/show"++ TimeZone ->+ Encoding.encodeUtf8ByteArray "TimeZone"++ TimeZoneShow ->+ Encoding.encodeUtf8ByteArray "TimeZone/show"++ List ->+ Encoding.encodeUtf8ByteArray "List"++ Const Type ->+ Encoding.encodeUtf8ByteArray "Type"++ Const Kind ->+ Encoding.encodeUtf8ByteArray "Kind"++ Const Sort ->+ Encoding.encodeUtf8ByteArray "Sort"++ a@App{} ->+ encodeListN+ (2 + length arguments)+ ( Encoding.encodeInt 0+ : go function+ : map go arguments+ )+ where+ (function, arguments) = unApply a++ Lam _ (FunctionBinding { functionBindingVariable = "_", functionBindingAnnotation = _A }) b ->+ encodeList3+ (Encoding.encodeInt 1)+ (go _A)+ (go b)++ Lam _ (FunctionBinding { functionBindingVariable = x, functionBindingAnnotation = _A }) b ->+ encodeList4+ (Encoding.encodeInt 1)+ (Encoding.encodeString x)+ (go _A)+ (go b)++ Pi _ "_" _A _B ->+ encodeList3+ (Encoding.encodeInt 2)+ (go _A)+ (go _B)++ Pi _ x _A _B ->+ encodeList4+ (Encoding.encodeInt 2)+ (Encoding.encodeString x)+ (go _A)+ (go _B)++ BoolOr l r ->+ encodeOperator 0 l r++ BoolAnd l r ->+ encodeOperator 1 l r++ BoolEQ l r ->+ encodeOperator 2 l r++ BoolNE l r ->+ encodeOperator 3 l r++ BytesLit b ->+ encodeList2+ (Encoding.encodeInt 33)+ (Encoding.encodeBytes b)++ NaturalPlus l r ->+ encodeOperator 4 l r++ NaturalTimes l r ->+ encodeOperator 5 l r++ TextAppend l r ->+ encodeOperator 6 l r++ ListAppend l r ->+ encodeOperator 7 l r++ Combine _ _ l r ->+ encodeOperator 8 l r++ Prefer _ _ l r ->+ encodeOperator 9 l r++ CombineTypes _ l r ->+ encodeOperator 10 l r++ ImportAlt l r ->+ encodeOperator 11 l r++ Equivalent _ l r ->+ encodeOperator 12 l r++ RecordCompletion l r ->+ encodeOperator 13 l r++ ListLit _T₀ xs+ | null xs ->+ encodeList2 (Encoding.encodeInt label) _T₁+ | otherwise ->+ encodeListN+ (2 + length xs)+ ( Encoding.encodeInt 4+ : Encoding.encodeNull+ : map go (Data.Foldable.toList xs)+ )+ where+ (label, _T₁) = case _T₀ of+ Nothing -> (4 , Encoding.encodeNull)+ Just (App List t) -> (4 , go t )+ Just t -> (28, go t )++ Some t ->+ encodeList3+ (Encoding.encodeInt 5)+ Encoding.encodeNull+ (go t)++ Merge t u Nothing ->+ encodeList3+ (Encoding.encodeInt 6)+ (go t)+ (go u)++ Merge t u (Just _T) ->+ encodeList4+ (Encoding.encodeInt 6)+ (go t)+ (go u)+ (go _T)++ Record xTs ->+ encodeList2+ (Encoding.encodeInt 7)+ (encodeMapWith (go . recordFieldValue) xTs)++ RecordLit xts ->+ encodeList2+ (Encoding.encodeInt 8)+ (encodeMapWith (go. recordFieldValue) xts)++ Field t (Syntax.fieldSelectionLabel -> x) ->+ encodeList3+ (Encoding.encodeInt 9)+ (go t)+ (Encoding.encodeString x)++ Project t (Left xs) ->+ encodeListN+ (2 + length xs)+ ( Encoding.encodeInt 10+ : go t+ : map Encoding.encodeString xs+ )++ Project t (Right _T) ->+ encodeList3+ (Encoding.encodeInt 10)+ (go t)+ (encodeList1 (go _T))++ Union xTs ->+ encodeList2+ (Encoding.encodeInt 11)+ (encodeMapWith encodeValue xTs)+ where+ encodeValue Nothing = Encoding.encodeNull+ encodeValue (Just _T) = go _T++ BoolLit b ->+ Encoding.encodeBool b++ BoolIf t l r ->+ encodeList4+ (Encoding.encodeInt 14)+ (go t)+ (go l)+ (go r)++ NaturalLit n ->+ encodeList2+ (Encoding.encodeInt 15)+ (Encoding.encodeInteger (fromIntegral n))++ IntegerLit n ->+ encodeList2+ (Encoding.encodeInt 16)+ (Encoding.encodeInteger (fromIntegral n))++ DoubleLit (DhallDouble n64)+ | useHalf -> Encoding.encodeFloat16 n32+ | useFloat -> Encoding.encodeFloat n32+ | otherwise -> Encoding.encodeDouble n64+ where+ n32 = double2Float n64++ n16 = toHalf n32++ useFloat = n64 == float2Double n32++ useHalf = n64 == (float2Double $ fromHalf n16)++ -- Fast path for the common case of an uninterpolated string+ TextLit (Chunks [] z) ->+ encodeList2+ (Encoding.encodeInt 18)+ (Encoding.encodeString z)++ TextLit (Chunks xys z) ->+ encodeListN+ (2 + 2 * length xys)+ ( Encoding.encodeInt 18+ : concatMap encodePair xys ++ [ Encoding.encodeString z ]+ )+ where+ encodePair (x, y) = [ Encoding.encodeString x, go y ]++ Assert t ->+ encodeList2+ (Encoding.encodeInt 19)+ (go t)++ Embed x ->+ encodeEmbed x++ Let a₀ b₀ ->+ encodeListN+ (2 + 3 * length as)+ ( Encoding.encodeInt 25+ : concatMap encodeBinding (toList as) ++ [ go b₁ ]+ )+ where+ MultiLet as b₁ = Syntax.multiLet a₀ b₀++ encodeBinding (Binding _ x _ mA₀ _ a) =+ [ Encoding.encodeString x+ , mA₁+ , go a+ ]+ where+ mA₁ = case mA₀ of+ Nothing -> Encoding.encodeNull+ Just (_, _A) -> go _A++ Annot t _T ->+ encodeList3+ (Encoding.encodeInt 26)+ (go t)+ (go _T)++ ToMap t Nothing ->+ encodeList2+ (Encoding.encodeInt 27)+ (go t)++ ToMap t (Just _T) ->+ encodeList3+ (Encoding.encodeInt 27)+ (go t)+ (go _T)++ With l ks r ->+ encodeList4+ (Encoding.encodeInt 29)+ (go l)+ (encodeList (fmap encodeWithComponent ks))+ (go r)+ where+ encodeWithComponent WithQuestion = Encoding.encodeInt 0+ encodeWithComponent (WithLabel k ) = Encoding.encodeString k++ DateLiteral day ->+ encodeList4+ (Encoding.encodeInt 30)+ (Encoding.encodeInt (fromInteger _YYYY))+ (Encoding.encodeInt _MM)+ (Encoding.encodeInt _DD)+ where+ (_YYYY, _MM, _DD) = Time.toGregorian day++ TimeLiteral (Time.TimeOfDay hh mm ss) precision ->+ encodeList4+ (Encoding.encodeInt 31)+ (Encoding.encodeInt hh)+ (Encoding.encodeInt mm)+ ( Encoding.encodeTag 4+ <> encodeList2+ (Encoding.encodeInt exponent)+ encodedMantissa+ )+ where+ exponent = negate (fromIntegral precision)++ mantissa :: Integer+ mantissa = truncate (ss * 10 ^ precision)++ encodedMantissa+ | fromIntegral (minBound :: Int) <= mantissa+ && mantissa <= fromIntegral (maxBound :: Int) =+ Encoding.encodeInt (fromInteger mantissa)+ | otherwise =+ Encoding.encodeInteger mantissa++ TimeZoneLiteral (Time.TimeZone minutes _ _) ->+ encodeList4+ (Encoding.encodeInt 32)+ (Encoding.encodeBool sign)+ (Encoding.encodeInt _HH)+ (Encoding.encodeInt _MM)+ where+ sign = 0 <= minutes++ (_HH, _MM) = abs minutes `divMod` 60++ ShowConstructor t ->+ encodeList2+ (Encoding.encodeInt 34)+ (go t)++ Note _ b ->+ go b++ encodeOperator n l r =+ encodeList4+ (Encoding.encodeInt 3)+ (Encoding.encodeInt n)+ (go l)+ (go r)++ encodeMapWith encodeValue m =+ Encoding.encodeMapLen (fromIntegral (Dhall.Map.size m))+ <> foldMap encodeKeyValue (Dhall.Map.toList (Dhall.Map.sort m))+ where+ encodeKeyValue (k, v) = Encoding.encodeString k <> encodeValue v++encodeList1 :: Encoding -> Encoding+encodeList1 a = Encoding.encodeListLen 1 <> a+{-# INLINE encodeList1 #-}++encodeList2 :: Encoding -> Encoding -> Encoding+encodeList2 a b = Encoding.encodeListLen 2 <> a <> b+{-# INLINE encodeList2 #-}++encodeList3 :: Encoding -> Encoding -> Encoding -> Encoding+encodeList3 a b c = Encoding.encodeListLen 3 <> a <> b <> c+{-# INLINE encodeList3 #-}++encodeList4 :: Encoding -> Encoding -> Encoding -> Encoding -> Encoding+encodeList4 a b c d = Encoding.encodeListLen 4 <> a <> b <> c <> d+{-# INLINE encodeList4 #-}++encodeListN :: Foldable f => Int -> f Encoding -> Encoding+encodeListN len xs =+ Encoding.encodeListLen (fromIntegral len) <> Foldable.fold xs+{-# INLINE encodeListN #-}++encodeList :: Foldable f => f Encoding -> Encoding+encodeList xs = encodeListN (length xs) xs+{-# INLINE encodeList #-}++decodeImport :: Int -> Decoder s Import+decodeImport len = do+ let die message = fail ("Dhall.Binary.decodeImport: " <> message)++ tokenType₀ <- Decoding.peekTokenType++ hash <- case tokenType₀ of+ TypeNull -> do+ Decoding.decodeNull++ return Nothing++ TypeBytes -> do+ bytes <- Decoding.decodeBytes++ let (prefix, suffix) = Data.ByteString.splitAt 2 bytes++ case prefix of+ "\x12\x20" -> return ()+ _ -> die ("Unrecognized multihash prefix: " <> show prefix)+ case Dhall.Crypto.sha256DigestFromByteString suffix of+ Nothing -> die ("Invalid sha256 digest: " <> show bytes)+ Just digest -> return (Just digest)++ _ ->+ die ("Unexpected hash token: " <> show tokenType₀)++ m <- Decoding.decodeWord++ importMode <- case m of+ 0 -> return Code+ 1 -> return RawText+ 2 -> return Location+ 3 -> return RawBytes+ _ -> die ("Unexpected code for import mode: " <> show m)++ let remote scheme = do+ tokenType₁ <- Decoding.peekTokenType++ headers <- case tokenType₁ of+ TypeNull -> do+ Decoding.decodeNull+ return Nothing++ _ -> do+ headers <- decodeExpressionInternal decodeImport++ return (Just headers)++ authority <- Decoding.decodeString++ paths <- replicateDecoder (len - 8) Decoding.decodeString++ file <- Decoding.decodeString++ tokenType₂ <- Decoding.peekTokenType++ query <- case tokenType₂ of+ TypeNull -> do+ Decoding.decodeNull+ return Nothing+ _ ->+ fmap Just Decoding.decodeString++ let components = reverse paths+ let directory = Directory {..}+ let path = File {..}++ return (Remote (URL {..}))++ let local prefix = do+ paths <- replicateDecoder (len - 5) Decoding.decodeString++ file <- Decoding.decodeString++ let components = reverse paths+ let directory = Directory {..}++ return (Local prefix (File {..}))++ let missing = return Missing++ let env = do+ x <- Decoding.decodeString++ return (Env x)++ n <- Decoding.decodeWord++ importType <- case n of+ 0 -> remote HTTP+ 1 -> remote HTTPS+ 2 -> local Absolute+ 3 -> local Here+ 4 -> local Parent+ 5 -> local Home+ 6 -> env+ 7 -> missing+ _ -> fail ("Unrecognized import type code: " <> show n)++ let importHashed = ImportHashed {..}++ return (Import {..})++encodeImport :: Import -> Encoding+encodeImport import_ =+ case importType of+ Remote (URL { scheme = scheme₀, .. }) ->+ encodeList+ ( prefix+ ++ [ Encoding.encodeInt scheme₁+ , using+ , Encoding.encodeString authority+ ]+ ++ map Encoding.encodeString (reverse components)+ ++ [ Encoding.encodeString file ]+ ++ [ case query of+ Nothing -> Encoding.encodeNull+ Just q -> Encoding.encodeString q+ ]+ )+ where+ using = case headers of+ Nothing ->+ Encoding.encodeNull+ Just h ->+ encodeExpressionInternal encodeImport (Syntax.denote h)++ scheme₁ = case scheme₀ of+ HTTP -> 0+ HTTPS -> 1++ File{..} = path++ Directory {..} = directory++ Local prefix₀ path ->+ encodeList+ ( prefix+ ++ [ Encoding.encodeInt prefix₁ ]+ ++ map Encoding.encodeString components₁+ ++ [ Encoding.encodeString file ]+ )+ where+ File{..} = path++ Directory{..} = directory++ prefix₁ = case prefix₀ of+ Absolute -> 2+ Here -> 3+ Parent -> 4+ Home -> 5++ components₁ = reverse components++ Env x ->+ encodeList+ (prefix ++ [ Encoding.encodeInt 6, Encoding.encodeString x ])++ Missing ->+ encodeList (prefix ++ [ Encoding.encodeInt 7 ])+ where+ prefix = [ Encoding.encodeInt 24, h, m ]+ where+ h = case hash of+ Nothing ->+ Encoding.encodeNull++ Just digest ->+ Encoding.encodeBytes ("\x12\x20" <> Dhall.Crypto.unSHA256Digest digest)++ m = Encoding.encodeInt (case importMode of+ Code -> 0+ RawText -> 1+ Location -> 2+ RawBytes -> 3 )++ Import{..} = import_++ ImportHashed{..} = importHashed++decodeVoid :: Int -> Decoder s Void+decodeVoid _ = fail "Dhall.Binary.decodeVoid: Cannot decode an uninhabited type"++encodeVoid :: Void -> Encoding+encodeVoid = absurd++instance Serialise (Expr Void Void) where+ encode = encodeExpressionInternal encodeVoid++ decode = decodeExpressionInternal decodeVoid++instance Serialise (Expr Void Import) where+ encode = encodeExpressionInternal encodeImport++ decode = decodeExpressionInternal decodeImport++-- | Encode a Dhall expression as a CBOR-encoded `ByteString`+encodeExpression :: Serialise (Expr Void a) => Expr Void a -> ByteString+encodeExpression = Serialise.serialise++-- | Decode a Dhall expression from a CBOR `Codec.CBOR.Term.Term`+decodeExpression+ :: Serialise (Expr s a) => ByteString -> Either DecodingFailure (Expr s a)+decodeExpression bytes =+ case decodeWithoutVersion <|> decodeWithVersion of+ Just expression -> Right expression+ Nothing -> Left (CBORIsNotDhall bytes)+ where+ adapt (Right ("", x)) = Just x+ adapt _ = Nothing++ decode' = decodeWith55799Tag decode++ -- This is the behavior specified by the standard+ decodeWithoutVersion = adapt (Read.deserialiseFromBytes decode' bytes)++ -- tag to ease the migration+ decodeWithVersion = adapt (Read.deserialiseFromBytes decodeWithTag bytes)+ where+ decodeWithTag = do+ 2 <- Decoding.decodeListLen++ version <- Decoding.decodeString+++ -- "_" has never been a valid version string, and this ensures that+ -- we don't interpret `[ "_", 0 ]` as the expression `_` (encoded as+ -- `0`) tagged with a version string of `"_"`+ if (version == "_")+ then fail "Dhall.Binary.decodeExpression: \"_\" is not a valid version string"+ else return ()++ decode'++decodeWith55799Tag :: Decoder s a -> Decoder s a+decodeWith55799Tag decoder = do+ tokenType <- Decoding.peekTokenType++ case tokenType of+ TypeTag -> do+ w <- Decoding.decodeTag++ if w /= 55799+ then fail ("Dhall.Binary.decodeWith55799Tag: Unexpected tag: " <> show w)+ else return ()++ decoder+ _ ->+ decoder++{-| This indicates that a given CBOR-encoded `ByteString` did not correspond to+ a valid Dhall expression+-}+newtype DecodingFailure = CBORIsNotDhall ByteString+ deriving (Eq)++instance Exception DecodingFailure++_ERROR :: String+_ERROR = "\ESC[1;31mError\ESC[0m"++instance Show DecodingFailure where+ show (CBORIsNotDhall bytes) =+ _ERROR <> ": Cannot decode CBOR to Dhall\n"+ <> "\n"+ <> "The following bytes do not encode a valid Dhall expression\n"+ <> "\n"+ <> "↳ 0x" <> concatMap toHex (Data.ByteString.Lazy.unpack bytes) <> "\n"+ where+ toHex = Printf.printf "%02x "++-- | This specialized version of 'Control.Monad.replicateM' reduces+-- decoding timings by roughly 10%.+replicateDecoder :: Int -> Decoder s a -> Decoder s [a]+replicateDecoder n0 decoder = go n0+ where+ go n+ | n <= 0 = pure []+ | otherwise = do+ x <- decoder+ xs <- go (n - 1)+ pure (x:xs)
@@ -1,10 +0,0 @@-module Dhall.Binary where--import Codec.CBOR.Term (Term)--import {-# SOURCE #-} Dhall.Core--class ToTerm a where- encode :: a -> Term--instance ToTerm a => ToTerm (Expr s a)
@@ -13,10 +13,10 @@ ) where import Data.Text (Text)-import Prelude hiding (lookup)+import Prelude hiding (lookup) -{-| A @(Context a)@ associates `Text` labels with values of type @a@. Each- `Text` label can correspond to multiple values of type @a@+{-| A @(Context a)@ associates `Data.Text.Text` labels with values of type @a@.+ Each `Data.Text.Text` label can correspond to multiple values of type @a@ The `Context` is used for type-checking when @(a = Expr X)@ @@ -57,7 +57,7 @@ > lookup k n (insert k v c) = lookup k (n - 1) c > lookup k n (insert j v c) = lookup k n c -- k /= j -}-lookup :: Text -> Integer -> Context a -> Maybe a+lookup :: Text -> Int -> Context a -> Maybe a lookup _ _ (Context [] ) = Nothing lookup x n (Context ((k, v):kvs)) =
@@ -1,2147 +1,156 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE UnicodeSyntax #-}-{-# OPTIONS_GHC -Wall #-}--{-| This module contains the core calculus for the Dhall language.-- Dhall is essentially a fork of the @morte@ compiler but with more built-in- functionality, better error messages, and Haskell integration--}--module Dhall.Core (- -- * Syntax- Const(..)- , Directory(..)- , File(..)- , FilePrefix(..)- , Import(..)- , ImportHashed(..)- , ImportMode(..)- , ImportType(..)- , URL(..)- , Scheme(..)- , Var(..)- , Binding(..)- , Chunks(..)- , Expr(..)-- -- * Normalization- , Dhall.Core.alphaNormalize- , normalize- , normalizeWith- , normalizeWithM- , Normalizer- , NormalizerM- , ReifiedNormalizer (..)- , judgmentallyEqual- , subst- , shift- , isNormalized- , isNormalizedWith- , denote- , freeIn-- -- * Pretty-printing- , pretty-- -- * Optics- , subExpressions- , chunkExprs-- -- * Miscellaneous- , internalError- , reservedIdentifiers- , escapeText- , pathCharacter- , throws- ) where--#if MIN_VERSION_base(4,8,0)-#else-import Control.Applicative (Applicative(..), (<$>))-#endif-import Control.Applicative (empty)-import Control.Exception (Exception)-import Control.Monad.IO.Class (MonadIO(..))-import Crypto.Hash (SHA256)-import Data.Bifunctor (Bifunctor(..))-import Data.Data (Data)-import Data.Foldable-import Data.Functor.Identity (Identity(..))-import Data.HashSet (HashSet)-import Data.List.NonEmpty (NonEmpty(..))-import Data.String (IsString(..))-import Data.Semigroup (Semigroup(..))-import Data.Sequence (Seq, ViewL(..), ViewR(..))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty)-import Data.Traversable-import Dhall.Map (Map)-import Dhall.Set (Set)-import Dhall.Src (Src)-import {-# SOURCE #-} Dhall.Pretty.Internal-import GHC.Generics (Generic)-import Numeric.Natural (Natural)-import Prelude hiding (succ)--import qualified Control.Exception-import qualified Control.Monad-import qualified Crypto.Hash-import qualified Data.Char-import {-# SOURCE #-} qualified Dhall.Eval-import qualified Data.HashSet-import qualified Data.Sequence-import qualified Data.Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Dhall.Map-import qualified Dhall.Set-import qualified Network.URI.Encode as URI.Encode-import qualified Text.Printf---{-| Constants for a pure type system-- The axioms are:--> ⊦ Type : Kind-> ⊦ Kind : Sort-- ... and the valid rule pairs are:--> ⊦ Type ↝ Type : Type -- Functions from terms to terms (ordinary functions)-> ⊦ Kind ↝ Type : Type -- Functions from types to terms (type-polymorphic functions)-> ⊦ Sort ↝ Type : Type -- Functions from kinds to terms-> ⊦ Kind ↝ Kind : Kind -- Functions from types to types (type-level functions)-> ⊦ Sort ↝ Kind : Sort -- Functions from kinds to types (kind-polymorphic functions)-> ⊦ Sort ↝ Sort : Sort -- Functions from kinds to kinds (kind-level functions)-- Note that Dhall does not support functions from terms to types and therefore- Dhall is not a dependently typed language--}-data Const = Type | Kind | Sort- deriving (Show, Eq, Ord, Data, Bounded, Enum, Generic)--instance Pretty Const where- pretty = Pretty.unAnnotate . prettyConst--{-| Internal representation of a directory that stores the path components in- reverse order-- In other words, the directory @\/foo\/bar\/baz@ is encoded as- @Directory { components = [ "baz", "bar", "foo" ] }@--}-newtype Directory = Directory { components :: [Text] }- deriving (Eq, Generic, Ord, Show)--instance Semigroup Directory where- Directory components₀ <> Directory components₁ =- Directory (components₁ <> components₀)--instance Pretty Directory where- pretty (Directory {..}) = foldMap prettyPathComponent (reverse components)--{-| A `File` is a `directory` followed by one additional path component- representing the `file` name--}-data File = File- { directory :: Directory- , file :: Text- } deriving (Eq, Generic, Ord, Show)--instance Pretty File where- pretty (File {..}) =- Pretty.pretty directory- <> prettyPathComponent file--instance Semigroup File where- File directory₀ _ <> File directory₁ file =- File (directory₀ <> directory₁) file---- | The beginning of a file path which anchors subsequent path components-data FilePrefix- = Absolute- -- ^ Absolute path- | Here- -- ^ Path relative to @.@- | Parent- -- ^ Path relative to @..@- | Home- -- ^ Path relative to @~@- deriving (Eq, Generic, Ord, Show)--instance Pretty FilePrefix where- pretty Absolute = ""- pretty Here = "."- pretty Parent = ".."- pretty Home = "~"--data Scheme = HTTP | HTTPS deriving (Eq, Generic, Ord, Show)--data URL = URL- { scheme :: Scheme- , authority :: Text- , path :: File- , query :: Maybe Text- , headers :: Maybe (Expr Src Import)- } deriving (Eq, Generic, Ord, Show)--instance Pretty URL where- pretty (URL {..}) =- schemeDoc- <> "://"- <> Pretty.pretty authority- <> pathDoc- <> queryDoc- <> foldMap prettyHeaders headers- where- prettyHeaders h = " using " <> Pretty.pretty h-- File {..} = path-- Directory {..} = directory-- pathDoc =- foldMap prettyURIComponent (reverse components)- <> prettyURIComponent file-- schemeDoc = case scheme of- HTTP -> "http"- HTTPS -> "https"-- queryDoc = case query of- Nothing -> ""- Just q -> "?" <> Pretty.pretty q---- | The type of import (i.e. local vs. remote vs. environment)-data ImportType- = Local FilePrefix File- -- ^ Local path- | Remote URL- -- ^ URL of remote resource and optional headers stored in an import- | Env Text- -- ^ Environment variable- | Missing- deriving (Eq, Generic, Ord, Show)--parent :: File-parent = File { directory = Directory { components = [ ".." ] }, file = "" }--instance Semigroup ImportType where- Local prefix file₀ <> Local Here file₁ = Local prefix (file₀ <> file₁)-- Remote (URL { path = path₀, ..}) <> Local Here path₁ =- Remote (URL { path = path₀ <> path₁, ..})-- Local prefix file₀ <> Local Parent file₁ =- Local prefix (file₀ <> parent <> file₁)-- Remote (URL { path = path₀, .. }) <> Local Parent path₁ =- Remote (URL { path = path₀ <> parent <> path₁, .. })-- import₀ <> Remote (URL { headers = headers₀, .. }) =- Remote (URL { headers = headers₁, .. })- where- importHashed₀ = Import (ImportHashed Nothing import₀) Code-- headers₁ = fmap (fmap (importHashed₀ <>)) headers₀-- _ <> import₁ =- import₁--instance Pretty ImportType where- pretty (Local prefix file) =- Pretty.pretty prefix <> Pretty.pretty file-- pretty (Remote url) = Pretty.pretty url-- pretty (Env env) = "env:" <> Pretty.pretty env-- pretty Missing = "missing"---- | How to interpret the import's contents (i.e. as Dhall code or raw text)-data ImportMode = Code | RawText deriving (Eq, Generic, Ord, Show)---- | A `ImportType` extended with an optional hash for semantic integrity checks-data ImportHashed = ImportHashed- { hash :: Maybe (Crypto.Hash.Digest SHA256)- , importType :: ImportType- } deriving (Eq, Generic, Ord, Show)--instance Semigroup ImportHashed where- ImportHashed _ importType₀ <> ImportHashed hash importType₁ =- ImportHashed hash (importType₀ <> importType₁)--instance Pretty ImportHashed where- pretty (ImportHashed Nothing p) =- Pretty.pretty p- pretty (ImportHashed (Just h) p) =- Pretty.pretty p <> " sha256:" <> Pretty.pretty (show h)---- | Reference to an external resource-data Import = Import- { importHashed :: ImportHashed- , importMode :: ImportMode- } deriving (Eq, Generic, Ord, Show)--instance Semigroup Import where- Import importHashed₀ _ <> Import importHashed₁ code =- Import (importHashed₀ <> importHashed₁) code--instance Pretty Import where- pretty (Import {..}) = Pretty.pretty importHashed <> Pretty.pretty suffix- where- suffix :: Text- suffix = case importMode of- RawText -> " as Text"- Code -> ""--{-| Label for a bound variable-- The `Text` field is the variable's name (i.e. \"@x@\").-- The `Int` field disambiguates variables with the same name if there are- multiple bound variables of the same name in scope. Zero refers to the- nearest bound variable and the index increases by one for each bound- variable of the same name going outward. The following diagram may help:--> ┌──refers to──┐-> │ │-> v │-> λ(x : Type) → λ(y : Type) → λ(x : Type) → x@0->-> ┌─────────────────refers to─────────────────┐-> │ │-> v │-> λ(x : Type) → λ(y : Type) → λ(x : Type) → x@1-- This `Int` behaves like a De Bruijn index in the special case where all- variables have the same name.-- You can optionally omit the index if it is @0@:--> ┌─refers to─┐-> │ │-> v │-> λ(x : Type) → λ(y : Type) → λ(x : Type) → x-- Zero indices are omitted when pretty-printing `Var`s and non-zero indices- appear as a numeric suffix.--}-data Var = V Text !Integer- deriving (Data, Generic, Eq, Ord, Show)--instance IsString Var where- fromString str = V (fromString str) 0--instance Pretty Var where- pretty = Pretty.unAnnotate . prettyVar---- | Syntax tree for expressions-data Expr s a- -- | > Const c ~ c- = Const Const- -- | > Var (V x 0) ~ x- -- > Var (V x n) ~ x@n- | Var Var- -- | > Lam x A b ~ λ(x : A) -> b- | Lam Text (Expr s a) (Expr s a)- -- | > Pi "_" A B ~ A -> B- -- > Pi x A B ~ ∀(x : A) -> B- | Pi Text (Expr s a) (Expr s a)- -- | > App f a ~ f a- | App (Expr s a) (Expr s a)- -- | > Let [Binding x Nothing r] e ~ let x = r in e- -- > Let [Binding x (Just t) r] e ~ let x : t = r in e- | Let (NonEmpty (Binding s a)) (Expr s a)- -- | > Annot x t ~ x : t- | Annot (Expr s a) (Expr s a)- -- | > Bool ~ Bool- | Bool- -- | > BoolLit b ~ b- | BoolLit Bool- -- | > BoolAnd x y ~ x && y- | BoolAnd (Expr s a) (Expr s a)- -- | > BoolOr x y ~ x || y- | BoolOr (Expr s a) (Expr s a)- -- | > BoolEQ x y ~ x == y- | BoolEQ (Expr s a) (Expr s a)- -- | > BoolNE x y ~ x != y- | BoolNE (Expr s a) (Expr s a)- -- | > BoolIf x y z ~ if x then y else z- | BoolIf (Expr s a) (Expr s a) (Expr s a)- -- | > Natural ~ Natural- | Natural- -- | > NaturalLit n ~ n- | NaturalLit Natural- -- | > NaturalFold ~ Natural/fold- | NaturalFold- -- | > NaturalBuild ~ Natural/build- | NaturalBuild- -- | > NaturalIsZero ~ Natural/isZero- | NaturalIsZero- -- | > NaturalEven ~ Natural/even- | NaturalEven- -- | > NaturalOdd ~ Natural/odd- | NaturalOdd- -- | > NaturalToInteger ~ Natural/toInteger- | NaturalToInteger- -- | > NaturalShow ~ Natural/show- | NaturalShow- -- | > NaturalPlus x y ~ x + y- | NaturalPlus (Expr s a) (Expr s a)- -- | > NaturalTimes x y ~ x * y- | NaturalTimes (Expr s a) (Expr s a)- -- | > Integer ~ Integer- | Integer- -- | > IntegerLit n ~ ±n- | IntegerLit Integer- -- | > IntegerShow ~ Integer/show- | IntegerShow- -- | > IntegerToDouble ~ Integer/toDouble- | IntegerToDouble- -- | > Double ~ Double- | Double- -- | > DoubleLit n ~ n- | DoubleLit Double- -- | > DoubleShow ~ Double/show- | DoubleShow- -- | > Text ~ Text- | Text- -- | > TextLit (Chunks [(t1, e1), (t2, e2)] t3) ~ "t1${e1}t2${e2}t3"- | TextLit (Chunks s a)- -- | > TextAppend x y ~ x ++ y- | TextAppend (Expr s a) (Expr s a)- -- | > TextShow ~ Text/show- | TextShow- -- | > List ~ List- | List- -- | > ListLit (Just t ) [x, y, z] ~ [x, y, z] : List t- -- > ListLit Nothing [x, y, z] ~ [x, y, z]- | ListLit (Maybe (Expr s a)) (Seq (Expr s a))- -- | > ListAppend x y ~ x # y- | ListAppend (Expr s a) (Expr s a)- -- | > ListBuild ~ List/build- | ListBuild- -- | > ListFold ~ List/fold- | ListFold- -- | > ListLength ~ List/length- | ListLength- -- | > ListHead ~ List/head- | ListHead- -- | > ListLast ~ List/last- | ListLast- -- | > ListIndexed ~ List/indexed- | ListIndexed- -- | > ListReverse ~ List/reverse- | ListReverse- -- | > Optional ~ Optional- | Optional- -- | > OptionalLit t (Just e) ~ [e] : Optional t- -- > OptionalLit t Nothing ~ [] : Optional t- | OptionalLit (Expr s a) (Maybe (Expr s a))- -- | > Some e ~ Some e- | Some (Expr s a)- -- | > None ~ None- | None- -- | > OptionalFold ~ Optional/fold- | OptionalFold- -- | > OptionalBuild ~ Optional/build- | OptionalBuild- -- | > Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 }- | Record (Map Text (Expr s a))- -- | > RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 }- | RecordLit (Map Text (Expr s a))- -- | > Union [(k1, Just t1), (k2, Nothing)] ~ < k1 : t1 | k2 >- | Union (Map Text (Maybe (Expr s a)))- -- | > UnionLit k v [(k1, Just t1), (k2, Nothing)] ~ < k = v | k1 : t1 | k2 >- | UnionLit Text (Expr s a) (Map Text (Maybe (Expr s a)))- -- | > Combine x y ~ x ∧ y- | Combine (Expr s a) (Expr s a)- -- | > CombineTypes x y ~ x ⩓ y- | CombineTypes (Expr s a) (Expr s a)- -- | > Prefer x y ~ x ⫽ y- | Prefer (Expr s a) (Expr s a)- -- | > Merge x y (Just t ) ~ merge x y : t- -- > Merge x y Nothing ~ merge x y- | Merge (Expr s a) (Expr s a) (Maybe (Expr s a))- -- | > Field e x ~ e.x- | Field (Expr s a) Text- -- | > Project e (Left xs) ~ e.{ xs }- -- | > Project e (Right t) ~ e.(t)- | Project (Expr s a) (Either (Set Text) (Expr s a))- -- | > Note s x ~ e- | Note s (Expr s a)- -- | > ImportAlt ~ e1 ? e2- | ImportAlt (Expr s a) (Expr s a)- -- | > Embed import ~ import- | Embed a- deriving (Eq, Ord, Foldable, Generic, Traversable, Show, Data)---- This instance is hand-written due to the fact that deriving--- it does not give us an INLINABLE pragma. We annotate this fmap--- implementation with this pragma below to allow GHC to, possibly,--- inline the implementation for performance improvements.-instance Functor (Expr s) where- fmap _ (Const c) = Const c- fmap _ (Var v) = Var v- fmap f (Lam v e1 e2) = Lam v (fmap f e1) (fmap f e2)- fmap f (Pi v e1 e2) = Pi v (fmap f e1) (fmap f e2)- fmap f (App e1 e2) = App (fmap f e1) (fmap f e2)- fmap f (Let as b) = Let (fmap (fmap f) as) (fmap f b)- fmap f (Annot e1 e2) = Annot (fmap f e1) (fmap f e2)- fmap _ Bool = Bool- fmap _ (BoolLit b) = BoolLit b- fmap f (BoolAnd e1 e2) = BoolAnd (fmap f e1) (fmap f e2)- fmap f (BoolOr e1 e2) = BoolOr (fmap f e1) (fmap f e2)- fmap f (BoolEQ e1 e2) = BoolEQ (fmap f e1) (fmap f e2)- fmap f (BoolNE e1 e2) = BoolNE (fmap f e1) (fmap f e2)- fmap f (BoolIf e1 e2 e3) = BoolIf (fmap f e1) (fmap f e2) (fmap f e3)- fmap _ Natural = Natural- fmap _ (NaturalLit n) = NaturalLit n- fmap _ NaturalFold = NaturalFold- fmap _ NaturalBuild = NaturalBuild- fmap _ NaturalIsZero = NaturalIsZero- fmap _ NaturalEven = NaturalEven- fmap _ NaturalOdd = NaturalOdd- fmap _ NaturalToInteger = NaturalToInteger- fmap _ NaturalShow = NaturalShow- fmap f (NaturalPlus e1 e2) = NaturalPlus (fmap f e1) (fmap f e2)- fmap f (NaturalTimes e1 e2) = NaturalTimes (fmap f e1) (fmap f e2)- fmap _ Integer = Integer- fmap _ (IntegerLit i) = IntegerLit i- fmap _ IntegerShow = IntegerShow- fmap _ IntegerToDouble = IntegerToDouble- fmap _ Double = Double- fmap _ (DoubleLit d) = DoubleLit d- fmap _ DoubleShow = DoubleShow- fmap _ Text = Text- fmap f (TextLit cs) = TextLit (fmap f cs)- fmap f (TextAppend e1 e2) = TextAppend (fmap f e1) (fmap f e2)- fmap _ TextShow = TextShow- fmap _ List = List- fmap f (ListLit maybeE seqE) = ListLit (fmap (fmap f) maybeE) (fmap (fmap f) seqE)- fmap f (ListAppend e1 e2) = ListAppend (fmap f e1) (fmap f e2)- fmap _ ListBuild = ListBuild- fmap _ ListFold = ListFold- fmap _ ListLength = ListLength- fmap _ ListHead = ListHead- fmap _ ListLast = ListLast- fmap _ ListIndexed = ListIndexed- fmap _ ListReverse = ListReverse- fmap _ Optional = Optional- fmap f (OptionalLit e maybeE) = OptionalLit (fmap f e) (fmap (fmap f) maybeE)- fmap f (Some e) = Some (fmap f e)- fmap _ None = None- fmap _ OptionalFold = OptionalFold- fmap _ OptionalBuild = OptionalBuild- fmap f (Record r) = Record (fmap (fmap f) r)- fmap f (RecordLit r) = RecordLit (fmap (fmap f) r)- fmap f (Union u) = Union (fmap (fmap (fmap f)) u)- fmap f (UnionLit v e u) = UnionLit v (fmap f e) (fmap (fmap (fmap f)) u)- fmap f (Combine e1 e2) = Combine (fmap f e1) (fmap f e2)- fmap f (CombineTypes e1 e2) = CombineTypes (fmap f e1) (fmap f e2)- fmap f (Prefer e1 e2) = Prefer (fmap f e1) (fmap f e2)- fmap f (Merge e1 e2 maybeE) = Merge (fmap f e1) (fmap f e2) (fmap (fmap f) maybeE)- fmap f (Field e1 v) = Field (fmap f e1) v- fmap f (Project e1 vs) = Project (fmap f e1) (fmap (fmap f) vs)- fmap f (Note s e1) = Note s (fmap f e1)- fmap f (ImportAlt e1 e2) = ImportAlt (fmap f e1) (fmap f e2)- fmap f (Embed a) = Embed (f a)- {-# INLINABLE fmap #-}--instance Applicative (Expr s) where- pure = Embed-- (<*>) = Control.Monad.ap--instance Monad (Expr s) where- return = pure-- Const a >>= _ = Const a- Var a >>= _ = Var a- Lam a b c >>= k = Lam a (b >>= k) (c >>= k)- Pi a b c >>= k = Pi a (b >>= k) (c >>= k)- App a b >>= k = App (a >>= k) (b >>= k)- Let as b >>= k = Let (fmap f as) (b >>= k)- where- f (Binding c d e) = Binding c (fmap (>>= k) d) (e >>= k)- Annot a b >>= k = Annot (a >>= k) (b >>= k)- Bool >>= _ = Bool- BoolLit a >>= _ = BoolLit a- BoolAnd a b >>= k = BoolAnd (a >>= k) (b >>= k)- BoolOr a b >>= k = BoolOr (a >>= k) (b >>= k)- BoolEQ a b >>= k = BoolEQ (a >>= k) (b >>= k)- BoolNE a b >>= k = BoolNE (a >>= k) (b >>= k)- BoolIf a b c >>= k = BoolIf (a >>= k) (b >>= k) (c >>= k)- Natural >>= _ = Natural- NaturalLit a >>= _ = NaturalLit a- NaturalFold >>= _ = NaturalFold- NaturalBuild >>= _ = NaturalBuild- NaturalIsZero >>= _ = NaturalIsZero- NaturalEven >>= _ = NaturalEven- NaturalOdd >>= _ = NaturalOdd- NaturalToInteger >>= _ = NaturalToInteger- NaturalShow >>= _ = NaturalShow- NaturalPlus a b >>= k = NaturalPlus (a >>= k) (b >>= k)- NaturalTimes a b >>= k = NaturalTimes (a >>= k) (b >>= k)- Integer >>= _ = Integer- IntegerLit a >>= _ = IntegerLit a- IntegerShow >>= _ = IntegerShow- IntegerToDouble >>= _ = IntegerToDouble- Double >>= _ = Double- DoubleLit a >>= _ = DoubleLit a- DoubleShow >>= _ = DoubleShow- Text >>= _ = Text- TextLit (Chunks a b) >>= k = TextLit (Chunks (fmap (fmap (>>= k)) a) b)- TextAppend a b >>= k = TextAppend (a >>= k) (b >>= k)- TextShow >>= _ = TextShow- List >>= _ = List- ListLit a b >>= k = ListLit (fmap (>>= k) a) (fmap (>>= k) b)- ListAppend a b >>= k = ListAppend (a >>= k) (b >>= k)- ListBuild >>= _ = ListBuild- ListFold >>= _ = ListFold- ListLength >>= _ = ListLength- ListHead >>= _ = ListHead- ListLast >>= _ = ListLast- ListIndexed >>= _ = ListIndexed- ListReverse >>= _ = ListReverse- Optional >>= _ = Optional- OptionalLit a b >>= k = OptionalLit (a >>= k) (fmap (>>= k) b)- Some a >>= k = Some (a >>= k)- None >>= _ = None- OptionalFold >>= _ = OptionalFold- OptionalBuild >>= _ = OptionalBuild- Record a >>= k = Record (fmap (>>= k) a)- RecordLit a >>= k = RecordLit (fmap (>>= k) a)- Union a >>= k = Union (fmap (fmap (>>= k)) a)- UnionLit a b c >>= k = UnionLit a (b >>= k) (fmap (fmap (>>= k)) c)- Combine a b >>= k = Combine (a >>= k) (b >>= k)- CombineTypes a b >>= k = CombineTypes (a >>= k) (b >>= k)- Prefer a b >>= k = Prefer (a >>= k) (b >>= k)- Merge a b c >>= k = Merge (a >>= k) (b >>= k) (fmap (>>= k) c)- Field a b >>= k = Field (a >>= k) b- Project a b >>= k = Project (a >>= k) (fmap (>>= k) b)- Note a b >>= k = Note a (b >>= k)- ImportAlt a b >>= k = ImportAlt (a >>= k) (b >>= k)- Embed a >>= k = k a--instance Bifunctor Expr where- first _ (Const a ) = Const a- first _ (Var a ) = Var a- first k (Lam a b c ) = Lam a (first k b) (first k c)- first k (Pi a b c ) = Pi a (first k b) (first k c)- first k (App a b ) = App (first k a) (first k b)- first k (Let as b ) = Let (fmap (first k) as) (first k b)- first k (Annot a b ) = Annot (first k a) (first k b)- first _ Bool = Bool- first _ (BoolLit a ) = BoolLit a- first k (BoolAnd a b ) = BoolAnd (first k a) (first k b)- first k (BoolOr a b ) = BoolOr (first k a) (first k b)- first k (BoolEQ a b ) = BoolEQ (first k a) (first k b)- first k (BoolNE a b ) = BoolNE (first k a) (first k b)- first k (BoolIf a b c ) = BoolIf (first k a) (first k b) (first k c)- first _ Natural = Natural- first _ (NaturalLit a ) = NaturalLit a- first _ NaturalFold = NaturalFold- first _ NaturalBuild = NaturalBuild- first _ NaturalIsZero = NaturalIsZero- first _ NaturalEven = NaturalEven- first _ NaturalOdd = NaturalOdd- first _ NaturalToInteger = NaturalToInteger- first _ NaturalShow = NaturalShow- first k (NaturalPlus a b ) = NaturalPlus (first k a) (first k b)- first k (NaturalTimes a b ) = NaturalTimes (first k a) (first k b)- first _ Integer = Integer- first _ (IntegerLit a ) = IntegerLit a- first _ IntegerShow = IntegerShow- first _ IntegerToDouble = IntegerToDouble- first _ Double = Double- first _ (DoubleLit a ) = DoubleLit a- first _ DoubleShow = DoubleShow- first _ Text = Text- first k (TextLit (Chunks a b)) = TextLit (Chunks (fmap (fmap (first k)) a) b)- first k (TextAppend a b ) = TextAppend (first k a) (first k b)- first _ TextShow = TextShow- first _ List = List- first k (ListLit a b ) = ListLit (fmap (first k) a) (fmap (first k) b)- first k (ListAppend a b ) = ListAppend (first k a) (first k b)- first _ ListBuild = ListBuild- first _ ListFold = ListFold- first _ ListLength = ListLength- first _ ListHead = ListHead- first _ ListLast = ListLast- first _ ListIndexed = ListIndexed- first _ ListReverse = ListReverse- first _ Optional = Optional- first k (OptionalLit a b ) = OptionalLit (first k a) (fmap (first k) b)- first k (Some a ) = Some (first k a)- first _ None = None- first _ OptionalFold = OptionalFold- first _ OptionalBuild = OptionalBuild- first k (Record a ) = Record (fmap (first k) a)- first k (RecordLit a ) = RecordLit (fmap (first k) a)- first k (Union a ) = Union (fmap (fmap (first k)) a)- first k (UnionLit a b c ) = UnionLit a (first k b) (fmap (fmap (first k)) c)- first k (Combine a b ) = Combine (first k a) (first k b)- first k (CombineTypes a b ) = CombineTypes (first k a) (first k b)- first k (Prefer a b ) = Prefer (first k a) (first k b)- first k (Merge a b c ) = Merge (first k a) (first k b) (fmap (first k) c)- first k (Field a b ) = Field (first k a) b- first k (Project a b ) = Project (first k a) (fmap (first k) b)- first k (Note a b ) = Note (k a) (first k b)- first k (ImportAlt a b ) = ImportAlt (first k a) (first k b)- first _ (Embed a ) = Embed a-- second = fmap--instance IsString (Expr s a) where- fromString str = Var (fromString str)--data Binding s a = Binding- { variable :: Text- , annotation :: Maybe (Expr s a)- , value :: Expr s a- } deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data)--instance Bifunctor Binding where- first k (Binding a b c) = Binding a (fmap (first k) b) (first k c)-- second = fmap---- | The body of an interpolated @Text@ literal-data Chunks s a = Chunks [(Text, Expr s a)] Text- deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data)--instance Data.Semigroup.Semigroup (Chunks s a) where- Chunks xysL zL <> Chunks [] zR =- Chunks xysL (zL <> zR)- Chunks xysL zL <> Chunks ((x, y):xysR) zR =- Chunks (xysL ++ (zL <> x, y):xysR) zR--instance Monoid (Chunks s a) where- mempty = Chunks [] mempty--#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)-#endif--instance IsString (Chunks s a) where- fromString str = Chunks [] (fromString str)--{- There is a one-to-one correspondence between the builders in this section- and the sub-parsers in "Dhall.Parser". Each builder is named after the- corresponding parser and the relationship between builders exactly matches- the relationship between parsers. This leads to the nice emergent property- of automatically getting all the parentheses and precedences right.-- This approach has one major disadvantage: you can get an infinite loop if- you add a new constructor to the syntax tree without adding a matching- case the corresponding builder.--}---- | Generates a syntactically valid Dhall program-instance Pretty a => Pretty (Expr s a) where- pretty = Pretty.unAnnotate . prettyExpr--{-| `shift` is used by both normalization and type-checking to avoid variable- capture by shifting variable indices-- For example, suppose that you were to normalize the following expression:--> λ(a : Type) → λ(x : a) → (λ(y : a) → λ(x : a) → y) x-- If you were to substitute @y@ with @x@ without shifting any variable- indices, then you would get the following incorrect result:--> λ(a : Type) → λ(x : a) → λ(x : a) → x -- Incorrect normalized form-- In order to substitute @x@ in place of @y@ we need to `shift` @x@ by @1@ in- order to avoid being misinterpreted as the @x@ bound by the innermost- lambda. If we perform that `shift` then we get the correct result:--> λ(a : Type) → λ(x : a) → λ(x : a) → x@1-- As a more worked example, suppose that you were to normalize the following- expression:--> λ(a : Type)-> → λ(f : a → a → a)-> → λ(x : a)-> → λ(x : a)-> → (λ(x : a) → f x x@1) x@1-- The correct normalized result would be:--> λ(a : Type)-> → λ(f : a → a → a)-> → λ(x : a)-> → λ(x : a)-> → f x@1 x-- The above example illustrates how we need to both increase and decrease- variable indices as part of substitution:-- * We need to increase the index of the outer @x\@1@ to @x\@2@ before we- substitute it into the body of the innermost lambda expression in order- to avoid variable capture. This substitution changes the body of the- lambda expression to @(f x\@2 x\@1)@-- * We then remove the innermost lambda and therefore decrease the indices of- both @x@s in @(f x\@2 x\@1)@ to @(f x\@1 x)@ in order to reflect that one- less @x@ variable is now bound within that scope-- Formally, @(shift d (V x n) e)@ modifies the expression @e@ by adding @d@ to- the indices of all variables named @x@ whose indices are greater than- @(n + m)@, where @m@ is the number of bound variables of the same name- within that scope-- In practice, @d@ is always @1@ or @-1@ because we either:-- * increment variables by @1@ to avoid variable capture during substitution- * decrement variables by @1@ when deleting lambdas after substitution-- @n@ starts off at @0@ when substitution begins and increments every time we- descend into a lambda or let expression that binds a variable of the same- name in order to avoid shifting the bound variables by mistake.--}-shift :: Integer -> Var -> Expr s a -> Expr s a-shift _ _ (Const a) = Const a-shift d (V x n) (Var (V x' n')) = Var (V x' n'')- where- n'' = if x == x' && n <= n' then n' + d else n'-shift d (V x n) (Lam x' _A b) = Lam x' _A' b'- where- _A' = shift d (V x n ) _A- b' = shift d (V x n') b- where- n' = if x == x' then n + 1 else n-shift d (V x n) (Pi x' _A _B) = Pi x' _A' _B'- where- _A' = shift d (V x n ) _A- _B' = shift d (V x n') _B- where- n' = if x == x' then n + 1 else n-shift d v (App f a) = App f' a'- where- f' = shift d v f- a' = shift d v a-shift d (V x₀ n₀) (Let (Binding x₁ mA₀ a₀ :| []) b₀) =- Let (Binding x₁ mA₁ a₁ :| []) b₁- where- n₁ = if x₀ == x₁ then n₀ + 1 else n₀-- mA₁ = fmap (shift d (V x₀ n₀)) mA₀- a₁ = shift d (V x₀ n₀) a₀-- b₁ = shift d (V x₀ n₁) b₀-shift d (V x₀ n₀) (Let (Binding x₁ mA₀ a₀ :| (l₀ : ls₀)) b₀) =- case shift d (V x₀ n₁) (Let (l₀ :| ls₀) b₀) of- Let (l₁ :| ls₁) b₁ -> Let (Binding x₁ mA₁ a₁ :| (l₁ : ls₁)) b₁- e -> Let (Binding x₁ mA₁ a₁ :| [] ) e- where- n₁ = if x₀ == x₁ then n₀ + 1 else n₀-- mA₁ = fmap (shift d (V x₀ n₀)) mA₀- a₁ = shift d (V x₀ n₀) a₀--shift d v (Annot a b) = Annot a' b'- where- a' = shift d v a- b' = shift d v b-shift _ _ Bool = Bool-shift _ _ (BoolLit a) = BoolLit a-shift d v (BoolAnd a b) = BoolAnd a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (BoolOr a b) = BoolOr a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (BoolEQ a b) = BoolEQ a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (BoolNE a b) = BoolNE a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (BoolIf a b c) = BoolIf a' b' c'- where- a' = shift d v a- b' = shift d v b- c' = shift d v c-shift _ _ Natural = Natural-shift _ _ (NaturalLit a) = NaturalLit a-shift _ _ NaturalFold = NaturalFold-shift _ _ NaturalBuild = NaturalBuild-shift _ _ NaturalIsZero = NaturalIsZero-shift _ _ NaturalEven = NaturalEven-shift _ _ NaturalOdd = NaturalOdd-shift _ _ NaturalToInteger = NaturalToInteger-shift _ _ NaturalShow = NaturalShow-shift d v (NaturalPlus a b) = NaturalPlus a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (NaturalTimes a b) = NaturalTimes a' b'- where- a' = shift d v a- b' = shift d v b-shift _ _ Integer = Integer-shift _ _ (IntegerLit a) = IntegerLit a-shift _ _ IntegerShow = IntegerShow-shift _ _ IntegerToDouble = IntegerToDouble-shift _ _ Double = Double-shift _ _ (DoubleLit a) = DoubleLit a-shift _ _ DoubleShow = DoubleShow-shift _ _ Text = Text-shift d v (TextLit (Chunks a b)) = TextLit (Chunks a' b)- where- a' = fmap (fmap (shift d v)) a-shift d v (TextAppend a b) = TextAppend a' b'- where- a' = shift d v a- b' = shift d v b-shift _ _ TextShow = TextShow-shift _ _ List = List-shift d v (ListLit a b) = ListLit a' b'- where- a' = fmap (shift d v) a- b' = fmap (shift d v) b-shift _ _ ListBuild = ListBuild-shift d v (ListAppend a b) = ListAppend a' b'- where- a' = shift d v a- b' = shift d v b-shift _ _ ListFold = ListFold-shift _ _ ListLength = ListLength-shift _ _ ListHead = ListHead-shift _ _ ListLast = ListLast-shift _ _ ListIndexed = ListIndexed-shift _ _ ListReverse = ListReverse-shift _ _ Optional = Optional-shift d v (OptionalLit a b) = OptionalLit a' b'- where- a' = shift d v a- b' = fmap (shift d v) b-shift d v (Some a) = Some a'- where- a' = shift d v a-shift _ _ None = None-shift _ _ OptionalFold = OptionalFold-shift _ _ OptionalBuild = OptionalBuild-shift d v (Record a) = Record a'- where- a' = fmap (shift d v) a-shift d v (RecordLit a) = RecordLit a'- where- a' = fmap (shift d v) a-shift d v (Union a) = Union a'- where- a' = fmap (fmap (shift d v)) a-shift d v (UnionLit a b c) = UnionLit a b' c'- where- b' = shift d v b- c' = fmap (fmap (shift d v)) c-shift d v (Combine a b) = Combine a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (CombineTypes a b) = CombineTypes a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (Prefer a b) = Prefer a' b'- where- a' = shift d v a- b' = shift d v b-shift d v (Merge a b c) = Merge a' b' c'- where- a' = shift d v a- b' = shift d v b- c' = fmap (shift d v) c-shift d v (Field a b) = Field a' b- where- a' = shift d v a-shift d v (Project a b) = Project a' b- where- a' = shift d v a-shift d v (Note a b) = Note a b'- where- b' = shift d v b-shift d v (ImportAlt a b) = ImportAlt a' b'- where- a' = shift d v a- b' = shift d v b--- The Dhall compiler enforces that all embedded values are closed expressions--- and `shift` does nothing to a closed expression-shift _ _ (Embed p) = Embed p--{-| Substitute all occurrences of a variable with an expression--> subst x C B ~ B[x := C]--}-subst :: Var -> Expr s a -> Expr s a -> Expr s a-subst _ _ (Const a) = Const a-subst (V x n) e (Lam y _A b) = Lam y _A' b'- where- _A' = subst (V x n ) e _A- b' = subst (V x n') (shift 1 (V y 0) e) b- n' = if x == y then n + 1 else n-subst (V x n) e (Pi y _A _B) = Pi y _A' _B'- where- _A' = subst (V x n ) e _A- _B' = subst (V x n') (shift 1 (V y 0) e) _B- n' = if x == y then n + 1 else n-subst v e (App f a) = App f' a'- where- f' = subst v e f- a' = subst v e a-subst v e (Var v') = if v == v' then e else Var v'-subst (V x₀ n₀) e₀ (Let (Binding x₁ mA₀ a₀ :| []) b₀) =- Let (Binding x₁ mA₁ a₁ :| []) b₁- where- n₁ = if x₀ == x₁ then n₀ + 1 else n₀-- e₁ = shift 1 (V x₁ 0) e₀-- mA₁ = fmap (subst (V x₀ n₀) e₀) mA₀- a₁ = subst (V x₀ n₀) e₀ a₀-- b₁ = subst (V x₀ n₁) e₁ b₀-subst (V x₀ n₀) e₀ (Let (Binding x₁ mA₀ a₀ :| (l₀ : ls₀)) b₀) =- case subst (V x₀ n₁) e₁ (Let (l₀ :| ls₀) b₀) of- Let (l₁ :| ls₁) b₁ -> Let (Binding x₁ mA₁ a₁ :| (l₁ : ls₁)) b₁- e -> Let (Binding x₁ mA₁ a₁ :| [] ) e- where- n₁ = if x₀ == x₁ then n₀ + 1 else n₀-- e₁ = shift 1 (V x₁ 0) e₀-- mA₁ = fmap (subst (V x₀ n₀) e₀) mA₀- a₁ = subst (V x₀ n₀) e₀ a₀--subst x e (Annot a b) = Annot a' b'- where- a' = subst x e a- b' = subst x e b-subst _ _ Bool = Bool-subst _ _ (BoolLit a) = BoolLit a-subst x e (BoolAnd a b) = BoolAnd a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (BoolOr a b) = BoolOr a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (BoolEQ a b) = BoolEQ a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (BoolNE a b) = BoolNE a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (BoolIf a b c) = BoolIf a' b' c'- where- a' = subst x e a- b' = subst x e b- c' = subst x e c-subst _ _ Natural = Natural-subst _ _ (NaturalLit a) = NaturalLit a-subst _ _ NaturalFold = NaturalFold-subst _ _ NaturalBuild = NaturalBuild-subst _ _ NaturalIsZero = NaturalIsZero-subst _ _ NaturalEven = NaturalEven-subst _ _ NaturalOdd = NaturalOdd-subst _ _ NaturalToInteger = NaturalToInteger-subst _ _ NaturalShow = NaturalShow-subst x e (NaturalPlus a b) = NaturalPlus a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (NaturalTimes a b) = NaturalTimes a' b'- where- a' = subst x e a- b' = subst x e b-subst _ _ Integer = Integer-subst _ _ (IntegerLit a) = IntegerLit a-subst _ _ IntegerShow = IntegerShow-subst _ _ IntegerToDouble = IntegerToDouble-subst _ _ Double = Double-subst _ _ (DoubleLit a) = DoubleLit a-subst _ _ DoubleShow = DoubleShow-subst _ _ Text = Text-subst x e (TextLit (Chunks a b)) = TextLit (Chunks a' b)- where- a' = fmap (fmap (subst x e)) a-subst x e (TextAppend a b) = TextAppend a' b'- where- a' = subst x e a- b' = subst x e b-subst _ _ TextShow = TextShow-subst _ _ List = List-subst x e (ListLit a b) = ListLit a' b'- where- a' = fmap (subst x e) a- b' = fmap (subst x e) b-subst x e (ListAppend a b) = ListAppend a' b'- where- a' = subst x e a- b' = subst x e b-subst _ _ ListBuild = ListBuild-subst _ _ ListFold = ListFold-subst _ _ ListLength = ListLength-subst _ _ ListHead = ListHead-subst _ _ ListLast = ListLast-subst _ _ ListIndexed = ListIndexed-subst _ _ ListReverse = ListReverse-subst _ _ Optional = Optional-subst x e (OptionalLit a b) = OptionalLit a' b'- where- a' = subst x e a- b' = fmap (subst x e) b-subst x e (Some a) = Some a'- where- a' = subst x e a-subst _ _ None = None-subst _ _ OptionalFold = OptionalFold-subst _ _ OptionalBuild = OptionalBuild-subst x e (Record kts) = Record kts'- where- kts' = fmap (subst x e) kts-subst x e (RecordLit kvs) = RecordLit kvs'- where- kvs' = fmap (subst x e) kvs-subst x e (Union kts) = Union kts'- where- kts' = fmap (fmap (subst x e)) kts-subst x e (UnionLit a b kts) = UnionLit a b' kts'- where- b' = subst x e b- kts' = fmap (fmap (subst x e)) kts-subst x e (Combine a b) = Combine a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (CombineTypes a b) = CombineTypes a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (Prefer a b) = Prefer a' b'- where- a' = subst x e a- b' = subst x e b-subst x e (Merge a b c) = Merge a' b' c'- where- a' = subst x e a- b' = subst x e b- c' = fmap (subst x e) c-subst x e (Field a b) = Field a' b- where- a' = subst x e a-subst x e (Project a b) = Project a' b- where- a' = subst x e a-subst x e (Note a b) = Note a b'- where- b' = subst x e b-subst x e (ImportAlt a b) = ImportAlt a' b'- where- a' = subst x e a- b' = subst x e b--- The Dhall compiler enforces that all embedded values are closed expressions--- and `subst` does nothing to a closed expression-subst _ _ (Embed p) = Embed p--{-| α-normalize an expression by renaming all bound variables to @\"_\"@ and- using De Bruijn indices to distinguish them-->>> alphaNormalize (Lam "a" (Const Type) (Lam "b" (Const Type) (Lam "x" "a" (Lam "y" "b" "x"))))-Lam "_" (Const Type) (Lam "_" (Const Type) (Lam "_" (Var (V "_" 1)) (Lam "_" (Var (V "_" 1)) (Var (V "_" 1)))))-- α-normalization does not affect free variables:-->>> alphaNormalize "x"-Var (V "x" 0)---}-alphaNormalize :: Expr s a -> Expr s a-alphaNormalize = Dhall.Eval.alphaNormalize--{-| Reduce an expression to its normal form, performing beta reduction-- `normalize` does not type-check the expression. You may want to type-check- expressions before normalizing them since normalization can convert an- ill-typed expression into a well-typed expression.-- However, `normalize` will not fail if the expression is ill-typed and will- leave ill-typed sub-expressions unevaluated.--}--normalize :: Eq a => Expr s a -> Expr t a-normalize = Dhall.Eval.nfEmpty---{-| This function is used to determine whether folds like @Natural/fold@ or- @List/fold@ should be lazy or strict in their accumulator based on the type- of the accumulator-- If this function returns `True`, then they will be strict in their- accumulator since we can guarantee an upper bound on the amount of work to- normalize the accumulator on each step of the loop. If this function- returns `False` then they will be lazy in their accumulator and only- normalize the final result at the end of the fold--}-boundedType :: Expr s a -> Bool-boundedType Bool = True-boundedType Natural = True-boundedType Integer = True-boundedType Double = True-boundedType Text = True-boundedType (App List _) = False-boundedType (App Optional t) = boundedType t-boundedType (Record kvs) = all boundedType kvs-boundedType (Union kvs) = all (all boundedType) kvs-boundedType _ = False---- | Remove all `Note` constructors from an `Expr` (i.e. de-`Note`)-denote :: Expr s a -> Expr t a-denote (Note _ b ) = denote b-denote (Const a ) = Const a-denote (Var a ) = Var a-denote (Lam a b c ) = Lam a (denote b) (denote c)-denote (Pi a b c ) = Pi a (denote b) (denote c)-denote (App a b ) = App (denote a) (denote b)-denote (Let as b ) = Let (fmap f as) (denote b)- where- f (Binding c d e) = Binding c (fmap denote d) (denote e)-denote (Annot a b ) = Annot (denote a) (denote b)-denote Bool = Bool-denote (BoolLit a ) = BoolLit a-denote (BoolAnd a b ) = BoolAnd (denote a) (denote b)-denote (BoolOr a b ) = BoolOr (denote a) (denote b)-denote (BoolEQ a b ) = BoolEQ (denote a) (denote b)-denote (BoolNE a b ) = BoolNE (denote a) (denote b)-denote (BoolIf a b c ) = BoolIf (denote a) (denote b) (denote c)-denote Natural = Natural-denote (NaturalLit a ) = NaturalLit a-denote NaturalFold = NaturalFold-denote NaturalBuild = NaturalBuild-denote NaturalIsZero = NaturalIsZero-denote NaturalEven = NaturalEven-denote NaturalOdd = NaturalOdd-denote NaturalToInteger = NaturalToInteger-denote NaturalShow = NaturalShow-denote (NaturalPlus a b ) = NaturalPlus (denote a) (denote b)-denote (NaturalTimes a b ) = NaturalTimes (denote a) (denote b)-denote Integer = Integer-denote (IntegerLit a ) = IntegerLit a-denote IntegerShow = IntegerShow-denote IntegerToDouble = IntegerToDouble-denote Double = Double-denote (DoubleLit a ) = DoubleLit a-denote DoubleShow = DoubleShow-denote Text = Text-denote (TextLit (Chunks a b)) = TextLit (Chunks (fmap (fmap denote) a) b)-denote (TextAppend a b ) = TextAppend (denote a) (denote b)-denote TextShow = TextShow-denote List = List-denote (ListLit a b ) = ListLit (fmap denote a) (fmap denote b)-denote (ListAppend a b ) = ListAppend (denote a) (denote b)-denote ListBuild = ListBuild-denote ListFold = ListFold-denote ListLength = ListLength-denote ListHead = ListHead-denote ListLast = ListLast-denote ListIndexed = ListIndexed-denote ListReverse = ListReverse-denote Optional = Optional-denote (OptionalLit a b ) = OptionalLit (denote a) (fmap denote b)-denote (Some a ) = Some (denote a)-denote None = None-denote OptionalFold = OptionalFold-denote OptionalBuild = OptionalBuild-denote (Record a ) = Record (fmap denote a)-denote (RecordLit a ) = RecordLit (fmap denote a)-denote (Union a ) = Union (fmap (fmap denote) a)-denote (UnionLit a b c ) = UnionLit a (denote b) (fmap (fmap denote) c)-denote (Combine a b ) = Combine (denote a) (denote b)-denote (CombineTypes a b ) = CombineTypes (denote a) (denote b)-denote (Prefer a b ) = Prefer (denote a) (denote b)-denote (Merge a b c ) = Merge (denote a) (denote b) (fmap denote c)-denote (Field a b ) = Field (denote a) b-denote (Project a b ) = Project (denote a) (fmap denote b)-denote (ImportAlt a b ) = ImportAlt (denote a) (denote b)-denote (Embed a ) = Embed a--{-| Reduce an expression to its normal form, performing beta reduction and applying- any custom definitions.-- `normalizeWith` is designed to be used with function `typeWith`. The `typeWith`- function allows typing of Dhall functions in a custom typing context whereas- `normalizeWith` allows evaluating Dhall expressions in a custom context.-- To be more precise `normalizeWith` applies the given normalizer when it finds an- application term that it cannot reduce by other means.-- Note that the context used in normalization will determine the properties of normalization.- That is, if the functions in custom context are not total then the Dhall language, evaluated- with those functions is not total either.---}-normalizeWith :: Eq a => Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a-normalizeWith (Just ctx) t = runIdentity (normalizeWithM (getReifiedNormalizer ctx) t)-normalizeWith _ t = Dhall.Eval.nfEmpty t--normalizeWithM- :: (Monad m, Eq a) => NormalizerM m a -> Expr s a -> m (Expr t a)-normalizeWithM ctx e0 = loop (denote e0)- where- loop e = case e of- Const k -> pure (Const k)- Var v -> pure (Var v)- Lam x _A b -> Lam x <$> _A' <*> b'- where- _A' = loop _A- b' = loop b- Pi x _A _B -> Pi x <$> _A' <*> _B'- where- _A' = loop _A- _B' = loop _B- App f a -> do- res <- ctx (App f a)- case res of- Just e1 -> loop e1- Nothing -> do- f' <- loop f- a' <- loop a- case f' of- Lam x _A b₀ -> do-- let a₂ = shift 1 (V x 0) a'- let b₁ = subst (V x 0) a₂ b₀- let b₂ = shift (-1) (V x 0) b₁-- loop b₂- _ -> do- case App f' a' of- -- build/fold fusion for `List`- App (App ListBuild _) (App (App ListFold _) e') -> loop e'-- -- build/fold fusion for `Natural`- App NaturalBuild (App NaturalFold e') -> loop e'-- -- build/fold fusion for `Optional`- App (App OptionalBuild _) (App (App OptionalFold _) e') -> loop e'-- App (App (App (App NaturalFold (NaturalLit n0)) t) succ') zero -> do- t' <- loop t- if boundedType t' then strict else lazy- where- strict = strictLoop (fromIntegral n0 :: Integer)- lazy = loop ( lazyLoop (fromIntegral n0 :: Integer))-- strictLoop !0 = loop zero- strictLoop !n = App succ' <$> strictLoop (n - 1) >>= loop-- lazyLoop !0 = zero- lazyLoop !n = App succ' (lazyLoop (n - 1))- App NaturalBuild g -> loop (App (App (App g Natural) succ) zero)- where- succ = Lam "x" Natural (NaturalPlus "x" (NaturalLit 1))-- zero = NaturalLit 0- App NaturalIsZero (NaturalLit n) -> pure (BoolLit (n == 0))- App NaturalEven (NaturalLit n) -> pure (BoolLit (even n))- App NaturalOdd (NaturalLit n) -> pure (BoolLit (odd n))- App NaturalToInteger (NaturalLit n) -> pure (IntegerLit (toInteger n))- App NaturalShow (NaturalLit n) ->- pure (TextLit (Chunks [] (Data.Text.pack (show n))))- App IntegerShow (IntegerLit n)- | 0 <= n -> pure (TextLit (Chunks [] ("+" <> Data.Text.pack (show n))))- | otherwise -> pure (TextLit (Chunks [] (Data.Text.pack (show n))))- -- `(read . show)` is used instead of `fromInteger` because `read` uses the correct rounding rule- App IntegerToDouble (IntegerLit n) -> pure (DoubleLit ((read . show) n))- App DoubleShow (DoubleLit n) ->- pure (TextLit (Chunks [] (Data.Text.pack (show n))))- App (App OptionalBuild _A₀) g ->- loop (App (App (App g optional) just) nothing)- where- optional = App Optional _A₀-- just = Lam "a" _A₀ (Some "a")-- nothing = App None _A₀- App (App ListBuild _A₀) g -> loop (App (App (App g list) cons) nil)- where- _A₁ = shift 1 "a" _A₀-- list = App List _A₀-- cons =- Lam "a" _A₀- (Lam "as"- (App List _A₁)- (ListAppend (ListLit Nothing (pure "a")) "as")- )-- nil = ListLit (Just _A₀) empty- App (App (App (App (App ListFold _) (ListLit _ xs)) t) cons) nil -> do- t' <- loop t- if boundedType t' then strict else lazy- where- strict = foldr strictCons strictNil xs- lazy = loop (foldr lazyCons lazyNil xs)-- strictNil = loop nil- lazyNil = nil-- strictCons y ys = do- App (App cons y) <$> ys >>= loop- lazyCons y ys = App (App cons y) ys- App (App ListLength _) (ListLit _ ys) ->- pure (NaturalLit (fromIntegral (Data.Sequence.length ys)))- App (App ListHead t) (ListLit _ ys) -> loop o- where- o = case Data.Sequence.viewl ys of- y :< _ -> Some y- _ -> App None t- App (App ListLast t) (ListLit _ ys) -> loop o- where- o = case Data.Sequence.viewr ys of- _ :> y -> Some y- _ -> App None t- App (App ListIndexed _A₀) (ListLit _A₁ as₀) -> loop (ListLit t as₁)- where- as₁ = Data.Sequence.mapWithIndex adapt as₀-- _A₂ = Record (Dhall.Map.fromList kts)- where- kts = [ ("index", Natural)- , ("value", _A₀)- ]-- t | null as₀ = Just _A₂- | otherwise = Nothing-- adapt n a_ =- RecordLit (Dhall.Map.fromList kvs)- where- kvs = [ ("index", NaturalLit (fromIntegral n))- , ("value", a_)- ]- App (App ListReverse t) (ListLit _ xs) ->- loop (ListLit m (Data.Sequence.reverse xs))- where- m = if Data.Sequence.null xs then Just t else Nothing- App (App (App (App (App OptionalFold _) (App None _)) _) _) nothing ->- loop nothing- App (App (App (App (App OptionalFold _) (Some x)) _) just) _ ->- loop (App just x)- App TextShow (TextLit (Chunks [] oldText)) ->- loop (TextLit (Chunks [] newText))- where- newText = textShow oldText- _ -> do- res2 <- ctx (App f' a')- case res2 of- Nothing -> pure (App f' a')- Just app' -> loop app'- Let (Binding x _ a₀ :| ls₀) b₀ -> do- a₁ <- loop a₀-- rest <- case ls₀ of- [] -> loop b₀- l₁ : ls₁ -> loop (Let (l₁ :| ls₁) b₀)-- let a₂ = shift 1 (V x 0) a₁- let b₁ = subst (V x 0) a₂ rest- let b₂ = shift (-1) (V x 0) b₁-- loop b₂- Annot x _ -> loop x- Bool -> pure Bool- BoolLit b -> pure (BoolLit b)- BoolAnd x y -> decide <$> loop x <*> loop y- where- decide (BoolLit True ) r = r- decide (BoolLit False) _ = BoolLit False- decide l (BoolLit True ) = l- decide _ (BoolLit False) = BoolLit False- decide l r- | judgmentallyEqual l r = l- | otherwise = BoolAnd l r- BoolOr x y -> decide <$> loop x <*> loop y- where- decide (BoolLit False) r = r- decide (BoolLit True ) _ = BoolLit True- decide l (BoolLit False) = l- decide _ (BoolLit True ) = BoolLit True- decide l r- | judgmentallyEqual l r = l- | otherwise = BoolOr l r- BoolEQ x y -> decide <$> loop x <*> loop y- where- decide (BoolLit True ) r = r- decide l (BoolLit True ) = l- decide l r- | judgmentallyEqual l r = BoolLit True- | otherwise = BoolEQ l r- BoolNE x y -> decide <$> loop x <*> loop y- where- decide (BoolLit False) r = r- decide l (BoolLit False) = l- decide l r- | judgmentallyEqual l r = BoolLit False- | otherwise = BoolNE l r- BoolIf bool true false -> decide <$> loop bool <*> loop true <*> loop false- where- decide (BoolLit True ) l _ = l- decide (BoolLit False) _ r = r- decide b (BoolLit True) (BoolLit False) = b- decide b l r- | judgmentallyEqual l r = l- | otherwise = BoolIf b l r- Natural -> pure Natural- NaturalLit n -> pure (NaturalLit n)- NaturalFold -> pure NaturalFold- NaturalBuild -> pure NaturalBuild- NaturalIsZero -> pure NaturalIsZero- NaturalEven -> pure NaturalEven- NaturalOdd -> pure NaturalOdd- NaturalToInteger -> pure NaturalToInteger- NaturalShow -> pure NaturalShow- NaturalPlus x y -> decide <$> loop x <*> loop y- where- decide (NaturalLit 0) r = r- decide l (NaturalLit 0) = l- decide (NaturalLit m) (NaturalLit n) = NaturalLit (m + n)- decide l r = NaturalPlus l r- NaturalTimes x y -> decide <$> loop x <*> loop y- where- decide (NaturalLit 1) r = r- decide l (NaturalLit 1) = l- decide (NaturalLit 0) _ = NaturalLit 0- decide _ (NaturalLit 0) = NaturalLit 0- decide (NaturalLit m) (NaturalLit n) = NaturalLit (m * n)- decide l r = NaturalTimes l r- Integer -> pure Integer- IntegerLit n -> pure (IntegerLit n)- IntegerShow -> pure IntegerShow- IntegerToDouble -> pure IntegerToDouble- Double -> pure Double- DoubleLit n -> pure (DoubleLit n)- DoubleShow -> pure DoubleShow- Text -> pure Text- TextLit (Chunks xys z) -> do- chunks' <- mconcat <$> chunks- case chunks' of- Chunks [("", x)] "" -> pure x- c -> pure (TextLit c)- where- chunks =- ((++ [Chunks [] z]) . concat) <$> traverse process xys-- process (x, y) = do- y' <- loop y- case y' of- TextLit c -> pure [Chunks [] x, c]- _ -> pure [Chunks [(x, y')] mempty]- TextAppend x y -> loop (TextLit (Chunks [("", x), ("", y)] ""))- TextShow -> pure TextShow- List -> pure List- ListLit t es- | Data.Sequence.null es -> ListLit <$> t' <*> es'- | otherwise -> ListLit Nothing <$> es'- where- t' = traverse loop t- es' = traverse loop es- ListAppend x y -> decide <$> loop x <*> loop y- where- decide (ListLit _ m) r | Data.Sequence.null m = r- decide l (ListLit _ n) | Data.Sequence.null n = l- decide (ListLit t m) (ListLit _ n) = ListLit t (m <> n)- decide l r = ListAppend l r- ListBuild -> pure ListBuild- ListFold -> pure ListFold- ListLength -> pure ListLength- ListHead -> pure ListHead- ListLast -> pure ListLast- ListIndexed -> pure ListIndexed- ListReverse -> pure ListReverse- Optional -> pure Optional- OptionalLit _A Nothing -> loop (App None _A)- OptionalLit _ (Just a) -> loop (Some a)- Some a -> Some <$> a'- where- a' = loop a- None -> pure None- OptionalFold -> pure OptionalFold- OptionalBuild -> pure OptionalBuild- Record kts -> Record . Dhall.Map.sort <$> kts'- where- kts' = traverse loop kts- RecordLit kvs -> RecordLit . Dhall.Map.sort <$> kvs'- where- kvs' = traverse loop kvs- Union kts -> Union . Dhall.Map.sort <$> kts'- where- kts' = traverse (traverse loop) kts- UnionLit k v kvs -> UnionLit k <$> v' <*> (Dhall.Map.sort <$> kvs')- where- v' = loop v- kvs' = traverse (traverse loop) kvs- Combine x y -> decide <$> loop x <*> loop y- where- decide (RecordLit m) r | Data.Foldable.null m =- r- decide l (RecordLit n) | Data.Foldable.null n =- l- decide (RecordLit m) (RecordLit n) =- RecordLit (Dhall.Map.sort (Dhall.Map.unionWith decide m n))- decide l r =- Combine l r- CombineTypes x y -> decide <$> loop x <*> loop y- where- decide (Record m) r | Data.Foldable.null m =- r- decide l (Record n) | Data.Foldable.null n =- l- decide (Record m) (Record n) =- Record (Dhall.Map.sort (Dhall.Map.unionWith decide m n))- decide l r =- CombineTypes l r- Prefer x y -> decide <$> loop x <*> loop y- where- decide (RecordLit m) r | Data.Foldable.null m =- r- decide l (RecordLit n) | Data.Foldable.null n =- l- decide (RecordLit m) (RecordLit n) =- RecordLit (Dhall.Map.sort (Dhall.Map.union n m))- decide l r =- Prefer l r- Merge x y t -> do- x' <- loop x- y' <- loop y- case x' of- RecordLit kvsX ->- case y' of- UnionLit kY vY _ ->- case Dhall.Map.lookup kY kvsX of- Just vX -> loop (App vX vY)- Nothing -> Merge x' y' <$> t'- Field (Union ktsY) kY ->- case Dhall.Map.lookup kY ktsY of- Just Nothing ->- case Dhall.Map.lookup kY kvsX of- Just vX -> return vX- Nothing -> Merge x' y' <$> t'- _ ->- Merge x' y' <$> t'- App (Field (Union ktsY) kY) vY ->- case Dhall.Map.lookup kY ktsY of- Just (Just _) ->- case Dhall.Map.lookup kY kvsX of- Just vX -> loop (App vX vY)- Nothing -> Merge x' y' <$> t'- _ ->- Merge x' y' <$> t'- _ -> Merge x' y' <$> t'- _ -> Merge x' y' <$> t'- where- t' = traverse loop t- Field r x -> do- r' <- loop r- case r' of- RecordLit kvs ->- case Dhall.Map.lookup x kvs of- Just v -> loop v- Nothing -> Field <$> (RecordLit <$> traverse loop kvs) <*> pure x- _ -> pure (Field r' x)- Project r (Left xs)-> do- r' <- loop r- case r' of- RecordLit kvs ->- case traverse adapt (Dhall.Set.toList xs) of- Just s ->- loop (RecordLit kvs')- where- kvs' = Dhall.Map.fromList s- Nothing ->- Project <$> (RecordLit <$> traverse loop kvs) <*> pure (Left xs)- where- adapt x = do- v <- Dhall.Map.lookup x kvs- return (x, v)- _ | null xs -> pure (RecordLit mempty)- | otherwise -> pure (Project r' (Left xs))- Project r (Right e1) -> do- e2 <- loop e1-- case e2 of- Record kts -> do- loop (Project r (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))- _ -> do- r' <- loop r- pure (Project r' (Right e2))- Note _ e' -> loop e'- ImportAlt l _r -> loop l- Embed a -> pure (Embed a)--textShow :: Text -> Text-textShow text = "\"" <> Data.Text.concatMap f text <> "\""- where- f '"' = "\\\""- f '$' = "\\u0024"- f '\\' = "\\\\"- f '\b' = "\\b"- f '\n' = "\\n"- f '\r' = "\\r"- f '\t' = "\\t"- f '\f' = "\\f"- f c | c <= '\x1F' = Data.Text.pack (Text.Printf.printf "\\u%04x" (Data.Char.ord c))- | otherwise = Data.Text.singleton c--{-| Returns `True` if two expressions are α-equivalent and β-equivalent and- `False` otherwise--}-judgmentallyEqual :: Eq a => Expr s a -> Expr t a -> Bool-judgmentallyEqual = Dhall.Eval.convEmpty---- | Use this to wrap you embedded functions (see `normalizeWith`) to make them--- polymorphic enough to be used.-type NormalizerM m a = forall s. Expr s a -> m (Maybe (Expr s a))--type Normalizer a = NormalizerM Identity a---- | A reified 'Normalizer', which can be stored in structures without--- running into impredicative polymorphism.-newtype ReifiedNormalizer a = ReifiedNormalizer- { getReifiedNormalizer :: Normalizer a }---- | Check if an expression is in a normal form given a context of evaluation.--- Unlike `isNormalized`, this will fully normalize and traverse through the expression.------ It is much more efficient to use `isNormalized`.-isNormalizedWith :: (Eq s, Eq a) => Normalizer a -> Expr s a -> Bool-isNormalizedWith ctx e = e == normalizeWith (Just (ReifiedNormalizer ctx)) e---- | Quickly check if an expression is in normal form-isNormalized :: Eq a => Expr s a -> Bool-isNormalized e0 = loop (denote e0)- where- loop e = case e of- Const _ -> True- Var _ -> True- Lam _ a b -> loop a && loop b- Pi _ a b -> loop a && loop b- App f a -> loop f && loop a && case App f a of- App (Lam _ _ _) _ -> False-- -- build/fold fusion for `List`- App (App ListBuild _) (App (App ListFold _) _) -> False-- -- build/fold fusion for `Natural`- App NaturalBuild (App NaturalFold _) -> False-- -- build/fold fusion for `Optional`- App (App OptionalBuild _) (App (App OptionalFold _) _) -> False-- App (App (App (App NaturalFold (NaturalLit _)) _) _) _ -> False- App NaturalBuild _ -> False- App NaturalIsZero (NaturalLit _) -> False- App NaturalEven (NaturalLit _) -> False- App NaturalOdd (NaturalLit _) -> False- App NaturalShow (NaturalLit _) -> False- App NaturalToInteger (NaturalLit _) -> False- App IntegerShow (IntegerLit _) -> False- App IntegerToDouble (IntegerLit _) -> False- App DoubleShow (DoubleLit _) -> False- App (App OptionalBuild _) _ -> False- App (App ListBuild _) _ -> False- App (App (App (App (App ListFold _) (ListLit _ _)) _) _) _ ->- False- App (App ListLength _) (ListLit _ _) -> False- App (App ListHead _) (ListLit _ _) -> False- App (App ListLast _) (ListLit _ _) -> False- App (App ListIndexed _) (ListLit _ _) -> False- App (App ListReverse _) (ListLit _ _) -> False- App (App (App (App (App OptionalFold _) (Some _)) _) _) _ ->- False- App (App (App (App (App OptionalFold _) (App None _)) _) _) _ ->- False- App TextShow (TextLit (Chunks [] _)) ->- False- _ -> True- Let _ _ -> False- Annot _ _ -> False- Bool -> True- BoolLit _ -> True- BoolAnd x y -> loop x && loop y && decide x y- where- decide (BoolLit _) _ = False- decide _ (BoolLit _) = False- decide l r = not (judgmentallyEqual l r)- BoolOr x y -> loop x && loop y && decide x y- where- decide (BoolLit _) _ = False- decide _ (BoolLit _) = False- decide l r = not (judgmentallyEqual l r)- BoolEQ x y -> loop x && loop y && decide x y- where- decide (BoolLit True) _ = False- decide _ (BoolLit True) = False- decide l r = not (judgmentallyEqual l r)- BoolNE x y -> loop x && loop y && decide x y- where- decide (BoolLit False) _ = False- decide _ (BoolLit False ) = False- decide l r = not (judgmentallyEqual l r)- BoolIf x y z ->- loop x && loop y && loop z && decide x y z- where- decide (BoolLit _) _ _ = False- decide _ (BoolLit True) (BoolLit False) = False- decide _ l r = not (judgmentallyEqual l r)- Natural -> True- NaturalLit _ -> True- NaturalFold -> True- NaturalBuild -> True- NaturalIsZero -> True- NaturalEven -> True- NaturalOdd -> True- NaturalShow -> True- NaturalToInteger -> True- NaturalPlus x y -> loop x && loop y && decide x y- where- decide (NaturalLit 0) _ = False- decide _ (NaturalLit 0) = False- decide (NaturalLit _) (NaturalLit _) = False- decide _ _ = True- NaturalTimes x y -> loop x && loop y && decide x y- where- decide (NaturalLit 0) _ = False- decide _ (NaturalLit 0) = False- decide (NaturalLit 1) _ = False- decide _ (NaturalLit 1) = False- decide (NaturalLit _) (NaturalLit _) = False- decide _ _ = True- Integer -> True- IntegerLit _ -> True- IntegerShow -> True- IntegerToDouble -> True- Double -> True- DoubleLit _ -> True- DoubleShow -> True- Text -> True- TextLit (Chunks [("", _)] "") -> False- TextLit (Chunks xys _) -> all (all check) xys- where- check y = loop y && case y of- TextLit _ -> False- _ -> True- TextAppend _ _ -> False- TextShow -> True- List -> True- ListLit t es -> all loop t && all loop es- ListAppend x y -> loop x && loop y && decide x y- where- decide (ListLit _ m) _ | Data.Sequence.null m = False- decide _ (ListLit _ n) | Data.Sequence.null n = False- decide (ListLit _ _) (ListLit _ _) = False- decide _ _ = True- ListBuild -> True- ListFold -> True- ListLength -> True- ListHead -> True- ListLast -> True- ListIndexed -> True- ListReverse -> True- Optional -> True- OptionalLit _ _ -> False- Some a -> loop a- None -> True- OptionalFold -> True- OptionalBuild -> True- Record kts -> Dhall.Map.isSorted kts && all loop kts- RecordLit kvs -> Dhall.Map.isSorted kvs && all loop kvs- Union kts -> Dhall.Map.isSorted kts && all (all loop) kts- UnionLit _ v kvs -> loop v && Dhall.Map.isSorted kvs && all (all loop) kvs- Combine x y -> loop x && loop y && decide x y- where- decide (RecordLit m) _ | Data.Foldable.null m = False- decide _ (RecordLit n) | Data.Foldable.null n = False- decide (RecordLit _) (RecordLit _) = False- decide _ _ = True- CombineTypes x y -> loop x && loop y && decide x y- where- decide (Record m) _ | Data.Foldable.null m = False- decide _ (Record n) | Data.Foldable.null n = False- decide (Record _) (Record _) = False- decide _ _ = True- Prefer x y -> loop x && loop y && decide x y- where- decide (RecordLit m) _ | Data.Foldable.null m = False- decide _ (RecordLit n) | Data.Foldable.null n = False- decide (RecordLit _) (RecordLit _) = False- decide _ _ = True- Merge x y t -> loop x && loop y && all loop t &&- case x of- RecordLit kvsX ->- case y of- UnionLit kY _ _ ->- case Dhall.Map.lookup kY kvsX of- Just _ -> False- Nothing -> True- _ -> True- _ -> True- Field r x -> loop r &&- case r of- RecordLit kvs ->- case Dhall.Map.lookup x kvs of- Just _ -> False- Nothing -> True- Union kvs ->- case Dhall.Map.lookup x kvs of- Just _ -> False- Nothing -> True- _ -> True- Project r xs -> loop r &&- case r of- RecordLit kvs ->- case xs of- Left s -> not (all (flip Dhall.Map.member kvs) s)- Right e' ->- case e' of- Record kts ->- loop (Project r (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))- _ ->- False- _ -> not (null xs)- Note _ e' -> loop e'- ImportAlt l _r -> loop l- Embed _ -> True--{-| Detect if the given variable is free within the given expression-->>> "x" `freeIn` "x"-True->>> "x" `freeIn` "y"-False->>> "x" `freeIn` Lam "x" (Const Type) "x"-False--}-freeIn :: Eq a => Var -> Expr s a -> Bool-variable `freeIn` expression =- Dhall.Core.shift 1 variable strippedExpression /= strippedExpression- where- denote' :: Expr t b -> Expr () b- denote' = denote-- strippedExpression = denote' expression--_ERROR :: String-_ERROR = "\ESC[1;31mError\ESC[0m"--{-| Utility function used to throw internal errors that should never happen- (in theory) but that are not enforced by the type system--}-internalError :: Data.Text.Text -> forall b . b-internalError text = error (unlines- [ _ERROR <> ": Compiler bug "- , " "- , "Explanation: This error message means that there is a bug in the Dhall compiler."- , "You didn't do anything wrong, but if you would like to see this problem fixed "- , "then you should report the bug at: "- , " "- , "https://github.com/dhall-lang/dhall-haskell/issues "- , " "- , "Please include the following text in your bug report: "- , " "- , "``` "- , Data.Text.unpack text <> " "- , "``` "- ] )---- | The set of reserved identifiers for the Dhall language-reservedIdentifiers :: HashSet Text-reservedIdentifiers =- Data.HashSet.fromList- [ "let"- , "in"- , "Type"- , "Kind"- , "Sort"- , "forall"- , "Bool"- , "True"- , "False"- , "merge"- , "if"- , "then"- , "else"- , "as"- , "using"- , "constructors"- , "Natural"- , "Natural/fold"- , "Natural/build"- , "Natural/isZero"- , "Natural/even"- , "Natural/odd"- , "Natural/toInteger"- , "Natural/show"- , "Integer"- , "Integer/show"- , "Integer/toDouble"- , "Double"- , "Double/show"- , "Text"- , "Text/show"- , "List"- , "List/build"- , "List/fold"- , "List/length"- , "List/head"- , "List/last"- , "List/indexed"- , "List/reverse"- , "Optional"- , "Some"- , "None"- , "Optional/build"- , "Optional/fold"- , "NaN"- , "Infinity"- ]----- | A traversal over the immediate sub-expressions of an expression.-subExpressions :: Applicative f => (Expr s a -> f (Expr s a)) -> Expr s a -> f (Expr s a)-subExpressions _ (Const c) = pure (Const c)-subExpressions _ (Var v) = pure (Var v)-subExpressions f (Lam a b c) = Lam a <$> f b <*> f c-subExpressions f (Pi a b c) = Pi a <$> f b <*> f c-subExpressions f (App a b) = App <$> f a <*> f b-subExpressions f (Let as b) = Let <$> traverse g as <*> f b- where- g (Binding c d e) = Binding c <$> traverse f d <*> f e-subExpressions f (Annot a b) = Annot <$> f a <*> f b-subExpressions _ Bool = pure Bool-subExpressions _ (BoolLit b) = pure (BoolLit b)-subExpressions f (BoolAnd a b) = BoolAnd <$> f a <*> f b-subExpressions f (BoolOr a b) = BoolOr <$> f a <*> f b-subExpressions f (BoolEQ a b) = BoolEQ <$> f a <*> f b-subExpressions f (BoolNE a b) = BoolNE <$> f a <*> f b-subExpressions f (BoolIf a b c) = BoolIf <$> f a <*> f b <*> f c-subExpressions _ Natural = pure Natural-subExpressions _ (NaturalLit n) = pure (NaturalLit n)-subExpressions _ NaturalFold = pure NaturalFold-subExpressions _ NaturalBuild = pure NaturalBuild-subExpressions _ NaturalIsZero = pure NaturalIsZero-subExpressions _ NaturalEven = pure NaturalEven-subExpressions _ NaturalOdd = pure NaturalOdd-subExpressions _ NaturalToInteger = pure NaturalToInteger-subExpressions _ NaturalShow = pure NaturalShow-subExpressions f (NaturalPlus a b) = NaturalPlus <$> f a <*> f b-subExpressions f (NaturalTimes a b) = NaturalTimes <$> f a <*> f b-subExpressions _ Integer = pure Integer-subExpressions _ (IntegerLit n) = pure (IntegerLit n)-subExpressions _ IntegerShow = pure IntegerShow-subExpressions _ IntegerToDouble = pure IntegerToDouble-subExpressions _ Double = pure Double-subExpressions _ (DoubleLit n) = pure (DoubleLit n)-subExpressions _ DoubleShow = pure DoubleShow-subExpressions _ Text = pure Text-subExpressions f (TextLit chunks) =- TextLit <$> chunkExprs f chunks-subExpressions f (TextAppend a b) = TextAppend <$> f a <*> f b-subExpressions _ TextShow = pure TextShow-subExpressions _ List = pure List-subExpressions f (ListLit a b) = ListLit <$> traverse f a <*> traverse f b-subExpressions f (ListAppend a b) = ListAppend <$> f a <*> f b-subExpressions _ ListBuild = pure ListBuild-subExpressions _ ListFold = pure ListFold-subExpressions _ ListLength = pure ListLength-subExpressions _ ListHead = pure ListHead-subExpressions _ ListLast = pure ListLast-subExpressions _ ListIndexed = pure ListIndexed-subExpressions _ ListReverse = pure ListReverse-subExpressions _ Optional = pure Optional-subExpressions f (OptionalLit a b) = OptionalLit <$> f a <*> traverse f b-subExpressions f (Some a) = Some <$> f a-subExpressions _ None = pure None-subExpressions _ OptionalFold = pure OptionalFold-subExpressions _ OptionalBuild = pure OptionalBuild-subExpressions f (Record a) = Record <$> traverse f a-subExpressions f ( RecordLit a ) = RecordLit <$> traverse f a-subExpressions f (Union a) = Union <$> traverse (traverse f) a-subExpressions f (UnionLit a b c) =- UnionLit a <$> f b <*> traverse (traverse f) c-subExpressions f (Combine a b) = Combine <$> f a <*> f b-subExpressions f (CombineTypes a b) = CombineTypes <$> f a <*> f b-subExpressions f (Prefer a b) = Prefer <$> f a <*> f b-subExpressions f (Merge a b t) = Merge <$> f a <*> f b <*> traverse f t-subExpressions f (Field a b) = Field <$> f a <*> pure b-subExpressions f (Project a b) = Project <$> f a <*> pure b-subExpressions f (Note a b) = Note a <$> f b-subExpressions f (ImportAlt l r) = ImportAlt <$> f l <*> f r-subExpressions _ (Embed a) = pure (Embed a)---- | A traversal over the immediate sub-expressions in 'Chunks'.-chunkExprs- :: Applicative f- => (Expr s a -> f (Expr t b))- -> Chunks s a -> f (Chunks t b)-chunkExprs f (Chunks chunks final) =- flip Chunks final <$> traverse (traverse f) chunks--{-| Returns `True` if the given `Char` is valid within an unquoted path- component-- This is exported for reuse within the @"Dhall.Parser.Token"@ module--}-pathCharacter :: Char -> Bool-pathCharacter c =- '\x21' == c- || ('\x24' <= c && c <= '\x27')- || ('\x2A' <= c && c <= '\x2B')- || ('\x2D' <= c && c <= '\x2E')- || ('\x30' <= c && c <= '\x3B')- || c == '\x3D'- || ('\x40' <= c && c <= '\x5A')- || ('\x5E' <= c && c <= '\x7A')- || c == '\x7C'- || c == '\x7E'--prettyPathComponent :: Text -> Doc ann-prettyPathComponent text- | Data.Text.all pathCharacter text =- "/" <> Pretty.pretty text- | otherwise =- "/\"" <> Pretty.pretty text <> "\""--prettyURIComponent :: Text -> Doc ann-prettyURIComponent text- | Data.Text.all (\c -> pathCharacter c && URI.Encode.isAllowed c) text =- "/" <> Pretty.pretty text- | otherwise =- "/\"" <> Pretty.pretty text <> "\""--{-| Convenience utility for converting `Either`-based exceptions to `IO`-based- exceptions--}-throws :: (Exception e, MonadIO io) => Either e a -> io a-throws (Left e) = liftIO (Control.Exception.throwIO e)-throws (Right r) = return r+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}++{-| This module contains the core calculus for the Dhall language.++ Dhall is essentially a fork of the @morte@ compiler but with more built-in+ functionality, better error messages, and Haskell integration+-}++module Dhall.Core (+ -- * Syntax+ Const(..)+ , Directory(..)+ , File(..)+ , FilePrefix(..)+ , Import(..)+ , ImportHashed(..)+ , ImportMode(..)+ , ImportType(..)+ , URL(..)+ , Scheme(..)+ , DhallDouble(..)+ , Var(..)+ , Binding(..)+ , makeBinding+ , Chunks(..)+ , PreferAnnotation(..)+ , RecordField(..)+ , makeRecordField+ , FunctionBinding(..)+ , makeFunctionBinding+ , FieldSelection (..)+ , makeFieldSelection+ , WithComponent (..)+ , Expr(..)++ -- * Normalization+ , alphaNormalize+ , normalize+ , normalizeWith+ , normalizeWithM+ , Normalizer+ , NormalizerM+ , ReifiedNormalizer (..)+ , judgmentallyEqual+ , subst+ , shift+ , isNormalized+ , isNormalizedWith+ , denote+ , renote+ , shallowDenote+ , freeIn++ -- * Pretty-printing+ , pretty++ -- * Optics+ , subExpressions+ , subExpressionsWith+ , chunkExprs+ , bindingExprs+ , recordFieldExprs+ , functionBindingExprs++ -- * Let-blocks+ , multiLet+ , wrapInLets+ , MultiLet(..)++ -- * Miscellaneous+ , internalError+ , reservedIdentifiers+ , escapeText+ , pathCharacter+ , throws+ , Eval.textShow+ , censorExpression+ , censorText+ ) where++import Control.Exception (Exception)+import Control.Monad.IO.Class (MonadIO (..))+import Data.Text (Text)+import Dhall.Normalize+import Dhall.Pretty.Internal+import Dhall.Src (Src (..))+import Dhall.Syntax+import Instances.TH.Lift ()+import Lens.Micro (over)+import Prettyprinter (Pretty)++import qualified Control.Exception+import qualified Data.Text+import qualified Dhall.Eval as Eval++-- | Pretty-print a value+pretty :: Pretty a => a -> Text+pretty = pretty_+{-# INLINE pretty #-}++{-| Escape a `Data.Text.Text` literal using Dhall's escaping rules++ Note that the result does not include surrounding quotes+-}+escapeText :: Text -> Text+escapeText = escapeText_+{-# INLINE escapeText #-}+++{-| Utility used to implement the @--censor@ flag, by:++ * Replacing all `Src` text with spaces+ * Replacing all `Dhall.Syntax.Text` literals inside type errors with spaces+-}+censorExpression :: Expr Src a -> Expr Src a+censorExpression (TextLit chunks) = TextLit (censorChunks chunks)+censorExpression (Note src e) = Note (censorSrc src) (censorExpression e)+censorExpression e = over subExpressions censorExpression e++censorChunks :: Chunks Src a -> Chunks Src a+censorChunks (Chunks xys z) = Chunks xys' z'+ where+ z' = censorText z++ xys' = [ (censorText x, censorExpression y) | (x, y) <- xys ]++{-| Utility used to censor `Data.Text.Text` by replacing all characters with a+ space+-}+censorText :: Text -> Text+censorText = Data.Text.map (\_ -> ' ')++censorSrc :: Src -> Src+censorSrc (Src { srcText = oldText, .. }) = Src { srcText = newText, .. }+ where+ newText = censorText oldText++{-| Convenience utility for converting `Either`-based exceptions to `IO`-based+ exceptions+-}+throws :: (Exception e, MonadIO io) => Either e a -> io a+throws (Left e) = liftIO (Control.Exception.throwIO e)+throws (Right r) = return r+{-# INLINABLE throws #-}++{- $setup+>>> import qualified Codec.Serialise+>>> import qualified Dhall.Binary+>>> import Data.SpecialValues+>>> import Test.QuickCheck (Arbitrary(..), oneof, elements)+>>> :{+ instance Arbitrary DhallDouble where+ arbitrary = fmap DhallDouble (oneof [ arbitrary, elements specialValues ])+:}+-}
@@ -1,11 +0,0 @@-module Dhall.Core where--data Const--data Var--data Expr s a--data Import--denote :: Expr s a -> Expr t a
@@ -0,0 +1,547 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-}++{-| Newtypes for writing customizable 'FromDhall' and 'ToDhall' instances+ through the DerivingVia strategy.++ Inspired by Matt Parson's blog post+ [Mirror Mirror: Reflection and Encoding Via](https://www.parsonsmatt.org/2020/02/04/mirror_mirror.html),+ but applied to Dhall instead of JSON.++ This module is intended to be used with+ [DerivingVia](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-DerivingVia)+ so it's only available for GHC >= v8.6.1.++ Check the section /Letting DerivingVia do the work/ if you want to see this module in action. (Click "Dhall.Deriving#derivingVia" to jump there)++-}++module Dhall.Deriving+ (+ -- * Introduction+ -- $introduction++ -- * Writing FromDhall instances by hand+ -- $instancesByHand++ -- * Letting DerivingVia do the work+ -- $derivingVia++ -- * Behind the scenes of Codec+ -- $behindTheScenes++ -- * DerivingVia newtype+ Codec (..)++ -- * Type-level functions on InterpretOptions+ , ModifyOptions (..)+ , Field+ , Constructor+ , SetSingletonConstructors++ -- * Type-level functions on Text+ , TextFunction (..)+ , DropPrefix+ , TitleCase+ , CamelCase+ , PascalCase+ , SnakeCase+ , SpinalCase+ , TrainCase++ -- * Type-level versions of SingletonConstructors+ , ToSingletonConstructors(..)+ , Bare+ , Wrapped+ , Smart++ -- * Identity and Composition for ModifyOptions and TextFunction+ , AsIs+ , type (<<<)++ -- * Helper function on Text+ , dropPrefix++ -- * InterpretOptions setters+ , addFieldModifier+ , addConstructorModifier+ , setSingletonConstructors++ ) where++import Data.Proxy (Proxy (..))+import Dhall+import GHC.Generics (Generic (Rep))+import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)++import qualified Data.Text as Text+import qualified Data.Text.Manipulate as Case++-- | Intended for use on @deriving via@ clauses for types with a+-- 'Generic' instance. The @tag@ argument is used to construct an+-- 'InterpretOptions' value which is used as the first argument+-- to 'genericAutoWith'.+newtype Codec tag a = Codec { unCodec :: a }++instance (Generic a, GenericFromDhall a (Rep a), ModifyOptions tag) => FromDhall (Codec tag a) where+ autoWith _ = Codec <$> genericAutoWith (modifyOptions @tag defaultInterpretOptions)++instance (Generic a, GenericToDhall (Rep a), ModifyOptions tag) => ToDhall (Codec tag a) where+ injectWith _ = unCodec >$< genericToDhallWith (modifyOptions @tag defaultInterpretOptions)++-- | Convert a type into a @InterpretOptions -> InterpretOptions@ function+class ModifyOptions a where+ modifyOptions :: InterpretOptions -> InterpretOptions+++-- | The identity for functions on 'InterpretOptions' and on @Text@.+-- Useful for deriving @FromDhall@ and @ToDhall@ with the default options.+type AsIs = ()++instance ModifyOptions AsIs where+ modifyOptions = id++instance TextFunction AsIs where+ textFunction = id+++-- | Composition for functions on 'InterpretOptions' and on @Text@.+-- We use @<<<@ since @.@ isn't a valid type operator yet+-- (it will be valid starting from ghc-8.8.1)+data a <<< b+infixr 1 <<<++instance (ModifyOptions a, ModifyOptions b) => ModifyOptions (a <<< b) where+ modifyOptions = modifyOptions @a . modifyOptions @b++instance (TextFunction a, TextFunction b) => TextFunction (a <<< b) where+ textFunction = textFunction @a . textFunction @b+++-- | @Field t@ post-composes the @fieldModifier@ from @options@ with the+-- value-level version of @t@, obtained with @TextFunction@+data Field a+instance TextFunction a => ModifyOptions (Field a) where+ modifyOptions = addFieldModifier (textFunction @a)++-- | @Constructor t@ post-composes the @constructorModifier@ from @options@+-- with the value-level version of @t@, obtained with @TextFunction@+data Constructor a+instance TextFunction a => ModifyOptions (Constructor a) where+ modifyOptions = addConstructorModifier (textFunction @a)+++-- * Text Functions++-- | Convert a type into a @Text -> Text@ function+class TextFunction a where+ textFunction :: Text -> Text++-- | @DropPrefix prefix@ corresponds to the value level+-- function @'dropPrefix' prefix@+data DropPrefix (s :: Symbol)+instance KnownSymbol s => TextFunction (DropPrefix s) where+ textFunction = dropPrefix (Text.pack (symbolVal @s Proxy))++-- | Convert casing to @Title Cased Phrase@+data TitleCase+instance TextFunction TitleCase where+ textFunction = Case.toTitle++-- | Convert casing to @camelCasedPhrase@+data CamelCase+instance TextFunction CamelCase where+ textFunction = Case.toCamel++-- | Convert casing to @PascalCasedPhrase@+data PascalCase+instance TextFunction PascalCase where+ textFunction = Case.toPascal++-- | Convert casing to @snake_cased_phrase@+data SnakeCase+instance TextFunction SnakeCase where+ textFunction = Case.toSnake++-- | Convert casing to @spinal-cased-phrase@+data SpinalCase+instance TextFunction SpinalCase where+ textFunction = Case.toSpinal++-- | Convert casing to @Train-Cased-Phrase@+data TrainCase+instance TextFunction TrainCase where+ textFunction = Case.toTrain+++-- | @SetSingletonConstructors t@ replaces the @singletonConstructors@+-- from @options@ with the value-level version of @t@.+data SetSingletonConstructors a+instance ToSingletonConstructors a => ModifyOptions (SetSingletonConstructors a) where+ modifyOptions = setSingletonConstructors (asSingletonConstructors @a)++-- | Convert a type of kind @SingletonConstructors@+-- into a value of type @SingletonConstructors@+class ToSingletonConstructors (a :: SingletonConstructors) where+ asSingletonConstructors :: SingletonConstructors++-- | Type-level version of 'Dhall.Bare'.+-- Never wrap the field of a singleton constructor in a record+type Bare = 'Bare+instance ToSingletonConstructors Bare where+ asSingletonConstructors = Bare++-- | Type-level version of 'Dhall.Wrapped'+-- Always wrap the field of a singleton constructor in a record+type Wrapped = 'Wrapped+instance ToSingletonConstructors Wrapped where+ asSingletonConstructors = Wrapped++-- | Type-level version of 'Dhall.Smart'+-- Wrap the field of a singleton constructor in a record+-- only if the field is named+type Smart = 'Smart+instance ToSingletonConstructors Smart where+ asSingletonConstructors = Smart+++-- * Text helper++-- | @dropPrefix prefix text@ returns the suffix of @text@ if its prefix+-- matches @prefix@, or the entire @text@ otherwise+dropPrefix :: Text -> (Text -> Text)+dropPrefix prefix text = case Text.stripPrefix prefix text of+ Nothing -> text+ Just e -> e++-- * InterpretOptions setters++-- | @addFieldModifier f options@ post-composes the @fieldModifier@+-- from @options@ with @f@.+addFieldModifier :: (Text -> Text) -> InterpretOptions -> InterpretOptions+addFieldModifier f options = options+ { fieldModifier = f . fieldModifier options }++-- | @addConstructorModifier f options@ post-composes the @constructorModifier@+-- from @options@ with @f@.+addConstructorModifier :: (Text -> Text) -> InterpretOptions -> InterpretOptions+addConstructorModifier f options = options+ { constructorModifier = f . constructorModifier options }++-- | @setSingletonConstructors v options@ replaces the @singletonConstructors@+-- from @options@ with @v@.+setSingletonConstructors :: SingletonConstructors -> InterpretOptions -> InterpretOptions+setSingletonConstructors v options = options+ { singletonConstructors = v }++{- $introduction++Let's take the following Haskell data types:++>>> :set -XDerivingStrategies++>>> :{+newtype Name = Name { getName :: Text }+ deriving stock (Show)+:}++>>> :{+data Font = Arial | ComicSans | Helvetica | TimesNewRoman+ deriving stock (Show)+:}++>>> :{+data Person = Person+ { personName :: Name+ , personFavoriteFont :: Font+ }+ deriving stock (Show)+:}++And assume we want to read the following Dhall file as a @Person@:++@+-- ./simon.dhall+let Name = Text+let Font = \< Arial | `Comic Sans` | Helvetica | `Times New Roman` \>+let Person = { name : Name, favoriteFont : Font }+in { name = \"Simon\", favoriteFont = Font.`Comic Sans` } : Person+@++Usually, you would build a 'Decoder' by hand, like this++>>> :{+font :: Decoder Font+font =+ union+ ( (Arial <$ constructor "Arial" unit)+ <> (ComicSans <$ constructor "Comic Sans" unit)+ <> (Helvetica <$ constructor "Helvetica" unit)+ <> (TimesNewRoman <$ constructor "Times New Roman" unit)+ )+:}++>>> :{+name :: Decoder Name+name = Name <$> strictText+:}++>>> :{+person :: Decoder Person+person =+ record+ ( Person <$> field "name" name+ <*> field "favoriteFont" font+ )+:}++and then you use it like this++>>> input person "./simon.dhall"+Person {personName = Name {getName = "Simon"}, personFavoriteFont = ComicSans}++So, it works! However, this is quite mechanic, and the compiler has pretty+much all the information it needs to do it for you. Besides, you'd like to+provide an instance of 'FromDhall' so you can use the polymorphic 'Decoder'+'auto' instead of explicitly calling @person@.+-}++{- $instancesByHand+"Aha!," you think, "I'll write an empty @instance 'FromDhall' Person@".+That in turn requires you to add two other instances for @Font@ and for @Name@,+plus 'Generic' instances for each of those, but that's okay.++>>> :set -XStandaloneDeriving+>>> :set -XDeriveGeneric++>>> :{+deriving stock instance Generic Name+deriving stock instance Generic Font+deriving stock instance Generic Person+:}++>>> :{+instance FromDhall Name+instance FromDhall Font+instance FromDhall Person+:}++However, when you try to read the same file with 'auto', you get this:++>>> input auto "./simon.dhall" :: IO Person+*** Exception:+...Error...: Expression doesn't match annotation+...+{ - personFavoriteFont : …+, - personName : …+, + favoriteFont : …+, + name : …+}+...+1│ ./simon.dhall : { personName : { getName : Text }+2│ , personFavoriteFont : < Arial | ComicSans | Helvetica | TimesNewRoman >+3│ }+...++What happened? The field names don't quite match, since we're using prefixed+field names in Haskell but no prefixes in Dhall. "Okay," you think,+"I can write a custom instance which builds on 'Generic' thanks to+'genericAutoWith', I only need to supply a function to drop the prefixes+and @camelCase@ the rest". So, using 'Data.Text.Manipulate.toCamel':++>>> import Data.Text.Manipulate (toCamel)+>>> import qualified Data.Text as Text+>>> :{+instance FromDhall Person where+ autoWith _ =+ genericAutoWith defaultInterpretOptions+ { fieldModifier = toCamel . Text.drop (Text.length "person") }+:}++Let's try to read that again:++>>> input auto "./simon.dhall":: IO Person+*** Exception:+...Error...: Expression doesn't match annotation+...+{ favoriteFont : < - ComicSans : …+ | - TimesNewRoman : …+ | + `Comic Sans` : …+ | + `Times New Roman` : …+ | …+ >+, name : - { … : … } (a record type)+ + Text+}+...+1│ ./simon.dhall : { name : { getName : Text }+2│ , favoriteFont : < Arial | ComicSans | Helvetica | TimesNewRoman >+3│ }+...++Okay, we're almost there. We have two things to solve now.+First, the @Font@ constructors are @PascalCased@ in Haskell,+but @Title Cased@ in Dhall. We can communicate this to our+'FromDhall' instance using 'Data.Text.Manipulate.toTitle':++>>> import Data.Text.Manipulate (toTitle)+>>> :{+instance FromDhall Font where+ autoWith _ =+ genericAutoWith defaultInterpretOptions+ { constructorModifier = toTitle }+:}++Second, we defined the @Name@ type in Haskell as a newtype over @Text@, with a+@getName@ field for unwrapping. In Dhall, however, @Name@ is a synonym of+'Data.Text.Text', which is why 'Dhall.input' above was expecting a record.+The 'Dhall.Bare' option for 'singletonConstructors' is a perfect fit here:+it translates Haskell singleton constructors into the Dhall version of the+nested type, without wrapping it into a record.+We can then tweak our 'FromDhall' instance like this:++>>> :{+instance FromDhall Name where+ autoWith _ =+ genericAutoWith defaultInterpretOptions+ { singletonConstructors = Bare }+:}++Since we're running this interactively, we also need to update the+instance for @Person@, but it's the same as before.++>>> :{+instance FromDhall Person where+ autoWith _ =+ genericAutoWith defaultInterpretOptions+ { fieldModifier = toCamel . Text.drop (Text.length "person") }+:}++Now, for the moment of truth:++>>> input auto "./simon.dhall":: IO Person+Person {personName = Name {getName = "Simon"}, personFavoriteFont = ComicSans}++That took a bit more work than we wanted, though, and a lot of it was just+boilerplate for defining the instances through `genericAutoWith`, tweaking+a single parameter at a time. Even worse, if we also wanted to provide+'ToDhall' instances we would need to keep the options in sync between both+instances, since otherwise the values wouldn't be able to round-trip from+Dhall to Dhall through Haskell.++-}++{- $derivingVia+ #derivingVia#++Starting with this dhall file:++@+-- ./simon.dhall+let Name = Text+let Font = \< Arial | `Comic Sans` | Helvetica | `Times New Roman` \>+let Person = { name : Name, favoriteFont : Font }+in { name = \"Simon\", favoriteFont = Font.`Comic Sans` } : Person+@++We can define the equivalent Haskell types as follows. Note that we+derive the 'FromDhall' and 'ToDhall' instances @via 'Codec' tag TheType@,+using a different @tag@ depending on the transformations we need to apply to+the Haskell type to get the Dhall equivalent:++>>> :set -XDataKinds+>>> :set -XDeriveGeneric+>>> :set -XDerivingVia+>>> :set -XTypeOperators++>>> :{+newtype Name = Name { getName :: Text }+ deriving stock (Generic, Show)+ deriving (FromDhall, ToDhall)+ via Codec (SetSingletonConstructors Bare) Name+:}++>>> :{+data Font = Arial | ComicSans | Helvetica | TimesNewRoman+ deriving stock (Generic, Show)+ deriving (FromDhall, ToDhall)+ via Codec (Constructor TitleCase) Font+:}++>>> :{+data Person = Person+ { personName :: Name+ , personFavoriteFont :: Font+ }+ deriving stock (Generic, Show)+ deriving (FromDhall, ToDhall)+ via Codec (Field (CamelCase <<< DropPrefix "person")) Person+:}++we can then read the file using 'auto':++>>> simon <- input auto "./simon.dhall":: IO Person+>>> print simon+Person {personName = Name {getName = "Simon"}, personFavoriteFont = ComicSans}++And using 'inject' we can get @simon@ back as a Dhall value:++>>> import qualified Data.Text.IO as Text+>>> import Dhall.Core (pretty)+>>> Text.putStrLn . pretty . embed inject $ simon+{ name = "Simon"+, favoriteFont =+ < Arial | `Comic Sans` | Helvetica | `Times New Roman` >.`Comic Sans`+}++-}++{- $behindTheScenes++@'Codec' tag a@ is really just a newtype over @a@, equipped with a+phantom @tag@. The 'FromDhall' instance for 'Codec' uses the generic+representation of @a@, together with the 'InterpretOptions' defined by @tag@ as+a series of modifications to be applied on 'defaultInterpretOptions'.++For the default behavior, using 'AsIs' (a synonym for @()@) as the @tag@+leaves the interpret options alone, so it's equivalent to the empty instance+we first tried to use.++@'Field' a@ and @'Constructor' a@ can be used to modify, respectively, the+'fieldModifier' and 'constructorModifier' options of 'InterpretOptions', by+post-composing the modifier with @'textFunction' \@a@, that is, the value-level+equivalent of @a@, obtained through the 'TextFunction' class.++In the case of @Person@, we used++@+ Codec (Field (CamelCase <<< DropPrefix "person")) Person+@++which means that the @Text -> Text@ version of++@+ CamelCase <<< DropPrefix "person"+@++was used to modify the @fieldModifier@ option.++In the value level, this translates to composing ('<<<')+'Data.Text.Manipulate.toCamel' ('CamelCase') with @'dropPrefix' "person"@+(@'DropPrefix' "person"@).++Finally, @'SetSingletonConstructors' a@ can be used to set the+'singletonConstructors' option of 'InterpretOptions', by replacing the option+with the value-level equivalent of @a@.+-}++{- $setup+>>> :set -XOverloadedStrings+-}
@@ -1,6 +1,7 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-} {-| This module provides functionality for concisely displaying the difference between two expressions@@ -12,44 +13,55 @@ module Dhall.Diff ( -- * Diff Diff (..)- , diffExpression , diffNormalized- , Dhall.Diff.diff+ , diff ) where -import Data.Foldable (fold, toList)-import Data.Function (on)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Monoid (Any(..))-import Data.Semigroup-import Data.Sequence (Seq)-import Data.String (IsString(..))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty)-import Dhall.Core (Binding(..), Chunks (..), Const(..), Expr(..), Var(..))-import Dhall.Binary (ToTerm)-import Dhall.Map (Map)-import Dhall.Set (Set)+import Data.ByteString (ByteString)+import Data.Foldable (fold, toList)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Monoid (Any (..))+import Data.Sequence (Seq)+import Data.String (IsString (..))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Map (Map) import Dhall.Pretty.Internal (Ann)-import Numeric.Natural (Natural)+import Dhall.Syntax+ ( Binding (..)+ , Chunks (..)+ , Const (..)+ , DhallDouble (..)+ , Expr (..)+ , FunctionBinding (..)+ , RecordField (..)+ , Var (..)+ , WithComponent (..)+ )+import Numeric.Natural (Natural)+import Prettyprinter (Doc, Pretty) -import qualified Data.Algorithm.Diff as Algo.Diff+import qualified Data.Algorithm.Diff as Algo.Diff import qualified Data.List.NonEmpty import qualified Data.Set import qualified Data.Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Dhall.Core+import qualified Data.Time as Time import qualified Dhall.Map-import qualified Dhall.Set-import qualified Dhall.Pretty.Internal as Internal+import qualified Dhall.Normalize as Normalize+import qualified Dhall.Pretty.Internal as Internal+import qualified Dhall.Syntax as Syntax+import qualified Prettyprinter as Pretty +{-| This type is a `Doc` enriched with a `same` flag to efficiently track if+ any difference was detected+-} data Diff = Diff { same :: Bool , doc :: Doc Ann } -instance Data.Semigroup.Semigroup Diff where+instance Semigroup Diff where Diff sameL docL <> Diff sameR docR = Diff (sameL && sameR) (docL <> docR) instance Monoid (Diff) where@@ -59,10 +71,6 @@ doc = mempty -#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)-#endif- instance IsString (Diff) where fromString string = Diff {..} where@@ -117,8 +125,8 @@ equals :: Diff equals = token Internal.equals -forall :: Diff-forall = token (Internal.forall Internal.Unicode)+forall_ :: Diff+forall_ = token (Internal.forall_ Internal.Unicode) lambda :: Diff lambda = token (Internal.lambda Internal.Unicode)@@ -154,17 +162,11 @@ rparen = token Internal.rparen -- | Render the difference between the normal form of two expressions-diffNormalized :: (Eq a, Pretty a, ToTerm a) => Expr s a -> Expr s a -> Doc Ann+diffNormalized :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff diffNormalized l0 r0 = Dhall.Diff.diff l1 r1 where- l1 = Dhall.Core.alphaNormalize (Dhall.Core.normalize l0)- r1 = Dhall.Core.alphaNormalize (Dhall.Core.normalize r0)---- | Render the difference between two expressions-diff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann-diff l0 r0 = doc- where- Diff {..} = diffExpression l0 r0+ l1 = Normalize.alphaNormalize (Normalize.normalize l0)+ r1 = Normalize.alphaNormalize (Normalize.normalize r0) diffPrimitive :: Eq a => (a -> Diff) -> a -> a -> Diff diffPrimitive f l r@@ -174,27 +176,44 @@ diffLabel :: Text -> Text -> Diff diffLabel = diffPrimitive (token . Internal.prettyLabel) -diffLabels :: Set Text -> Set Text -> Diff+diffLabels :: [Text] -> [Text] -> Diff diffLabels ksL ksR = braced (diffFieldNames <> (if anyEqual then [ ignore ] else [])) where- extraL = Dhall.Set.difference ksL ksR- extraR = Dhall.Set.difference ksR ksL+ setL = Data.Set.fromList ksL+ setR = Data.Set.fromList ksR + extraL = Data.Set.difference setL setR+ extraR = Data.Set.difference setR setL+ diffFieldNames = foldMap (adapt minus) extraL <> foldMap (adapt plus) extraR where adapt sign key = [ sign (token (Internal.prettyLabel key)) ] - anyEqual = not (Data.Set.null (Data.Set.intersection- (Dhall.Set.toSet ksL)- (Dhall.Set.toSet ksR)))+ anyEqual = not (Data.Set.null (Data.Set.intersection setL setR)) diffNatural :: Natural -> Natural -> Diff diffNatural = diffPrimitive (token . Internal.prettyNatural) -diffDouble :: Double -> Double -> Diff-diffDouble = diffPrimitive (token . Internal.prettyDouble)+diffDouble :: DhallDouble -> DhallDouble -> Diff+diffDouble = diffPrimitive (token . Internal.prettyDouble . getDhallDouble) +diffDateLiteral :: Time.Day -> Time.Day -> Diff+diffDateLiteral =+ diffPrimitive (token . Internal.prettyExpr @(Expr Void Void) . DateLiteral)++diffTimeLiteral :: Time.TimeOfDay -> Word -> Time.TimeOfDay -> Word -> Diff+diffTimeLiteral tL pL tR pR =+ diffPrimitive+ (token . Internal.prettyExpr @(Expr Void Void) . uncurry TimeLiteral)+ (tL, pL)+ (tR, pR)++diffTimeZoneLiteral :: Time.TimeZone -> Time.TimeZone -> Diff+diffTimeZoneLiteral =+ diffPrimitive+ (token . Internal.prettyExpr @(Expr Void Void) . TimeZoneLiteral)+ diffConst :: Const -> Const -> Diff diffConst = diffPrimitive (token . Internal.prettyConst) @@ -207,12 +226,16 @@ diffInteger :: Integer -> Integer -> Diff diffInteger = diffPrimitive (token . Internal.prettyNumber) +diffInt :: Int -> Int -> Diff+diffInt = diffPrimitive (token . Internal.prettyInt)+ diffVar :: Var -> Var -> Diff-diffVar (V xL nL) (V xR nR) = format mempty label <> "@" <> natural+diffVar (V xL nL) (V xR nR) =+ format mempty label <> if same natural then mempty else "@" <> natural where label = diffLabel xL xR - natural = diffInteger nL nR+ natural = diffInt nL nR diffPretty :: (Eq a, Pretty a) => a -> a -> Diff diffPretty = diffPrimitive (token . Pretty.pretty)@@ -253,10 +276,12 @@ diffKeyVals :: (Eq a, Pretty a) => Diff- -> Map Text (Expr s a)- -> Map Text (Expr s a)+ -> Map Text (RecordField Void a)+ -> Map Text (RecordField Void a) -> [Diff]-diffKeyVals assign = diffKeysWith assign diffExpression+diffKeyVals assign kvsL kvsR = diffKeysWith assign diff+ (recordFieldValue <$> kvsL)+ (recordFieldValue <$> kvsR) diffKeysWith :: Diff@@ -267,8 +292,8 @@ diffKeysWith assign diffVals kvsL kvsR = diffFieldNames <> diffFieldValues <> (if anyEqual then [ ignore ] else []) where- ksL = Data.Set.fromList (Dhall.Map.keys kvsL)- ksR = Data.Set.fromList (Dhall.Map.keys kvsR)+ ksL = Dhall.Map.keysSet kvsL+ ksR = Dhall.Map.keysSet kvsR extraL = Data.Set.difference ksL ksR extraR = Data.Set.difference ksR ksL@@ -309,15 +334,8 @@ bracketed = enclosed (lbracket <> " ") (comma <> " ") rbracket diffText :: Text -> Text -> Diff-diffText l r- | null parts = "\"\""- | allDifferent parts = difference textSkeleton textSkeleton- | allSame parts = textSkeleton- | otherwise = "\"" <> foldMap prettyPart parts <> "\""+diffText l r = "\"" <> foldMap prettyPart parts <> "\"" where- allDifferent = not . any isBoth- allSame = all isBoth- -- TODO: check for color support from the TTY colorDiff colorCode chars = "\ESC["@@ -347,7 +365,7 @@ diffChunks :: (Eq a, Pretty a)- => Chunks s a -> Chunks s a -> Diff+ => Chunks Void a -> Chunks Void a -> Diff diffChunks cL cR | null chunks = "\"\"" | [c] <- chunks = c@@ -358,30 +376,38 @@ diffTextSkeleton = difference textSkeleton textSkeleton - chunks = zipWith chunkDiff (toEitherList cL) (toEitherList cR) + chunks = zipWith chunkDiff (toEitherList cL) (toEitherList cR) chunkDiff a b = case (a, b) of (Left x, Left y ) -> diffText x y- (Right x, Right y) -> diffExpression x y+ (Right x, Right y) -> diff x y _ -> diffTextSkeleton +diffBytes :: ByteString -> ByteString -> Diff+diffBytes l r =+ "0x" <> diffText (Internal.prettyBase16 l) (Internal.prettyBase16 r)+ diffList :: (Eq a, Pretty a)- => Seq (Expr s a) -> Seq (Expr s a) -> Diff-diffList l r- | allDifferent parts = difference listSkeleton listSkeleton- | otherwise = bracketed (foldMap diffPart parts)+ => Seq (Expr Void a) -> Seq (Expr Void a) -> Diff+diffList l r = bracketed (loop parts₀) where- allDifferent = any (not . isBoth)- -- Sections of the list that are only in left, only in right, or in both- parts =- Algo.Diff.getGroupedDiffBy ((same .) . diffExpression) (toList l) (toList r)+ parts₀ = Algo.Diff.getGroupedDiffBy equal (toList l) (toList r) + equal a b = same (diff a b)+ -- Render each element of a list using an extra rendering function f prettyElems f = map (f . token . Internal.prettyExpr) + loop [] =+ mempty+ loop (Algo.Diff.First as : Algo.Diff.Second bs : parts)+ | length as == length bs = zipWith diff as bs <> loop parts+ loop (part : parts) =+ diffPart part <> loop parts+ diffPart part = case part of -- Only present in left@@ -396,58 +422,22 @@ Algo.Diff.Both _ _ -> pure ignore --- Helper function to check when a diff part is present on both sides-isBoth :: Algo.Diff.Diff a -> Bool-isBoth p- | Algo.Diff.Both _ _ <- p = True- | otherwise = False- diffRecord :: (Eq a, Pretty a)- => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff+ => Map Text (RecordField Void a) -> Map Text (RecordField Void a) -> Diff diffRecord kvsL kvsR = braced (diffKeyVals colon kvsL kvsR) diffRecordLit :: (Eq a, Pretty a)- => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff+ => Map Text (RecordField Void a) -> Map Text (RecordField Void a) -> Diff diffRecordLit kvsL kvsR = braced (diffKeyVals equals kvsL kvsR) diffUnion :: (Eq a, Pretty a)- => Map Text (Maybe (Expr s a)) -> Map Text (Maybe (Expr s a)) -> Diff+ => Map Text (Maybe (Expr Void a)) -> Map Text (Maybe (Expr Void a)) -> Diff diffUnion kvsL kvsR = angled (diffKeysWith colon diffVals kvsL kvsR) where- diffVals = diffMaybe (colon <> " ") diffExpression--diffUnionLit- :: (Eq a, Pretty a)- => Text- -> Text- -> Expr s a- -> Expr s a- -> Map Text (Maybe (Expr s a))- -> Map Text (Maybe (Expr s a))- -> Diff-diffUnionLit kL kR vL vR kvsL kvsR =- langle- <> " "- <> format " " (diffLabel kL kR)- <> equals- <> " "- <> format " " (diffExpression vL vR)- <> halfAngled (diffKeysWith colon diffVals kvsL kvsR)- where- diffVals = diffMaybe (colon <> " ") diffExpression-- halfAngled = enclosed (pipe <> " ") (pipe <> " ") rangle--listSkeleton :: Diff-listSkeleton =- lbracket- <> " "- <> ignore- <> " "- <> rbracket+ diffVals = diffMaybe (colon <> " ") diff textSkeleton :: Diff textSkeleton =@@ -469,12 +459,14 @@ <> rarrow <> " " <> ignore+ <> " (a function)" skeleton (Pi {}) = ignore <> " " <> rarrow <> " " <> ignore+ <> " (a function type)" skeleton (App Optional _) = "Optional " <> ignore@@ -545,6 +537,10 @@ <> keyword "else" <> " " <> ignore+skeleton (BytesLit {}) =+ "0x\""+ <> ignore+ <> "\"" skeleton (NaturalPlus {}) = ignore <> " "@@ -565,32 +561,26 @@ <> operator "++" <> " " <> ignore-skeleton (ListLit {}) =- listSkeleton- <> " "- <> colon- <> " "- <> builtin "List"- <> " "- <> ignore+skeleton (ListLit _ elems)+ | null elems =+ lbracket+ <> rbracket+ <> " "+ <> colon+ <> " "+ <> ignore+ | otherwise =+ lbracket+ <> " "+ <> ignore+ <> " "+ <> rbracket skeleton (ListAppend {}) = ignore <> " " <> operator "#" <> " " <> ignore-skeleton (OptionalLit {}) =- lbracket- <> " "- <> ignore- <> " "- <> rbracket- <> " "- <> colon- <> " "- <> builtin "Optional"- <> " "- <> ignore skeleton (Record {}) = lbrace <> " "@@ -601,6 +591,7 @@ <> ignore <> " " <> rbrace+ <> " (a record type)" skeleton (RecordLit {}) = lbrace <> " "@@ -611,6 +602,7 @@ <> ignore <> " " <> rbrace+ <> " (a record)" skeleton (Union {}) = langle <> " "@@ -621,16 +613,7 @@ <> ignore <> " " <> rangle-skeleton (UnionLit {}) =- langle- <> " "- <> ignore- <> " "- <> equals- <> " "- <> ignore- <> " "- <> rangle+ <> " (a union type)" skeleton (Combine {}) = ignore <> " "@@ -649,12 +632,24 @@ <> operator "⫽" <> " " <> ignore+skeleton (RecordCompletion {}) =+ ignore+ <> operator "::"+ <> ignore skeleton (Merge {}) = keyword "merge" <> " " <> ignore <> " " <> ignore+skeleton (ToMap {}) =+ keyword "toMap"+ <> " "+ <> ignore+skeleton (ShowConstructor {}) =+ keyword "showConstructor"+ <> " "+ <> ignore skeleton (Field {}) = ignore <> dot@@ -667,16 +662,25 @@ <> ignore <> " " <> rbrace+skeleton (With {}) =+ ignore+ <> " "+ <> keyword "with"+ <> " "+ <> ignore skeleton x = token (Pretty.pretty x) mismatch :: Pretty a => Expr s a -> Expr s a -> Diff mismatch l r = difference (skeleton l) (skeleton r) -diffExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff-diffExpression l@(Lam {}) r@(Lam {}) =+-- | Render the difference between two expressions+diff :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff+diff l@(Lam {}) r@(Lam {}) = enclosed' " " (rarrow <> " ") (docs l r) where- docs (Lam aL bL cL) (Lam aR bR cR) =+ docs+ (Lam _ (FunctionBinding { functionBindingVariable = aL, functionBindingAnnotation = bL }) cL)+ (Lam _ (FunctionBinding { functionBindingVariable = aR, functionBindingAnnotation = bR }) cR) = Data.List.NonEmpty.cons (align doc) (docs cL cR) where doc = lambda@@ -684,16 +688,16 @@ <> format " " (diffLabel aL aR) <> colon <> " "- <> format mempty (diffExpression bL bR)+ <> format mempty (diff bL bR) <> rparen docs aL aR =- pure (diffExpression aL aR)-diffExpression l@(Lam {}) r =+ pure (diff aL aR)+diff l@(Lam {}) r = mismatch l r-diffExpression l r@(Lam {}) =+diff l r@(Lam {}) = mismatch l r-diffExpression l@(BoolIf {}) r@(BoolIf {}) =+diff l@(BoolIf {}) r@(BoolIf {}) = enclosed' " " (keyword "else" <> " ") (docs l r) where docs (BoolIf aL bL cL) (BoolIf aR bR cR) =@@ -701,98 +705,115 @@ where doc = keyword "if" <> " "- <> format " " (diffExpression aL aR)+ <> format " " (diff aL aR) <> keyword "then" <> " "- <> diffExpression bL bR+ <> diff bL bR docs aL aR =- pure (diffExpression aL aR)-diffExpression l@(BoolIf {}) r =+ pure (diff aL aR)+diff l@(BoolIf {}) r = mismatch l r-diffExpression l r@(BoolIf {}) =+diff l r@(BoolIf {}) = mismatch l r-diffExpression (Let asL bL ) (Let asR bR) =- enclosed' "" (keyword "in" <> " ")- (Data.List.NonEmpty.zipWith docA asL asR <> pure docB)+diff l@(Let {}) r@(Let {}) =+ enclosed' " " (keyword "in" <> " ") (docs l r) where- docA (Binding cL dL eL) (Binding cR dR eR) = align doc+ docs (Let (Binding _ aL _ bL _ cL) dL) (Let (Binding _ aR _ bR _ cR) dR) =+ Data.List.NonEmpty.cons (align doc) (docs dL dR) where+ bL' = fmap snd bL+ bR' = fmap snd bR+ doc = keyword "let" <> " "- <> format " " (diffLabel cL cR)- <> format " " (diffMaybe (colon <> " ") diffExpression dL dR)+ <> format " " (diffLabel aL aR)+ <> format " " (diffMaybe (colon <> " ") diff bL' bR') <> equals <> " "- <> diffExpression eL eR-- docB = diffExpression bL bR-diffExpression l@(Let {}) r =+ <> diff cL cR+ docs aL aR = pure (diff aL aR)+diff l@(Let {}) r = mismatch l r-diffExpression l r@(Let {}) =+diff l r@(Let {}) = mismatch l r-diffExpression l@(Pi {}) r@(Pi {}) =+diff l@(Pi {}) r@(Pi {}) = enclosed' " " (rarrow <> " ") (docs l r) where- docs (Pi aL bL cL) (Pi aR bR cR) =+ docs (Pi _ aL bL cL) (Pi _ aR bR cR) = Data.List.NonEmpty.cons (align doc) (docs cL cR) where doc | same docA && same docB = ignore+ | same docA =+ format mempty docB | otherwise =- forall- <> lparen- <> format " " docA- <> colon- <> " "- <> format mempty docB- <> rparen+ forall_+ <> lparen+ <> format " " docA+ <> colon+ <> " "+ <> format mempty docB+ <> rparen where docA = diffLabel aL aR - docB = diffExpression bL bR+ docB = diff bL bR - docs aL aR = pure (diffExpression aL aR)-diffExpression l@(Pi {}) r =+ docs aL aR = pure (diff aL aR)+diff l@(Pi {}) r = mismatch l r-diffExpression l r@(Pi {}) =+diff l r@(Pi {}) = mismatch l r-diffExpression l r =+diff (Assert aL) (Assert aR) =+ align+ ( " " <> keyword "assert"+ <> hardline <> colon <> " " <> diff aL aR+ )+diff l@(Assert {}) r =+ mismatch l r+diff l r@(Assert {}) =+ mismatch l r+diff l r = diffAnnotatedExpression l r -diffAnnotatedExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffAnnotatedExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffAnnotatedExpression (Merge aL bL cL) (Merge aR bR cR) = align doc where doc = keyword "merge" <> " "- <> format " " (diffImportExpression aL aR)- <> format " " (diffImportExpression bL bR)+ <> format " " (diffWithExpression aL aR)+ <> format " " (diffWithExpression bL bR) <> diffMaybe (colon <> " ") diffApplicationExpression cL cR diffAnnotatedExpression l@(Merge {}) r = mismatch l r diffAnnotatedExpression l r@(Merge {}) = mismatch l r+diffAnnotatedExpression (ToMap aL bL) (ToMap aR bR) = align doc+ where+ doc = keyword "toMap"+ <> " "+ <> format " " (diffWithExpression aL aR)+ <> diffMaybe (colon <> " ") diffApplicationExpression bL bR+diffAnnotatedExpression l@(ToMap {}) r =+ mismatch l r+diffAnnotatedExpression l r@(ToMap {}) =+ mismatch l r+diffAnnotatedExpression (ShowConstructor aL) (ShowConstructor aR) = align doc+ where+ doc = keyword "showConstructor"+ <> " "+ <> format " " (diffWithExpression aL aR)+diffAnnotatedExpression l@(ShowConstructor {}) r =+ mismatch l r+diffAnnotatedExpression l r@(ShowConstructor {}) =+ mismatch l r diffAnnotatedExpression (ListLit aL@(Just _) bL) (ListLit aR bR) = align doc where doc = format " " (diffList bL bR)- <> format " " (diffMaybe (colon <> " ") (diffApplicationExpression `on` App List) aL aR)+ <> format " " (diffMaybe (colon <> " ") diffApplicationExpression aL aR) diffAnnotatedExpression (ListLit aL bL) (ListLit aR@(Just _) bR) = align doc where doc = format " " (diffList bL bR)- <> format " " (diffMaybe (colon <> " ") (diffApplicationExpression `on` App List) aL aR)-diffAnnotatedExpression (OptionalLit aL bL) (OptionalLit aR bR) =- align doc- where- doc = lbracket- <> " "- <> format " " (diffMaybe mempty diffExpression bL bR)- <> rbracket- <> " "- <> colon- <> " "- <> diffApplicationExpression (App Optional aL) (App Optional aR)-diffAnnotatedExpression l@(OptionalLit {}) r =- mismatch l r-diffAnnotatedExpression l r@(OptionalLit {}) =- mismatch l r+ <> format " " (diffMaybe (colon <> " ") diffApplicationExpression aL aR) diffAnnotatedExpression l@(Annot {}) r@(Annot {}) = enclosed' " " (colon <> " ") (docs l r) where@@ -801,7 +822,7 @@ where doc = diffOperatorExpression aL aR docs aL aR =- diffExpression aL aR :| []+ diff aL aR :| [] diffAnnotatedExpression l@(Annot {}) r = mismatch l r diffAnnotatedExpression l r@(Annot {}) =@@ -809,17 +830,47 @@ diffAnnotatedExpression l r = diffOperatorExpression l r -diffOperatorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff-diffOperatorExpression = diffOrExpression+{- Whitespace in diffs of operator expressions: -diffOrExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+All indentation (whether pretty-printing or diffing) is a multiple of two+spaces, so if the operator is one character long (like ?) then the diff pads+the left margin to two space:++ ␣␣e₀+ ?␣e₁++... but if the operator is two characters long (like ||) then the diff pads+the left margin to four spaces:++ ␣␣␣␣e₀+ ||␣␣e₁+-}+diffOperatorExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff+diffOperatorExpression = diffImportAltExpression++diffImportAltExpression :: (Pretty a, Eq a) => Expr Void a -> Expr Void a -> Diff+diffImportAltExpression l@(ImportAlt {}) r@(ImportAlt {}) =+ enclosed' " " (operator "?" <> " ") (docs l r)+ where+ docs (ImportAlt aL bL) (ImportAlt aR bR) =+ Data.List.NonEmpty.cons (diffOrExpression aL aR) (docs bL bR)+ docs aL aR =+ pure (diffOrExpression aL aR)+diffImportAltExpression l@(ImportAlt {}) r =+ mismatch l r+diffImportAltExpression l r@(ImportAlt {}) =+ mismatch l r+diffImportAltExpression l r =+ diffOrExpression l r++diffOrExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffOrExpression l@(BoolOr {}) r@(BoolOr {}) = enclosed' " " (operator "||" <> " ") (docs l r) where docs (BoolOr aL bL) (BoolOr aR bR) =- Data.List.NonEmpty.cons (diffTextAppendExpression aL aR) (docs bL bR)+ Data.List.NonEmpty.cons (diffPlusExpression aL aR) (docs bL bR) docs aL aR =- pure (diffTextAppendExpression aL aR)+ pure (diffPlusExpression aL aR) diffOrExpression l@(BoolOr {}) r = mismatch l r diffOrExpression l r@(BoolOr {}) =@@ -827,14 +878,14 @@ diffOrExpression l r = diffPlusExpression l r -diffPlusExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPlusExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffPlusExpression l@(NaturalPlus {}) r@(NaturalPlus {}) = enclosed' " " (operator "+" <> " ") (docs l r) where docs (NaturalPlus aL bL) (NaturalPlus aR bR) =- Data.List.NonEmpty.cons (diffListAppendExpression aL aR) (docs bL bR)+ Data.List.NonEmpty.cons (diffTextAppendExpression aL aR) (docs bL bR) docs aL aR =- pure (diffListAppendExpression aL aR)+ pure (diffTextAppendExpression aL aR) diffPlusExpression l@(NaturalPlus {}) r = mismatch l r diffPlusExpression l r@(NaturalPlus {}) =@@ -842,14 +893,14 @@ diffPlusExpression l r = diffTextAppendExpression l r -diffTextAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffTextAppendExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffTextAppendExpression l@(TextAppend {}) r@(TextAppend {}) = enclosed' " " (operator "++" <> " ") (docs l r) where docs (TextAppend aL bL) (TextAppend aR bR) =- Data.List.NonEmpty.cons (diffPlusExpression aL aR) (docs bL bR)+ Data.List.NonEmpty.cons (diffListAppendExpression aL aR) (docs bL bR) docs aL aR =- pure (diffPlusExpression aL aR)+ pure (diffListAppendExpression aL aR) diffTextAppendExpression l@(TextAppend {}) r = mismatch l r diffTextAppendExpression l r@(TextAppend {}) =@@ -857,7 +908,7 @@ diffTextAppendExpression l r = diffListAppendExpression l r -diffListAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffListAppendExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffListAppendExpression l@(ListAppend {}) r@(ListAppend {}) = enclosed' " " (operator "#" <> " ") (docs l r) where@@ -872,7 +923,7 @@ diffListAppendExpression l r = diffAndExpression l r -diffAndExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffAndExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffAndExpression l@(BoolAnd {}) r@(BoolAnd {}) = enclosed' " " (operator "&&" <> " ") (docs l r) where@@ -887,11 +938,11 @@ diffAndExpression l r = diffCombineExpression l r -diffCombineExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffCombineExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffCombineExpression l@(Combine {}) r@(Combine {}) = enclosed' " " (operator "∧" <> " ") (docs l r) where- docs (Combine aL bL) (Combine aR bR) =+ docs (Combine _ _ aL bL) (Combine _ _ aR bR) = Data.List.NonEmpty.cons (diffPreferExpression aL aR) (docs bL bR) docs aL aR = pure (diffPreferExpression aL aR)@@ -902,11 +953,11 @@ diffCombineExpression l r = diffPreferExpression l r -diffPreferExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPreferExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffPreferExpression l@(Prefer {}) r@(Prefer {}) = enclosed' " " (operator "⫽" <> " ") (docs l r) where- docs (Prefer aL bL) (Prefer aR bR) =+ docs (Prefer _ _ aL bL) (Prefer _ _ aR bR) = Data.List.NonEmpty.cons (diffCombineTypesExpression aL aR) (docs bL bR) docs aL aR = pure (diffCombineTypesExpression aL aR)@@ -917,11 +968,11 @@ diffPreferExpression l r = diffCombineTypesExpression l r -diffCombineTypesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffCombineTypesExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffCombineTypesExpression l@(CombineTypes {}) r@(CombineTypes {}) = enclosed' " " (operator "*" <> " ") (docs l r) where- docs (CombineTypes aL bL) (CombineTypes aR bR) =+ docs (CombineTypes _ aL bL) (CombineTypes _ aR bR) = Data.List.NonEmpty.cons (diffTimesExpression aL aR) (docs bL bR) docs aL aR = pure (diffTimesExpression aL aR)@@ -932,7 +983,7 @@ diffCombineTypesExpression l r = diffTimesExpression l r -diffTimesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffTimesExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffTimesExpression l@(NaturalTimes {}) r@(NaturalTimes {}) = enclosed' " " (operator "*" <> " ") (docs l r) where@@ -947,7 +998,7 @@ diffTimesExpression l r = diffEqualExpression l r -diffEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffEqualExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffEqualExpression l@(BoolEQ {}) r@(BoolEQ {}) = enclosed' " " (operator "==" <> " ") (docs l r) where@@ -962,49 +1013,99 @@ diffEqualExpression l r = diffNotEqualExpression l r -diffNotEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffNotEqualExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffNotEqualExpression l@(BoolNE {}) r@(BoolNE {}) = enclosed' " " (operator "!=" <> " ") (docs l r) where docs (BoolNE aL bL) (BoolNE aR bR) =- Data.List.NonEmpty.cons (diffApplicationExpression aL aR) (docs bL bR)+ Data.List.NonEmpty.cons (diffEquivalentExpression aL aR) (docs bL bR) docs aL aR =- pure (diffApplicationExpression aL aR)+ pure (diffEquivalentExpression aL aR) diffNotEqualExpression l@(BoolNE {}) r = mismatch l r diffNotEqualExpression l r@(BoolNE {}) = mismatch l r diffNotEqualExpression l r =+ diffEquivalentExpression l r++diffEquivalentExpression+ :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff+diffEquivalentExpression l@(Equivalent {}) r@(Equivalent {}) =+ enclosed' " " (operator "≡" <> " ") (docs l r)+ where+ docs (Equivalent _ aL bL) (Equivalent _ aR bR) =+ Data.List.NonEmpty.cons (diffApplicationExpression aL aR) (docs bL bR)+ docs aL aR =+ pure (diffApplicationExpression aL aR)+diffEquivalentExpression l@(Equivalent {}) r =+ mismatch l r+diffEquivalentExpression l r@(Equivalent {}) =+ mismatch l r+diffEquivalentExpression l r = diffApplicationExpression l r -diffApplicationExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffApplicationExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffApplicationExpression l@(App {}) r@(App {}) = enclosed' mempty mempty (Data.List.NonEmpty.reverse (docs l r)) where docs (App aL bL) (App aR bR) =- Data.List.NonEmpty.cons (diffImportExpression bL bR) (docs aL aR)+ Data.List.NonEmpty.cons (diffWithExpression bL bR) (docs aL aR) docs (Some aL) (Some aR) =- diffImportExpression aL aR :| [ builtin "Some" ]+ diffWithExpression aL aR :| [ builtin "Some" ] docs aL aR@(Some {}) = pure (mismatch aL aR) docs aL@(Some {}) aR = pure (mismatch aL aR) docs aL aR =- pure (diffImportExpression aL aR)+ pure (diffWithExpression aL aR) diffApplicationExpression l@(App {}) r = mismatch l r diffApplicationExpression l r@(App {}) = mismatch l r diffApplicationExpression (Some l) (Some r) =- enclosed' mempty mempty (builtin "Some" :| [ diffImportExpression l r ])+ enclosed' mempty mempty (builtin "Some" :| [ diffWithExpression l r ]) diffApplicationExpression l@(Some {}) r = mismatch l r diffApplicationExpression l r@(Some {}) = mismatch l r diffApplicationExpression l r =+ diffWithExpression l r++diffWithExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff+diffWithExpression (With eL ksL vL) (With eR ksR vR) =+ align+ ( format " " (diffImportExpression eL eR)+ <> "with "+ <> align+ ( format " " (diffPath (fmap toText ksL) (fmap toText ksR))+ <> "= "+ <> diffOperatorExpression vL vR+ )+ )+ where+ toText WithQuestion = "?"+ toText (WithLabel k ) = k++ diffPath (kL :| []) (kR :| []) =+ diffLabel kL kR+ diffPath (kL₀ :| kL₁ : ksL') (kR₀ :| kR₁ : ksR') =+ format "" (diffLabel kL₀ kR₀)+ <> dot+ <> diffPath (kL₁ :| ksL') (kR₁ :| ksR')+ diffPath (kL :| []) (kR₀ :| kR₁ : ksR') =+ format "" (diffLabel kL kR₀)+ <> plus (foldMap (\k -> dot <> token (Internal.prettyLabel k)) (kR₁ :| ksR'))+ diffPath (kL₀ :| kL₁ : ksL') (kR :| []) =+ format "" (diffLabel kL₀ kR)+ <> minus (foldMap (\k -> dot <> token (Internal.prettyLabel k)) (kL₁ :| ksL'))+diffWithExpression l r@With{} =+ mismatch l r+diffWithExpression l@With{} r =+ mismatch l r+diffWithExpression l r = diffImportExpression l r -diffImportExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffImportExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffImportExpression (Embed l) (Embed r) = diffPretty l r diffImportExpression l@(Embed {}) r =@@ -1012,18 +1113,28 @@ diffImportExpression l r@(Embed {}) = mismatch l r diffImportExpression l r =+ diffRecordCompletionExpression l r++diffRecordCompletionExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff+diffRecordCompletionExpression (RecordCompletion aL bL) (RecordCompletion aR bR) =+ diffSelectorExpression aL aR <> "::" <> diffSelectorExpression bL bR+diffRecordCompletionExpression l@(RecordCompletion {}) r =+ mismatch l r+diffRecordCompletionExpression l r@(RecordCompletion {}) =+ mismatch l r+diffRecordCompletionExpression l r = diffSelectorExpression l r -diffSelectorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffSelectorExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffSelectorExpression l@(Field {}) r@(Field {}) = enclosed' " " (dot <> " ") (Data.List.NonEmpty.reverse (docs l r)) where- docs (Field aL bL) (Field aR bR) =+ docs (Field aL (Syntax.fieldSelectionLabel -> bL)) (Field aR (Syntax.fieldSelectionLabel -> bR)) = Data.List.NonEmpty.cons (diffLabel bL bR) (docs aL aR) docs (Project aL (Left bL)) (Project aR (Left bR)) = Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR) docs (Project aL (Right bL)) (Project aR (Right bR)) =- Data.List.NonEmpty.cons (diffExpression bL bR) (docs aL aR)+ Data.List.NonEmpty.cons (diff bL bR) (docs aL aR) docs aL aR = pure (diffPrimitiveExpression aL aR) diffSelectorExpression l@(Field {}) r =@@ -1033,12 +1144,12 @@ diffSelectorExpression l@(Project {}) r@(Project {}) = enclosed' " " (dot <> " ") (Data.List.NonEmpty.reverse (docs l r)) where- docs (Field aL bL) (Field aR bR) =+ docs (Field aL (Syntax.fieldSelectionLabel -> bL)) (Field aR (Syntax.fieldSelectionLabel ->bR)) = Data.List.NonEmpty.cons (diffLabel bL bR) (docs aL aR) docs (Project aL (Left bL)) (Project aR (Left bR)) = Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR) docs (Project aL (Right bL)) (Project aR (Right bR)) =- Data.List.NonEmpty.cons (diffExpression bL bR) (docs aL aR)+ Data.List.NonEmpty.cons (diff bL bR) (docs aL aR) docs aL aR = pure (diffPrimitiveExpression aL aR) diffSelectorExpression l@(Project {}) r =@@ -1048,7 +1159,7 @@ diffSelectorExpression l r = diffPrimitiveExpression l r -diffPrimitiveExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPrimitiveExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff diffPrimitiveExpression (Var aL) (Var aR) = diffVar aL aR diffPrimitiveExpression l@(Var {}) r =@@ -1067,6 +1178,18 @@ mismatch l r diffPrimitiveExpression l r@Bool = mismatch l r+diffPrimitiveExpression Bytes Bytes =+ "…"+diffPrimitiveExpression l@Bytes r =+ mismatch l r+diffPrimitiveExpression l r@Bytes =+ mismatch l r+diffPrimitiveExpression (BytesLit l) (BytesLit r) =+ diffBytes l r+diffPrimitiveExpression l@(BytesLit {}) r =+ mismatch l r+diffPrimitiveExpression l r@(BytesLit {}) =+ mismatch l r diffPrimitiveExpression Natural Natural = "…" diffPrimitiveExpression l@Natural r =@@ -1115,12 +1238,30 @@ mismatch l r diffPrimitiveExpression l r@NaturalShow = mismatch l r+diffPrimitiveExpression NaturalSubtract NaturalSubtract =+ "…"+diffPrimitiveExpression l@NaturalSubtract r =+ mismatch l r+diffPrimitiveExpression l r@NaturalSubtract =+ mismatch l r diffPrimitiveExpression Integer Integer = "…" diffPrimitiveExpression l@Integer r = mismatch l r diffPrimitiveExpression l r@Integer = mismatch l r+diffPrimitiveExpression IntegerClamp IntegerClamp =+ "…"+diffPrimitiveExpression l@IntegerClamp r =+ mismatch l r+diffPrimitiveExpression l r@IntegerClamp =+ mismatch l r+diffPrimitiveExpression IntegerNegate IntegerNegate =+ "…"+diffPrimitiveExpression l@IntegerNegate r =+ mismatch l r+diffPrimitiveExpression l r@IntegerNegate =+ mismatch l r diffPrimitiveExpression IntegerShow IntegerShow = "…" diffPrimitiveExpression l@IntegerShow r =@@ -1151,12 +1292,54 @@ mismatch l r diffPrimitiveExpression l r@Text = mismatch l r+diffPrimitiveExpression TextReplace TextReplace =+ "…"+diffPrimitiveExpression l@TextReplace r =+ mismatch l r+diffPrimitiveExpression l r@TextReplace =+ mismatch l r diffPrimitiveExpression TextShow TextShow = "…" diffPrimitiveExpression l@TextShow r = mismatch l r diffPrimitiveExpression l r@TextShow = mismatch l r+diffPrimitiveExpression Date Date =+ "…"+diffPrimitiveExpression l r@Date =+ mismatch l r+diffPrimitiveExpression l@Date r=+ mismatch l r+diffPrimitiveExpression DateShow DateShow =+ "…"+diffPrimitiveExpression l r@DateShow =+ mismatch l r+diffPrimitiveExpression l@DateShow r=+ mismatch l r+diffPrimitiveExpression Time Time =+ "…"+diffPrimitiveExpression l r@Time =+ mismatch l r+diffPrimitiveExpression l@Time r=+ mismatch l r+diffPrimitiveExpression TimeShow TimeShow =+ "…"+diffPrimitiveExpression l r@TimeShow =+ mismatch l r+diffPrimitiveExpression l@TimeShow r=+ mismatch l r+diffPrimitiveExpression TimeZone TimeZone =+ "…"+diffPrimitiveExpression l r@TimeZone =+ mismatch l r+diffPrimitiveExpression l@TimeZone r=+ mismatch l r+diffPrimitiveExpression TimeZoneShow TimeZoneShow =+ "…"+diffPrimitiveExpression l r@TimeZoneShow =+ mismatch l r+diffPrimitiveExpression l@TimeZoneShow r=+ mismatch l r diffPrimitiveExpression List List = "…" diffPrimitiveExpression l@List r =@@ -1166,10 +1349,6 @@ diffPrimitiveExpression (ListLit Nothing bL) (ListLit Nothing bR) = align doc where doc = format " " (diffList bL bR)-diffPrimitiveExpression l@(ListLit {}) r =- mismatch l r-diffPrimitiveExpression l r@(ListLit {}) =- mismatch l r diffPrimitiveExpression ListBuild ListBuild = "…" diffPrimitiveExpression l@ListBuild r =@@ -1224,18 +1403,6 @@ mismatch l r diffPrimitiveExpression l r@None = mismatch l r-diffPrimitiveExpression OptionalFold OptionalFold =- "…"-diffPrimitiveExpression l@OptionalFold r =- mismatch l r-diffPrimitiveExpression l r@OptionalFold =- mismatch l r-diffPrimitiveExpression OptionalBuild OptionalBuild =- "…"-diffPrimitiveExpression l@OptionalBuild r =- mismatch l r-diffPrimitiveExpression l r@OptionalBuild =- mismatch l r diffPrimitiveExpression (BoolLit aL) (BoolLit aR) = diffBool aL aR diffPrimitiveExpression l@(BoolLit {}) r =@@ -1266,6 +1433,24 @@ mismatch l r diffPrimitiveExpression l r@(TextLit {}) = mismatch l r+diffPrimitiveExpression (DateLiteral l) (DateLiteral r) =+ diffDateLiteral l r+diffPrimitiveExpression l@(DateLiteral {}) r =+ mismatch l r+diffPrimitiveExpression l r@(DateLiteral {}) =+ mismatch l r+diffPrimitiveExpression (TimeLiteral tL pL) (TimeLiteral tR pR) =+ diffTimeLiteral tL pL tR pR+diffPrimitiveExpression l@(TimeLiteral {}) r =+ mismatch l r+diffPrimitiveExpression l r@(TimeLiteral {}) =+ mismatch l r+diffPrimitiveExpression (TimeZoneLiteral l) (TimeZoneLiteral r) =+ diffTimeZoneLiteral l r+diffPrimitiveExpression l@(TimeZoneLiteral {}) r =+ mismatch l r+diffPrimitiveExpression l r@(TimeZoneLiteral {}) =+ mismatch l r diffPrimitiveExpression (Record aL) (Record aR) = diffRecord aL aR diffPrimitiveExpression l@(Record {}) r =@@ -1284,15 +1469,9 @@ mismatch l r diffPrimitiveExpression l r@(Union {}) = mismatch l r-diffPrimitiveExpression (UnionLit aL bL cL) (UnionLit aR bR cR) =- diffUnionLit aL aR bL bR cL cR-diffPrimitiveExpression l@(UnionLit {}) r =- mismatch l r-diffPrimitiveExpression l r@(UnionLit {}) =- mismatch l r diffPrimitiveExpression aL aR = if same doc then ignore else align ("( " <> doc <> hardline <> ")") where- doc = diffExpression aL aR+ doc = diff aL aR
@@ -0,0 +1,515 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -Wno-orphans #-}++-- | Implementation of the @dhall to-directory-tree@ subcommand+module Dhall.DirectoryTree+ ( -- * Filesystem+ toDirectoryTree+ , FilesystemError(..)++ -- * Low-level types and functions+ , module Dhall.DirectoryTree.Types+ , decodeDirectoryTree+ , directoryTreeType+ ) where++import Control.Applicative (empty)+import Control.Exception (Exception)+import Control.Monad (unless, when)+import Data.Either.Validation (Validation (..))+import Data.Functor.Identity (Identity (..))+import Data.Maybe (fromMaybe, isJust)+import Data.Sequence (Seq)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.DirectoryTree.Types+import Dhall.Marshal.Decode (Decoder (..), Expector)+import Dhall.Src (Src)+import Dhall.Syntax+ ( Chunks (..)+ , Const (..)+ , Expr (..)+ , RecordField (..)+ , Var (..)+ )+import System.FilePath ((</>))+import System.PosixCompat.Types (FileMode, GroupID, UserID)++import qualified Control.Exception as Exception+import qualified Data.ByteString as ByteString+import qualified Data.Foldable as Foldable+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Map as Map+import qualified Dhall.Marshal.Decode as Decode+import qualified Dhall.Pretty+import qualified Dhall.TypeCheck as TypeCheck+import qualified Dhall.Util as Util+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.String as Pretty+import qualified System.Directory as Directory+import qualified System.FilePath as FilePath+#ifdef mingw32_HOST_OS+import System.IO.Error (illegalOperationErrorType, mkIOError)+#else+import qualified System.Posix.User as Posix+#endif+import qualified System.PosixCompat.Files as Posix++{-| Attempt to transform a Dhall record into a directory tree where:++ * Records are translated into directories++ * @Map@s are also translated into directories++ * @Text@ values or fields are translated into files++ * @Optional@ values are omitted if @None@++ * There is a more advanced way to construct directory trees using a fixpoint+ encoding. See the documentation below on that.++ For example, the following Dhall record:++ > { dir = { `hello.txt` = "Hello\n" }+ > , `goodbye.txt`= Some "Goodbye\n"+ > , `missing.txt` = None Text+ > }++ ... should translate to this directory tree:++ > $ tree result+ > result+ > ├── dir+ > │ └── hello.txt+ > └── goodbye.txt+ >+ > $ cat result/dir/hello.txt+ > Hello+ >+ > $ cat result/goodbye.txt+ > Goodbye++ Use this in conjunction with the Prelude's support for rendering JSON/YAML+ in "pure Dhall" so that you can generate files containing JSON. For example:++ > let JSON =+ > https://prelude.dhall-lang.org/v12.0.0/JSON/package.dhall sha256:843783d29e60b558c2de431ce1206ce34bdfde375fcf06de8ec5bf77092fdef7+ >+ > in { `example.json` =+ > JSON.render (JSON.array [ JSON.number 1.0, JSON.bool True ])+ > , `example.yaml` =+ > JSON.renderYAML+ > (JSON.object (toMap { foo = JSON.string "Hello", bar = JSON.null }))+ > }++ ... which would generate:++ > $ cat result/example.json+ > [ 1.0, true ]+ >+ > $ cat result/example.yaml+ > ! "bar": null+ > ! "foo": "Hello"++ /Advanced construction of directory trees/++ In addition to the ways described above using "simple" Dhall values to+ construct the directory tree there is one based on a fixpoint encoding. It+ works by passing a value of the following type to the interpreter:++ > let User = < UserId : Natural | UserName : Text >+ >+ > let Group = < GroupId : Natural | GroupName : Text >+ >+ > let Access =+ > { execute : Optional Bool+ > , read : Optional Bool+ > , write : Optional Bool+ > }+ >+ > let Mode =+ > { user : Optional Access+ > , group : Optional Access+ > , other : Optional Access+ > }+ >+ > let Entry =+ > \(content : Type) ->+ > { name : Text+ > , content : content+ > , user : Optional User+ > , group : Optional Group+ > , mode : Optional Mode+ > }+ >+ > in forall (tree : Type) ->+ > forall ( make+ > : { directory : Entry (List tree) -> tree+ > , file : Entry Text -> tree+ > }+ > ) ->+ > List tree++ The fact that the metadata for filesystem entries is modeled after the POSIX+ permission model comes with the unfortunate downside that it might not apply+ to other systems: There, changes to the metadata (user, group, permissions)+ might be a no-op and __no warning will be issued__.+ This is a leaking abstraction of the+ [unix-compat](https://hackage.haskell.org/package/unix-compat) package used+ internally.++ __NOTE__: This utility does not take care of type-checking and normalizing+ the provided expression. This will raise a `FilesystemError` exception or a+ `Dhall.Marshal.Decode.DhallErrors` exception upon encountering an expression+ that cannot be converted as-is.+-}+toDirectoryTree+ :: Bool -- ^ Whether to allow path separators in file names or not+ -> FilePath+ -> Expr Void Void+ -> IO ()+toDirectoryTree allowSeparators path expression = case expression of+ RecordLit keyValues ->+ Map.unorderedTraverseWithKey_ process $ recordFieldValue <$> keyValues++ ListLit (Just (App List (Record [ ("mapKey", recordFieldValue -> Text), ("mapValue", _) ]))) [] ->+ Directory.createDirectoryIfMissing allowSeparators path++ ListLit _ records+ | not (null records)+ , Just keyValues <- extract (Foldable.toList records) ->+ Foldable.traverse_ (uncurry process) keyValues++ TextLit (Chunks [] text) ->+ Text.IO.writeFile path text++ Some value ->+ toDirectoryTree allowSeparators path value++ App (Field (Union _) _) value -> do+ toDirectoryTree allowSeparators path value++ App None _ ->+ return ()++ -- If this pattern matches we assume the user wants to use the fixpoint+ -- approach, hence we typecheck it and output error messages like we would+ -- do for every other Dhall program.+ Lam _ _ (Lam _ _ _) -> do+ entries <- decodeDirectoryTree expression++ processFilesystemEntryList allowSeparators path entries++ _ ->+ die+ where+ extract [] =+ return []++ extract (RecordLit [ ("mapKey", recordFieldValue -> TextLit (Chunks [] key))+ , ("mapValue", recordFieldValue -> value)] : records) =+ fmap ((key, value) :) (extract records)++ extract _ =+ empty++ process key value = do+ when (not allowSeparators && Text.isInfixOf (Text.pack [ FilePath.pathSeparator ]) key) $+ die++ Directory.createDirectoryIfMissing allowSeparators path++ toDirectoryTree allowSeparators (path </> Text.unpack key) value++ die = Exception.throwIO FilesystemError{..}+ where+ unexpectedExpression = expression++-- | Decode a fixpoint directory tree from a Dhall expression.+decodeDirectoryTree :: Expr s Void -> IO (Seq FilesystemEntry)+decodeDirectoryTree (Core.alphaNormalize . Core.denote -> expression@(Lam _ _ (Lam _ _ body))) = do+ expected' <- case directoryTreeType of+ Success x -> return x+ Failure e -> Exception.throwIO e++ _ <- Core.throws $ TypeCheck.typeOf $ Annot expression expected'++ case Decode.extract decoder body of+ Success x -> return x+ Failure e -> Exception.throwIO e+ where+ decoder :: Decoder (Seq FilesystemEntry)+ decoder = Decode.auto+decodeDirectoryTree expr = Exception.throwIO $ FilesystemError $ Core.denote expr++-- | The type of a fixpoint directory tree expression.+directoryTreeType :: Expector (Expr Src Void)+directoryTreeType = Pi Nothing "tree" (Const Type)+ <$> (Pi Nothing "make" <$> makeType <*> pure (App List (Var (V "tree" 0))))++-- | The type of make part of a fixpoint directory tree expression.+makeType :: Expector (Expr Src Void)+makeType = Record . Map.fromList <$> sequenceA+ [ makeConstructor "directory" (Decode.auto :: Decoder DirectoryEntry)+ , makeConstructor "file" (Decode.auto :: Decoder TextFileEntry)+ , makeConstructor "binary-file" (Decode.auto :: Decoder BinaryFileEntry)+ ]+ where+ makeConstructor :: Text -> Decoder b -> Expector (Text, RecordField Src Void)+ makeConstructor name dec = (name,) . Core.makeRecordField+ <$> (Pi Nothing "_" <$> expected dec <*> pure (Var (V "tree" 0)))++-- | Resolve a `User` to a numerical id.+getUser :: User -> IO UserID+getUser (UserId uid) = return uid+getUser (UserName name) =+#ifdef mingw32_HOST_OS+ ioError $ mkIOError illegalOperationErrorType x Nothing Nothing+ where x = "System.Posix.User.getUserEntryForName: not supported"+#else+ Posix.userID <$> Posix.getUserEntryForName name+#endif++-- | Resolve a `Group` to a numerical id.+getGroup :: Group -> IO GroupID+getGroup (GroupId gid) = return gid+getGroup (GroupName name) =+#ifdef mingw32_HOST_OS+ ioError $ mkIOError illegalOperationErrorType x Nothing Nothing+ where x = "System.Posix.User.getGroupEntryForName: not supported"+#else+ Posix.groupID <$> Posix.getGroupEntryForName name+#endif++-- | Process a `FilesystemEntry`. Writes the content to disk and apply the+-- metadata to the newly created item.+processFilesystemEntry :: Bool -> FilePath -> FilesystemEntry -> IO ()+processFilesystemEntry allowSeparators path (DirectoryEntry entry) =+ processEntryWith path entry $ \path' content -> do+ Directory.createDirectoryIfMissing allowSeparators path'+ processFilesystemEntryList allowSeparators path' content+processFilesystemEntry allowSeparators path (BinaryFileEntry entry) =+ processEntryWith path entry $ \path' content -> do+ when allowSeparators $ do+ Directory.createDirectoryIfMissing True (FilePath.takeDirectory path')+ ByteString.writeFile path' content+processFilesystemEntry allowSeparators path (TextFileEntry entry) =+ processEntryWith path entry $ \path' content -> do+ when allowSeparators $ do+ Directory.createDirectoryIfMissing True (FilePath.takeDirectory path')+ Text.IO.writeFile path' content++-- | A helper function used by 'processFilesystemEntry'.+processEntryWith+ :: FilePath+ -> Entry a+ -> (FilePath -> a -> IO ())+ -> IO ()+processEntryWith path entry f = do+ let path' = path </> entryName entry+ when (hasMetadata entry && not isMetadataSupported) $+ Exception.throwIO (MetadataUnsupportedError path')+ f path' (entryContent entry)+ -- It is important that we write the metadata after we wrote the content of+ -- the file as we might lock ourself out by changing ownership or+ -- permissions.+ applyMetadata entry path'++-- | Process a list of `FilesystemEntry`s.+processFilesystemEntryList :: Bool -> FilePath -> Seq FilesystemEntry -> IO ()+processFilesystemEntryList allowSeparators path = Foldable.traverse_+ (processFilesystemEntry allowSeparators path)++-- | Does this entry have some metadata set?+hasMetadata :: Entry a -> Bool+hasMetadata entry+ = isJust (entryUser entry)+ || isJust (entryGroup entry)+ || maybe False hasMode (entryMode entry)+ where+ hasMode :: Mode Maybe -> Bool+ hasMode mode+ = maybe False hasAccess (modeUser mode)+ || maybe False hasAccess (modeGroup mode)+ || maybe False hasAccess (modeOther mode)++ hasAccess :: Access Maybe -> Bool+ hasAccess access+ = isJust (accessExecute access)+ || isJust (accessRead access)+ || isJust (accessWrite access)++-- | Set the metadata of an object referenced by a path.+applyMetadata :: Entry a -> FilePath -> IO ()+applyMetadata entry fp = do+ s <- Posix.getFileStatus fp+ let user = Posix.fileOwner s+ group = Posix.fileGroup s+ mode = fileModeToMode $ Posix.fileMode s++ user' <- getUser $ fromMaybe (UserId user) (entryUser entry)+ group' <- getGroup $ fromMaybe (GroupId group) (entryGroup entry)+ unless ((user', group') == (user, group)) $+ Posix.setOwnerAndGroup fp user' group'++ let mode' = maybe mode (updateModeWith mode) (entryMode entry)+ unless (mode' == mode) $+ setFileMode fp $ modeToFileMode mode'++-- | Calculate the new `Mode` from the current mode and the changes specified by+-- the user.+updateModeWith :: Mode Identity -> Mode Maybe -> Mode Identity+updateModeWith x y = Mode+ { modeUser = combine modeUser modeUser+ , modeGroup = combine modeGroup modeGroup+ , modeOther = combine modeOther modeOther+ }+ where+ combine f g = maybe (f x) (Identity . updateAccessWith (runIdentity $ f x)) (g y)++-- | Calculate the new `Access` from the current permissions and the changes+-- specified by the user.+updateAccessWith :: Access Identity -> Access Maybe -> Access Identity+updateAccessWith x y = Access+ { accessExecute = combine accessExecute accessExecute+ , accessRead = combine accessRead accessRead+ , accessWrite = combine accessWrite accessWrite+ }+ where+ combine f g = maybe (f x) Identity (g y)++-- | Convert a filesystem mode given as a bitmask (`FileMode`) to an ADT+-- (`Mode`).+fileModeToMode :: FileMode -> Mode Identity+fileModeToMode mode = Mode+ { modeUser = Identity $ Access+ { accessExecute = Identity $ mode `hasFileMode` Posix.ownerExecuteMode+ , accessRead = Identity $ mode `hasFileMode` Posix.ownerReadMode+ , accessWrite = Identity $ mode `hasFileMode` Posix.ownerReadMode+ }+ , modeGroup = Identity $ Access+ { accessExecute = Identity $ mode `hasFileMode` Posix.groupExecuteMode+ , accessRead = Identity $ mode `hasFileMode` Posix.groupReadMode+ , accessWrite = Identity $ mode `hasFileMode` Posix.groupReadMode+ }+ , modeOther = Identity $ Access+ { accessExecute = Identity $ mode `hasFileMode` Posix.otherExecuteMode+ , accessRead = Identity $ mode `hasFileMode` Posix.otherReadMode+ , accessWrite = Identity $ mode `hasFileMode` Posix.otherReadMode+ }+ }++-- | Convert a filesystem mode given as an ADT (`Mode`) to a bitmask+-- (`FileMode`).+modeToFileMode :: Mode Identity -> FileMode+modeToFileMode mode = foldr Posix.unionFileModes Posix.nullFileMode $+ [ Posix.ownerExecuteMode | runIdentity $ accessExecute (runIdentity $ modeUser mode) ] <>+ [ Posix.ownerReadMode | runIdentity $ accessRead (runIdentity $ modeUser mode) ] <>+ [ Posix.ownerWriteMode | runIdentity $ accessWrite (runIdentity $ modeUser mode) ] <>+ [ Posix.groupExecuteMode | runIdentity $ accessExecute (runIdentity $ modeGroup mode) ] <>+ [ Posix.groupReadMode | runIdentity $ accessRead (runIdentity $ modeGroup mode) ] <>+ [ Posix.groupWriteMode | runIdentity $ accessWrite (runIdentity $ modeGroup mode) ] <>+ [ Posix.otherExecuteMode | runIdentity $ accessExecute (runIdentity $ modeOther mode) ] <>+ [ Posix.otherReadMode | runIdentity $ accessRead (runIdentity $ modeOther mode) ] <>+ [ Posix.otherWriteMode | runIdentity $ accessWrite (runIdentity $ modeOther mode) ]++-- | Check whether the second `FileMode` is contained in the first one.+hasFileMode :: FileMode -> FileMode -> Bool+hasFileMode mode x = (mode `Posix.intersectFileModes` x) == x++{- | This error indicates that you supplied an invalid Dhall expression to the+ `toDirectoryTree` function. The Dhall expression could not be translated+ to a directory tree.+-}+newtype FilesystemError =+ FilesystemError { unexpectedExpression :: Expr Void Void }++instance Exception FilesystemError++instance Show FilesystemError where+ show FilesystemError{..} =+ Pretty.renderString (Dhall.Pretty.layout message)+ where+ message =+ Util._ERROR <> ": Not a valid directory tree expression \n\\+ \ \n\\+ \Explanation: Only a subset of Dhall expressions can be converted to a directory \n\\+ \tree. Specifically, record literals or maps can be converted to directories, \n\\+ \❰Text❱ literals can be converted to files, and ❰Optional❱ values are included if \n\\+ \❰Some❱ and omitted if ❰None❱. Values of union types can also be converted if \n\\+ \they are an alternative which has a non-nullary constructor whose argument is of \n\\+ \an otherwise convertible type. Furthermore, there is a more advanced approach to \n\\+ \constructing a directory tree utilizing a fixpoint encoding. Consult the upstream \n\\+ \documentation of the `toDirectoryTree` function in the Dhall.Directory module for \n\\+ \further information on that. \n\\+ \No other type of value can be translated to a directory tree. \n\\+ \ \n\\+ \For example, this is a valid expression that can be translated to a directory \n\\+ \tree: \n\\+ \ \n\\+ \ \n\\+ \ ┌──────────────────────────────────┐ \n\\+ \ │ { `example.json` = \"[1, true]\" } │ \n\\+ \ └──────────────────────────────────┘ \n\\+ \ \n\\+ \ \n\\+ \In contrast, the following expression is not allowed due to containing a \n\\+ \❰Natural❱ field, which cannot be translated in this way: \n\\+ \ \n\\+ \ \n\\+ \ ┌───────────────────────┐ \n\\+ \ │ { `example.txt` = 1 } │ \n\\+ \ └───────────────────────┘ \n\\+ \ \n\\+ \ \n\\+ \Note that key names cannot contain path separators: \n\\+ \ \n\\+ \ \n\\+ \ ┌─────────────────────────────────────┐ \n\\+ \ │ { `directory/example.txt` = \"ABC\" } │ Invalid: Key contains a forward slash\n\\+ \ └─────────────────────────────────────┘ \n\\+ \ \n\\+ \ \n\\+ \Instead, you need to refactor the expression to use nested records instead: \n\\+ \ \n\\+ \ \n\\+ \ ┌───────────────────────────────────────────┐ \n\\+ \ │ { directory = { `example.txt` = \"ABC\" } } │ \n\\+ \ └───────────────────────────────────────────┘ \n\\+ \ \n\\+ \ \n\\+ \You tried to translate the following expression to a directory tree: \n\\+ \ \n\\+ \" <> Util.insert unexpectedExpression <> "\n\\+ \ \n\\+ \... which is not an expression that can be translated to a directory tree. \n"++{- | This error indicates that you want to set some metadata for a file or+ directory, but that operation is not supported on your platform.+-}+newtype MetadataUnsupportedError =+ MetadataUnsupportedError { metadataForPath :: FilePath }++instance Exception MetadataUnsupportedError++instance Show MetadataUnsupportedError where+ show MetadataUnsupportedError{..} =+ Pretty.renderString (Dhall.Pretty.layout message)+ where+ message =+ Util._ERROR <> ": Setting metadata is not supported on this platform. \n\\+ \ \n\\+ \Explanation: Your Dhall expression indicates that you intend to set some metadata \n\\+ \like ownership or permissions for the following file or directory: \n\\+ \ \n\\+ \" <> Pretty.pretty metadataForPath <> "\n\\+ \ \n\\+ \... which is not supported on your platform. \n"
@@ -0,0 +1,267 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -Wno-orphans #-}++-- | Types used by the implementation of the @to-directory-tree@ subcommand+module Dhall.DirectoryTree.Types+ ( FilesystemEntry(DirectoryEntry, BinaryFileEntry, TextFileEntry, FileEntry)+ , DirectoryEntry+ , FileEntry+ , BinaryFileEntry+ , TextFileEntry+ , Entry(..)+ , User(..)+ , Group(..)+ , Mode(..)+ , Access(..)++ , setFileMode+ , prettyFileMode++ , isMetadataSupported+ ) where++import Data.ByteString (ByteString)+import Data.Functor.Identity (Identity (..))+import Data.Sequence (Seq)+import Data.Text (Text)+import Dhall.Marshal.Decode+ ( Decoder (..)+ , FromDhall (..)+ , Generic+ , InputNormalizer+ , InterpretOptions (..)+ )+import Dhall.Syntax (Expr (..), FieldSelection (..), Var (..))+import System.PosixCompat.Types (GroupID, UserID)++import qualified Data.Text as Text+import qualified Dhall.Marshal.Decode as Decode+import qualified System.PosixCompat.Files as Posix++#ifdef mingw32_HOST_OS+import Control.Monad (unless)+import Data.Word (Word32)+import System.IO (hPutStrLn, stderr)+import System.PosixCompat.Types (CMode)++import qualified Unsafe.Coerce++type FileMode = CMode+#else+import System.PosixCompat.Types (FileMode)++import qualified System.PosixCompat.Types as Posix+#endif++pattern Make :: Text -> Expr s a -> Expr s a+pattern Make label entry <- App (Field (Var (V "_" 0)) (fieldSelectionLabel -> label)) entry++-- | A directory in the filesystem.+type DirectoryEntry = Entry (Seq FilesystemEntry)++-- | A file in the filesystem.+{-# DEPRECATED FileEntry "`FileEntry` is deprecated and will be removed eventually. Please use `TextFileEntry` instead." #-}+type FileEntry = Entry Text++-- | A binary file in the filesystem.+type BinaryFileEntry = Entry ByteString++-- | A text file in the filesystem.+type TextFileEntry = Entry Text++-- | A filesystem entry.+data FilesystemEntry+ = DirectoryEntry (Entry (Seq FilesystemEntry))+ | BinaryFileEntry BinaryFileEntry+ | TextFileEntry TextFileEntry+ deriving (Eq, Generic, Ord, Show)++pattern FileEntry :: Entry Text -> FilesystemEntry+pattern FileEntry entry = TextFileEntry entry++instance FromDhall FilesystemEntry where+ autoWith normalizer = Decoder+ { expected = pure $ Var (V "tree" 0)+ , extract = \case+ Make "directory" entry ->+ DirectoryEntry <$> extract (autoWith normalizer) entry+ Make "file" entry ->+ TextFileEntry <$> extract (autoWith normalizer) entry+ Make "binary-file" entry ->+ BinaryFileEntry <$> extract (autoWith normalizer) entry+ expr -> Decode.typeError (expected (Decode.autoWith normalizer :: Decoder FilesystemEntry)) expr+ }++-- | A generic filesystem entry. This type holds the metadata that apply to all+-- entries. It is parametric over the content of such an entry.+data Entry a = Entry+ { entryName :: String+ , entryContent :: a+ , entryUser :: Maybe User+ , entryGroup :: Maybe Group+ , entryMode :: Maybe (Mode Maybe)+ }+ deriving (Eq, Generic, Ord, Show)++instance FromDhall a => FromDhall (Entry a) where+ autoWith = Decode.genericAutoWithInputNormalizer Decode.defaultInterpretOptions+ { fieldModifier = Text.toLower . Text.drop (Text.length "entry")+ }++-- | A user identified either by id or name.+data User+ = UserId UserID+ | UserName String+ deriving (Eq, Generic, Ord, Show)++instance FromDhall User++#ifdef mingw32_HOST_OS+instance FromDhall UserID where+ autoWith normalizer = Unsafe.Coerce.unsafeCoerce <$> autoWith @Word32 normalizer+#else+instance FromDhall Posix.CUid where+ autoWith normalizer = Posix.CUid <$> autoWith normalizer+#endif++-- | A group identified either by id or name.+data Group+ = GroupId GroupID+ | GroupName String+ deriving (Eq, Generic, Ord, Show)++instance FromDhall Group++#ifdef mingw32_HOST_OS+instance FromDhall GroupID where+ autoWith normalizer = Unsafe.Coerce.unsafeCoerce <$> autoWith @Word32 normalizer+#else+instance FromDhall Posix.CGid where+ autoWith normalizer = Posix.CGid <$> autoWith normalizer+#endif++-- | A filesystem mode. See chmod(1).+-- The parameter is meant to be instantiated by either `Identity` or `Maybe`+-- depending on the completeness of the information:+-- * For data read from the filesystem it will be `Identity`.+-- * For user-supplied data it will be `Maybe` as we want to be able to set+-- only specific bits.+data Mode f = Mode+ { modeUser :: f (Access f)+ , modeGroup :: f (Access f)+ , modeOther :: f (Access f)+ }+ deriving Generic++deriving instance Eq (Mode Identity)+deriving instance Eq (Mode Maybe)+deriving instance Ord (Mode Identity)+deriving instance Ord (Mode Maybe)+deriving instance Show (Mode Identity)+deriving instance Show (Mode Maybe)++instance FromDhall (Mode Identity) where+ autoWith = modeDecoder++instance FromDhall (Mode Maybe) where+ autoWith = modeDecoder++modeDecoder :: FromDhall (f (Access f)) => InputNormalizer -> Decoder (Mode f)+modeDecoder = Decode.genericAutoWithInputNormalizer Decode.defaultInterpretOptions+ { fieldModifier = Text.toLower . Text.drop (Text.length "mode")+ }++-- | The permissions for a subject (user/group/other).+data Access f = Access+ { accessExecute :: f Bool+ , accessRead :: f Bool+ , accessWrite :: f Bool+ }+ deriving Generic++deriving instance Eq (Access Identity)+deriving instance Eq (Access Maybe)+deriving instance Ord (Access Identity)+deriving instance Ord (Access Maybe)+deriving instance Show (Access Identity)+deriving instance Show (Access Maybe)++instance FromDhall (Access Identity) where+ autoWith = accessDecoder++instance FromDhall (Access Maybe) where+ autoWith = accessDecoder++accessDecoder :: FromDhall (f Bool) => InputNormalizer -> Decoder (Access f)+accessDecoder = Decode.genericAutoWithInputNormalizer Decode.defaultInterpretOptions+ { fieldModifier = Text.toLower . Text.drop (Text.length "access")+ }++++-- | A wrapper around `Posix.setFileMode`. On Windows, it does check the+-- resulting file mode of the file/directory and emits a warning if it doesn't+-- match the desired file mode. On all other OS it is identical to+-- `Posix.setFileMode` as it is assumed to work correctly.+setFileMode :: FilePath -> FileMode -> IO ()+#ifdef mingw32_HOST_OS+setFileMode fp mode = do+ Posix.setFileMode fp mode+ mode' <- Posix.fileMode <$> Posix.getFileStatus fp+ unless (mode' == mode) $ hPutStrLn stderr $+ "Warning: Setting file mode did not succeed for " <> fp <> "\n" <>+ " Expected: " <> prettyFileMode mode <> "\n" <>+ " Actual: " <> prettyFileMode mode'+#else+setFileMode fp mode = Posix.setFileMode fp mode+#endif++-- | Pretty-print a `FileMode`. The format is similar to the one ls(1):+-- It is display as three blocks of three characters. The first block are the+-- permissions of the user, the second one are the ones of the group and the+-- third one the ones of other subjects. A @r@ denotes that the file or+-- directory is readable by the subject, a @w@ denotes that it is writable and+-- an @x@ denotes that it is executable. Unset permissions are represented by+-- @-@.+prettyFileMode :: FileMode -> String+prettyFileMode mode = userPP <> groupPP <> otherPP+ where+ userPP :: String+ userPP =+ isBitSet 'r' Posix.ownerReadMode <>+ isBitSet 'w' Posix.ownerWriteMode <>+ isBitSet 'x' Posix.ownerExecuteMode++ groupPP :: String+ groupPP =+ isBitSet 'r' Posix.groupReadMode <>+ isBitSet 'w' Posix.groupWriteMode <>+ isBitSet 'x' Posix.groupExecuteMode++ otherPP :: String+ otherPP =+ isBitSet 'r' Posix.otherReadMode <>+ isBitSet 'w' Posix.otherWriteMode <>+ isBitSet 'x' Posix.otherExecuteMode++ isBitSet :: Char -> FileMode -> String+ isBitSet c mask = if mask `Posix.intersectFileModes` mode /= Posix.nullFileMode+ then [c]+ else "-"++-- | Is setting metadata supported on this platform or not.+isMetadataSupported :: Bool+#ifdef mingw32_HOST_OS+isMetadataSupported = False+#else+isMetadataSupported = True+#endif
@@ -1,946 +1,1567 @@-{-# LANGUAGE- BangPatterns,- CPP,- LambdaCase,- OverloadedStrings,- PatternSynonyms,- RankNTypes,- ScopedTypeVariables,- TupleSections,- ViewPatterns- #-}--{-# OPTIONS_GHC- -O- -fno-warn-name-shadowing- -fno-warn-unused-matches- #-}--{-|-Eval-apply environment machine with conversion checking and quoting to normal-forms. Fairly similar to GHCI's STG machine algorithmically, but much simpler,-with no known call optimization or environment trimming.--Potential optimizations without changing Expr:- - In conversion checking, get non-shadowing variables not by linear- Env-walking, but by keeping track of Env size, and generating names which- are known to be illegal as source-level names (to rule out shadowing).- - Use HashMap Text chunks for large let-definitions blocks. "Large" vs "Small"- is fairly cheap to determine at evaluation time.--Potential optimizations with changing Expr:- - Use Int in Var instead of Integer. Overflow is practically impossible.- - Use actual full de Bruijn indices in Var instead of Text counting indices. Then, we'd- switch to full de Bruijn levels in Val as well, and use proper constant time non-shadowing- name generation.---}--module Dhall.Eval (- Env(..)- , Names(..)- , Closure(..)- , VChunks(..)- , Val(..)- , Void- , inst- , eval- , conv- , convEmpty- , quote- , nf- , nfEmpty- , Dhall.Eval.alphaNormalize- ) where--#if MIN_VERSION_base(4,8,0)-#else-import Control.Applicative (Applicative(..), (<$>))-#endif--import Data.Foldable (foldr', foldl', toList)-import Data.List.NonEmpty (NonEmpty(..), cons)-import Data.Semigroup (Semigroup(..))-import Data.Sequence (Seq)-import Data.Text (Text)--import Dhall.Core (- Expr(..)- , Binding(..)- , Chunks(..)- , Const(..)- , Import- , Var(..)- , denote- )---- import Control.Exception (throw)--- import Dhall.Import.Types (InternalError)-import Dhall.Map (Map)-import Dhall.Set (Set)-import GHC.Natural (Natural)-import Unsafe.Coerce (unsafeCoerce)--import qualified Data.Char-import qualified Data.List.NonEmpty-import qualified Data.Sequence-import qualified Data.Text-import qualified Dhall.Binary-import qualified Dhall.Map-import qualified Dhall.Set-import qualified Text.Printf--------------------------------------------------------------------------------------------------------data Env a =- Empty- | Skip !(Env a) {-# unpack #-} !Text- | Extend !(Env a) {-# unpack #-} !Text (Val a)--data Void--coeExprVoid :: Expr Void a -> Expr s a-coeExprVoid = unsafeCoerce-{-# inline coeExprVoid #-}--errorMsg :: String-errorMsg = unlines- [ _ERROR <> ": Compiler bug "- , " "- , "An ill-typed expression was encountered during normalization. "- , "Explanation: This error message means that there is a bug in the Dhall compiler."- , "You didn't do anything wrong, but if you would like to see this problem fixed "- , "then you should report the bug at: "- , " "- , "https://github.com/dhall-lang/dhall-haskell/issues "- ]- where- _ERROR :: String- _ERROR = "\ESC[1;31mError\ESC[0m"---data Closure a = Cl !Text !(Env a) !(Expr Void a)-data VChunks a = VChunks ![(Text, Val a)] !Text--instance Semigroup (VChunks a) where- VChunks xys z <> VChunks [] z' = VChunks xys (z <> z')- VChunks xys z <> VChunks ((x', y'):xys') z' = VChunks (xys ++ (z <> x', y'):xys') z'--instance Monoid (VChunks a) where- mempty = VChunks [] mempty--#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)-#endif--data HLamInfo a- = Prim- | Typed !Text (Val a)- | NaturalFoldCl (Val a)- | ListFoldCl (Val a)- | OptionalFoldCl (Val a)--pattern VPrim :: (Val a -> Val a) -> Val a-pattern VPrim f = VHLam Prim f--data Val a- = VConst !Const- | VVar !Text !Int- | VPrimVar- | VApp !(Val a) !(Val a)-- | VLam (Val a) {-# unpack #-} !(Closure a)- | VHLam !(HLamInfo a) !(Val a -> Val a)-- | VPi (Val a) {-# unpack #-} !(Closure a)- | VHPi !Text (Val a) !(Val a -> Val a)-- | VBool- | VBoolLit !Bool- | VBoolAnd !(Val a) !(Val a)- | VBoolOr !(Val a) !(Val a)- | VBoolEQ !(Val a) !(Val a)- | VBoolNE !(Val a) !(Val a)- | VBoolIf !(Val a) !(Val a) !(Val a)-- | VNatural- | VNaturalLit !Natural- | VNaturalFold !(Val a) !(Val a) !(Val a) !(Val a)- | VNaturalBuild !(Val a)- | VNaturalIsZero !(Val a)- | VNaturalEven !(Val a)- | VNaturalOdd !(Val a)- | VNaturalToInteger !(Val a)- | VNaturalShow !(Val a)- | VNaturalPlus !(Val a) !(Val a)- | VNaturalTimes !(Val a) !(Val a)-- | VInteger- | VIntegerLit !Integer- | VIntegerShow !(Val a)- | VIntegerToDouble !(Val a)-- | VDouble- | VDoubleLit !Double- | VDoubleShow !(Val a)-- | VText- | VTextLit !(VChunks a)- | VTextAppend !(Val a) !(Val a)- | VTextShow !(Val a)-- | VList !(Val a)- | VListLit !(Maybe (Val a)) !(Seq (Val a))- | VListAppend !(Val a) !(Val a)- | VListBuild (Val a) !(Val a)- | VListFold (Val a) !(Val a) !(Val a) !(Val a) !(Val a)- | VListLength (Val a) !(Val a)- | VListHead (Val a) !(Val a)- | VListLast (Val a) !(Val a)- | VListIndexed (Val a) !(Val a)- | VListReverse (Val a) !(Val a)-- | VOptional (Val a)- | VSome (Val a)- | VNone (Val a)- | VOptionalFold (Val a) !(Val a) (Val a) !(Val a) !(Val a)- | VOptionalBuild (Val a) !(Val a)- | VRecord !(Map Text (Val a))- | VRecordLit !(Map Text (Val a))- | VUnion !(Map Text (Maybe (Val a)))- | VUnionLit !Text !(Val a) !(Map Text (Maybe (Val a)))- | VCombine !(Val a) !(Val a)- | VCombineTypes !(Val a) !(Val a)- | VPrefer !(Val a) !(Val a)- | VMerge !(Val a) !(Val a) !(Maybe (Val a))- | VField !(Val a) !Text- | VInject !(Map Text (Maybe (Val a))) !Text !(Maybe (Val a))- | VProject !(Val a) !(Either (Set Text) (Val a))- | VEmbed a--vFun :: Val a -> Val a -> Val a-vFun a b = VHPi "_" a (\_ -> b)-{-# inline vFun #-}---- Evaluation-------------------------------------------------------------------------------------------------------textShow :: Text -> Text-textShow text = "\"" <> Data.Text.concatMap f text <> "\""- where- f '"' = "\\\""- f '$' = "\\u0024"- f '\\' = "\\\\"- f '\b' = "\\b"- f '\n' = "\\n"- f '\r' = "\\r"- f '\t' = "\\t"- f '\f' = "\\f"- f c | c <= '\x1F' = Data.Text.pack (Text.Printf.printf "\\u%04x" (Data.Char.ord c))- | otherwise = Data.Text.singleton c--countName :: Text -> Env a -> Int-countName x = go (0 :: Int) where- go !acc Empty = acc- go acc (Skip env x' ) = go (if x == x' then acc + 1 else acc) env- go acc (Extend env x' _) = go (if x == x' then acc + 1 else acc) env--inst :: Eq a => Closure a -> Val a -> Val a-inst (Cl x env t) !u = eval (Extend env x u) t-{-# inline inst #-}---- Out-of-env variables have negative de Bruijn levels.-vVar :: Env a -> Var -> Val a-vVar env (V x (fromInteger -> i :: Int)) = go env i where- go (Extend env x' v) i- | x == x' = if i == 0 then v else go env (i - 1)- | otherwise = go env i- go (Skip env x') i- | x == x' = if i == 0 then VVar x (countName x env) else go env (i - 1)- | otherwise = go env i- go Empty i = VVar x (0 - i - 1)--vApp :: Eq a => Val a -> Val a -> Val a-vApp !t !u = case t of- VLam _ t -> inst t u- VHLam _ t -> t u- t -> VApp t u-{-# inline vApp #-}--vCombine :: Val a -> Val a -> Val a-vCombine t u = case (t, u) of- (VRecordLit m, u) | null m -> u- (t, VRecordLit m) | null m -> t- (VRecordLit m, VRecordLit m') -> VRecordLit (Dhall.Map.sort (Dhall.Map.unionWith vCombine m m'))- (t, u) -> VCombine t u--vCombineTypes :: Val a -> Val a -> Val a-vCombineTypes t u = case (t, u) of- (VRecord m, u) | null m -> u- (t, VRecord m) | null m -> t- (VRecord m, VRecord m') -> VRecord (Dhall.Map.sort (Dhall.Map.unionWith vCombineTypes m m'))- (t, u) -> VCombineTypes t u--vListAppend :: Val a -> Val a -> Val a-vListAppend t u = case (t, u) of- (VListLit _ xs, u) | null xs -> u- (t, VListLit _ ys) | null ys -> t- (VListLit t xs, VListLit _ ys) -> VListLit t (xs <> ys)- (t, u) -> VListAppend t u-{-# inline vListAppend #-}--vNaturalPlus :: Val a -> Val a -> Val a-vNaturalPlus t u = case (t, u) of- (VNaturalLit 0, u ) -> u- (t, VNaturalLit 0) -> t- (VNaturalLit m, VNaturalLit n) -> VNaturalLit (m + n)- (t, u ) -> VNaturalPlus t u-{-# inline vNaturalPlus #-}--eval :: forall a. Eq a => Env a -> Expr Void a -> Val a-eval !env t =- let- evalE :: Expr Void a -> Val a- evalE = eval env- {-# inline evalE #-}-- evalChunks :: Chunks Void a -> VChunks a- evalChunks (Chunks xys z) =- foldr' (\(x, t) vcs ->- case evalE t of- VTextLit vcs' -> VChunks [] x <> vcs' <> vcs- t -> VChunks [(x, t)] mempty <> vcs)- (VChunks [] z)- xys- {-# inline evalChunks #-}-- in case t of- Const k -> VConst k- Var v -> vVar env v- Lam x a t -> VLam (evalE a) (Cl x env t)- Pi x a b -> VPi (evalE a) (Cl x env b)- App t u -> vApp (evalE t) (evalE u)- Let (b :| bs) t -> go env (b:bs) where- go !env [] = eval env t- go env (b:bs) = go (Extend env (variable b)- (eval env (value b))) bs- Annot t _ -> evalE t-- Bool -> VBool- BoolLit b -> VBoolLit b- BoolAnd t u -> case (evalE t, evalE u) of- (VBoolLit True, u) -> u- (VBoolLit False, u) -> VBoolLit False- (t, VBoolLit True) -> t- (t, VBoolLit False) -> VBoolLit False- (t, u) | conv env t u -> t- (t, u) -> VBoolAnd t u- BoolOr t u -> case (evalE t, evalE u) of- (VBoolLit False, u) -> u- (VBoolLit True, u) -> VBoolLit True- (t, VBoolLit False) -> t- (t, VBoolLit True) -> VBoolLit True- (t, u) | conv env t u -> t- (t, u) -> VBoolOr t u- BoolEQ t u -> case (evalE t, evalE u) of- (VBoolLit True, u) -> u- (t, VBoolLit True) -> t- (t, u) | conv env t u -> VBoolLit True- (t, u) -> VBoolEQ t u- BoolNE t u -> case (evalE t, evalE u) of- (VBoolLit False, u) -> u- (t, VBoolLit False) -> t- (t, u) | conv env t u -> VBoolLit False- (t, u) -> VBoolNE t u- BoolIf b t f -> case (evalE b, evalE t, evalE f) of- (VBoolLit True, t, f) -> t- (VBoolLit False, t, f) -> f- (b, VBoolLit True, VBoolLit False) -> b- (b, t, f) | conv env t f -> t- (b, t, f) -> VBoolIf b t f-- Natural -> VNatural- NaturalLit n -> VNaturalLit n- NaturalFold -> VPrim $ \case- VNaturalLit n ->- VHLam (Typed "natural" (VConst Type)) $ \natural ->- VHLam (Typed "succ" (vFun natural natural)) $ \succ ->- VHLam (Typed "zero" natural) $ \zero ->- let go !acc 0 = acc- go acc n = go (vApp succ acc) (n - 1)- in go zero (fromIntegral n :: Integer)- n ->- VHLam (NaturalFoldCl n) $ \natural -> VPrim $ \succ -> VPrim $ \zero ->- VNaturalFold n natural succ zero- NaturalBuild -> VPrim $ \case- VHLam (NaturalFoldCl x) _ -> x- VPrimVar -> VNaturalBuild VPrimVar- t ->- t `vApp` VNatural- `vApp` VHLam (Typed "n" VNatural) (\n -> vNaturalPlus n (VNaturalLit 1))- `vApp` VNaturalLit 0-- NaturalIsZero -> VPrim $ \case VNaturalLit n -> VBoolLit (n == 0)- n -> VNaturalIsZero n- NaturalEven -> VPrim $ \case VNaturalLit n -> VBoolLit (even n)- n -> VNaturalEven n- NaturalOdd -> VPrim $ \case VNaturalLit n -> VBoolLit (odd n)- n -> VNaturalOdd n- NaturalToInteger -> VPrim $ \case VNaturalLit n -> VIntegerLit (fromIntegral n)- n -> VNaturalToInteger n- NaturalShow -> VPrim $ \case VNaturalLit n -> VTextLit (VChunks [] (Data.Text.pack (show n)))- n -> VNaturalShow n- NaturalPlus t u -> vNaturalPlus (evalE t) (evalE u)- NaturalTimes t u -> case (evalE t, evalE u) of- (VNaturalLit 1, u ) -> u- (t, VNaturalLit 1) -> t- (VNaturalLit 0, u ) -> VNaturalLit 0- (t, VNaturalLit 0) -> VNaturalLit 0- (VNaturalLit m, VNaturalLit n) -> VNaturalLit (m * n)- (t, u ) -> VNaturalTimes t u-- Integer -> VInteger- IntegerLit n -> VIntegerLit n- IntegerShow -> VPrim $ \case- VIntegerLit n- | 0 <= n -> VTextLit (VChunks [] (Data.Text.pack ('+':show n)))- | otherwise -> VTextLit (VChunks [] (Data.Text.pack (show n)))- n -> VIntegerShow n- IntegerToDouble -> VPrim $ \case VIntegerLit n -> VDoubleLit (read (show n))- -- `(read . show)` is used instead of `fromInteger`- -- because `read` uses the correct rounding rule- n -> VIntegerToDouble n-- Double -> VDouble- DoubleLit n -> VDoubleLit n- DoubleShow -> VPrim $ \case VDoubleLit n -> VTextLit (VChunks [] (Data.Text.pack (show n)))- n -> VDoubleShow n-- Text -> VText- TextLit cs -> case evalChunks cs of- VChunks [("", t)] "" -> t- vcs -> VTextLit vcs- TextAppend t u -> evalE (TextLit (Chunks [("", t), ("", u)] ""))- TextShow -> VPrim $ \case- VTextLit (VChunks [] x) -> VTextLit (VChunks [] (textShow x))- t -> VTextShow t-- List -> VPrim VList- ListLit ma ts -> VListLit (evalE <$> ma) (evalE <$> ts)- ListAppend t u -> vListAppend (evalE t) (evalE u)- ListBuild -> VPrim $ \a -> VPrim $ \case- VHLam (ListFoldCl x) _ -> x- VPrimVar -> VListBuild a VPrimVar- t ->- t `vApp` VList a- `vApp` VHLam (Typed "a" a) (\x ->- VHLam (Typed "as" (VList a)) (\as ->- vListAppend (VListLit Nothing (pure x)) as))- `vApp` VListLit (Just a) mempty-- ListFold -> VPrim $ \a -> VPrim $ \case- VListLit _ as ->- VHLam (Typed "list" (VConst Type)) $ \list ->- VHLam (Typed "cons" (vFun a $ vFun list list) ) $ \cons ->- VHLam (Typed "nil" list) $ \nil ->- foldr' (\x b -> cons `vApp` x `vApp` b) nil as- as ->- VHLam (ListFoldCl as) $ \t -> VPrim $ \c -> VPrim $ \n ->- VListFold a as t c n-- ListLength -> VPrim $ \ a -> VPrim $ \case- VListLit _ as -> VNaturalLit (fromIntegral (Data.Sequence.length as))- as -> VListLength a as- ListHead -> VPrim $ \ a -> VPrim $ \case- VListLit _ as -> case Data.Sequence.viewl as of- y Data.Sequence.:< _ -> VSome y- _ -> VNone a- as -> VListHead a as- ListLast -> VPrim $ \ a -> VPrim $ \case- VListLit _ as -> case Data.Sequence.viewr as of- _ Data.Sequence.:> t -> VSome t- _ -> VNone a- as -> VListLast a as- ListIndexed -> VPrim $ \ a -> VPrim $ \case- VListLit _ as -> let- a' = if null as then- Just (VRecord (Dhall.Map.fromList- [("index", VNatural), ("value", a)]))- else- Nothing- as' = Data.Sequence.mapWithIndex- (\i t -> VRecordLit- (Dhall.Map.fromList [("index", VNaturalLit (fromIntegral i)),- ("value", t)]))- as- in VListLit a' as'- t -> VListIndexed a t- ListReverse -> VPrim $ \ ~a -> VPrim $ \case- VListLit t as | null as -> VListLit t (Data.Sequence.reverse as)- VListLit t as -> VListLit Nothing (Data.Sequence.reverse as)- t -> VListReverse a t-- Optional -> VPrim VOptional- OptionalLit a mt -> maybe (VNone (evalE a)) (\t -> VSome (evalE t)) mt- Some t -> VSome (evalE t)- None -> VPrim $ \ ~a -> VNone a-- OptionalFold -> VPrim $ \ ~a -> VPrim $ \case- VNone _ ->- VHLam (Typed "optional" (VConst Type)) $ \optional ->- VHLam (Typed "some" (vFun a optional)) $ \some ->- VHLam (Typed "none" optional) $ \none ->- none- VSome t ->- VHLam (Typed "optional" (VConst Type)) $ \optional ->- VHLam (Typed "some" (vFun a optional)) $ \some ->- VHLam (Typed "none" optional) $ \none ->- some `vApp` t- opt ->- VHLam (OptionalFoldCl opt) $ \o ->- VPrim $ \s ->- VPrim $ \n ->- VOptionalFold a opt o s n- OptionalBuild -> VPrim $ \ ~a -> VPrim $ \case- VHLam (OptionalFoldCl x) _ -> x- VPrimVar -> VOptionalBuild a VPrimVar- t -> t `vApp` VOptional a- `vApp` VHLam (Typed "a" a) VSome- `vApp` VNone a-- Record kts -> VRecord (Dhall.Map.sort (evalE <$> kts))- RecordLit kts -> VRecordLit (Dhall.Map.sort (evalE <$> kts))- Union kts -> VUnion (Dhall.Map.sort ((evalE <$>) <$> kts))- UnionLit k v kts -> VUnionLit k (evalE v) (Dhall.Map.sort ((evalE <$>) <$> kts))- Combine t u -> vCombine (evalE t) (evalE u)- CombineTypes t u -> vCombineTypes (evalE t) (evalE u)- Prefer t u -> case (evalE t, evalE u) of- (VRecordLit m, u) | null m -> u- (t, VRecordLit m) | null m -> t- (VRecordLit m, VRecordLit m') ->- VRecordLit (Dhall.Map.sort (Dhall.Map.union m' m))- (t, u) -> VPrefer t u- Merge x y ma -> case (evalE x, evalE y, evalE <$> ma) of- (VRecordLit m, VUnionLit k v _, _)- | Just f <- Dhall.Map.lookup k m -> f `vApp` v- | otherwise -> error errorMsg- (VRecordLit m, VInject _ k mt, _)- | Just f <- Dhall.Map.lookup k m -> maybe f (vApp f) mt- | otherwise -> error errorMsg- (x, y, ma) -> VMerge x y ma- Field t k -> case evalE t of- VRecordLit m- | Just v <- Dhall.Map.lookup k m -> v- | otherwise -> error errorMsg- VUnion m -> case Dhall.Map.lookup k m of- Just (Just _) -> VPrim $ \ ~u -> VInject m k (Just u)- Just Nothing -> VInject m k Nothing- _ -> error errorMsg- t -> VField t k- Project t (Left ks) ->- if null ks then- VRecordLit mempty- else case evalE t of- VRecordLit kvs- | Just s <- traverse (\k -> (k,) <$> Dhall.Map.lookup k kvs) (toList ks)- -> VRecordLit (Dhall.Map.sort (Dhall.Map.fromList s))- | otherwise -> error errorMsg- t -> VProject t (Left ks)- Project t (Right e) ->- case evalE e of- VRecord kts ->- evalE (Project t (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))- e' -> VProject (evalE t) (Right e')- Note _ e -> evalE e- ImportAlt t _ -> evalE t- Embed a -> VEmbed a----- Conversion checking-----------------------------------------------------------------------------------eqListBy :: (a -> a -> Bool) -> [a] -> [a] -> Bool-eqListBy f = go where- go (x:xs) (y:ys) | f x y = go xs ys- go [] [] = True- go _ _ = False-{-# inline eqListBy #-}--eqMapsBy :: Ord k => (v -> v -> Bool) -> Map k v -> Map k v -> Bool-eqMapsBy f mL mR = eqListBy eq (Dhall.Map.toList mL) (Dhall.Map.toList mR)- where- eq (kL, vL) (kR, vR) = kL == kR && f vL vR-{-# inline eqMapsBy #-}--eqMaybeBy :: (a -> a -> Bool) -> Maybe a -> Maybe a -> Bool-eqMaybeBy f = go where- go (Just x) (Just y) = f x y- go Nothing Nothing = True- go _ _ = False-{-# inline eqMaybeBy #-}--conv :: forall a. Eq a => Env a -> Val a -> Val a -> Bool-conv !env t t' =- let- fresh :: Text -> (Text, Val a)- fresh x = (x, VVar x (countName x env))- {-# inline fresh #-}-- freshCl :: Closure a -> (Text, Val a, Closure a)- freshCl cl@(Cl x _ _) = (x, snd (fresh x), cl)- {-# inline freshCl #-}-- convChunks :: VChunks a -> VChunks a -> Bool- convChunks (VChunks xys z) (VChunks xys' z') =- eqListBy (\(x, y) (x', y') -> x == x' && conv env y y') xys xys' && z == z'- {-# inline convChunks #-}-- convE :: Val a -> Val a -> Bool- convE = conv env- {-# inline convE #-}-- convSkip :: Text -> Val a -> Val a -> Bool- convSkip x = conv (Skip env x)- {-# inline convSkip #-}-- in case (t, t') of- (VConst k, VConst k') -> k == k'- (VVar x i, VVar x' i') -> x == x' && i == i'-- (VLam _ (freshCl -> (x, v, t)), VLam _ t' ) -> convSkip x (inst t v) (inst t' v)- (VLam _ (freshCl -> (x, v, t)), VHLam _ t') -> convSkip x (inst t v) (t' v)- (VLam _ (freshCl -> (x, v, t)), t' ) -> convSkip x (inst t v) (vApp t' v)- (VHLam _ t, VLam _ (freshCl -> (x, v, t'))) -> convSkip x (t v) (inst t' v)- (VHLam _ t, VHLam _ t' ) -> let (x, v) = fresh "x" in convSkip x (t v) (t' v)- (VHLam _ t, t' ) -> let (x, v) = fresh "x" in convSkip x (t v) (vApp t' v)-- (t, VLam _ (freshCl -> (x, v, t'))) -> convSkip x (vApp t v) (inst t' v)- (t, VHLam _ t' ) -> let (x, v) = fresh "x" in convSkip x (vApp t v) (t' v)-- (VApp t u, VApp t' u') -> convE t t' && convE u u'-- (VPi a b, VPi a' (freshCl -> (x, v, b'))) ->- convE a a' && convSkip x (inst b v) (inst b' v)- (VPi a b, VHPi (fresh -> (x, v)) a' b') ->- convE a a' && convSkip x (inst b v) (b' v)- (VHPi _ a b, VPi a' (freshCl -> (x, v, b'))) ->- convE a a' && convSkip x (b v) (inst b' v)- (VHPi _ a b, VHPi (fresh -> (x, v)) a' b') ->- convE a a' && convSkip x (b v) (b' v)-- (VBool , VBool ) -> True- (VBoolLit b , VBoolLit b' ) -> b == b'- (VBoolAnd t u, VBoolAnd t' u' ) -> convE t t' && convE u u'- (VBoolOr t u, VBoolOr t' u' ) -> convE t t' && convE u u'- (VBoolEQ t u, VBoolEQ t' u' ) -> convE t t' && convE u u'- (VBoolNE t u, VBoolNE t' u' ) -> convE t t' && convE u u'- (VBoolIf t u v, VBoolIf t' u' v') -> convE t t' && convE u u' && convE v v'-- (VNatural, VNatural) -> True- (VNaturalLit n, VNaturalLit n') -> n == n'- (VNaturalFold t _ u v, VNaturalFold t' _ u' v') ->- convE t t' && convE u u' && convE v v'-- (VNaturalBuild t , VNaturalBuild t') -> convE t t'- (VNaturalIsZero t , VNaturalIsZero t') -> convE t t'- (VNaturalEven t , VNaturalEven t') -> convE t t'- (VNaturalOdd t , VNaturalOdd t') -> convE t t'- (VNaturalToInteger t , VNaturalToInteger t') -> convE t t'- (VNaturalShow t , VNaturalShow t') -> convE t t'- (VNaturalPlus t u , VNaturalPlus t' u') -> convE t t' && convE u u'- (VNaturalTimes t u , VNaturalTimes t' u') -> convE t t' && convE u u'-- (VInteger , VInteger) -> True- (VIntegerLit t , VIntegerLit t') -> t == t'- (VIntegerShow t , VIntegerShow t') -> convE t t'- (VIntegerToDouble t , VIntegerToDouble t') -> convE t t'-- (VDouble , VDouble) -> True- (VDoubleLit n , VDoubleLit n') -> Dhall.Binary.encode (DoubleLit n :: Expr Void Import) ==- Dhall.Binary.encode (DoubleLit n' :: Expr Void Import)- (VDoubleShow t , VDoubleShow t') -> convE t t'-- (VText, VText) -> True-- (VTextLit cs , VTextLit cs') -> convChunks cs cs'- (VTextAppend t u , VTextAppend t' u') -> convE t t' && convE u u'- (VTextShow t , VTextShow t') -> convE t t'-- (VList a , VList a' ) -> convE a a'- (VListLit _ xs , VListLit _ xs') -> eqListBy convE (toList xs) (toList xs')-- (VListAppend t u , VListAppend t' u' ) -> convE t t' && convE u u'- (VListBuild a t , VListBuild a' t' ) -> convE t t'- (VListLength a t , VListLength a' t' ) -> convE a a' && convE t t'- (VListHead _ t , VListHead _ t' ) -> convE t t'- (VListLast _ t , VListLast _ t' ) -> convE t t'- (VListIndexed _ t , VListIndexed _ t' ) -> convE t t'- (VListReverse _ t , VListReverse _ t' ) -> convE t t'- (VListFold a l _ t u , VListFold a' l' _ t' u' ) ->- convE a a' && convE l l' && convE t t' && convE u u'-- (VOptional a , VOptional a' ) -> convE a a'- (VSome t , VSome t' ) -> convE t t'- (VNone _ , VNone _ ) -> True- (VOptionalBuild _ t , VOptionalBuild _ t' ) -> convE t t'- (VRecord m , VRecord m' ) -> eqMapsBy convE m m'- (VRecordLit m , VRecordLit m' ) -> eqMapsBy convE m m'- (VUnion m , VUnion m' ) -> eqMapsBy (eqMaybeBy convE) m m'- (VUnionLit k v m , VUnionLit k' v' m' ) -> k == k' && convE v v' &&- eqMapsBy (eqMaybeBy convE) m m'- (VCombine t u , VCombine t' u' ) -> convE t t' && convE u u'- (VCombineTypes t u , VCombineTypes t' u' ) -> convE t t' && convE u u'- (VPrefer t u , VPrefer t' u' ) -> convE t t' && convE u u'- (VMerge t u _ , VMerge t' u' _ ) -> convE t t' && convE u u'- (VField t k , VField t' k' ) -> convE t t' && k == k'- (VProject t (Left ks) , VProject t' (Left ks') ) -> convE t t' && ks == ks'- (VProject t (Right e) , VProject t' (Right e') ) -> convE t t' && convE e e'- (VInject m k mt , VInject m' k' mt' ) -> eqMapsBy (eqMaybeBy convE) m m'- && k == k' && eqMaybeBy convE mt mt'- (VEmbed a , VEmbed a' ) -> a == a'- (VOptionalFold a t _ u v , VOptionalFold a' t' _ u' v' ) ->- convE a a' && convE t t' && convE u u' && convE v v'-- (_, _) -> False--convEmpty :: Eq a => Expr s a -> Expr t a -> Bool-convEmpty (denote -> t) (denote -> u) = conv Empty (eval Empty t) (eval Empty u)---- Quoting-------------------------------------------------------------------------------------------------------data Names- = NEmpty- | NBind !Names {-# unpack #-} !Text- deriving Show--envNames :: Env a -> Names-envNames Empty = NEmpty-envNames (Skip env x ) = NBind (envNames env) x-envNames (Extend env x _) = NBind (envNames env) x--countName' :: Text -> Names -> Int-countName' x = go 0 where- go !acc NEmpty = acc- go acc (NBind env x') = go (if x == x' then acc + 1 else acc) env---- | Quote a value into beta-normal form.-quote :: forall a. Eq a => Names -> Val a -> Expr Void a-quote !env !t =- let- fresh :: Text -> (Text, Val a)- fresh x = (x, VVar x (countName' x env))- {-# inline fresh #-}-- freshCl :: Closure a -> (Text, Val a, Closure a)- freshCl cl@(Cl x _ _) = (x, snd (fresh x), cl)- {-# inline freshCl #-}-- qVar :: Text -> Int -> Expr Void a- qVar !x !i = Var (V x (fromIntegral (countName' x env - i - 1)))- {-# inline qVar #-}-- quoteE :: Val a -> Expr Void a- quoteE = quote env- {-# inline quoteE #-}-- quoteBind :: Text -> Val a -> Expr Void a- quoteBind x = quote (NBind env x)- {-# inline quoteBind #-}-- qApp :: Expr Void a -> Val a -> Expr Void a- qApp t VPrimVar = t- qApp t u = App t (quoteE u)- {-# inline qApp #-}-- in case t of- VConst k -> Const k- VVar x i -> qVar x i- VApp t u -> quoteE t `qApp` u- VLam a (freshCl -> (x, v, t)) -> Lam x (quoteE a) (quoteBind x (inst t v))- VHLam i t -> case i of- Typed (fresh -> (x, v)) a -> Lam x (quoteE a) (quoteBind x (t v))- Prim -> quote env (t VPrimVar)- NaturalFoldCl{} -> quote env (t VPrimVar)- ListFoldCl{} -> quote env (t VPrimVar)- OptionalFoldCl{} -> quote env (t VPrimVar)-- VPi a (freshCl -> (x, v, b)) -> Pi x (quoteE a) (quoteBind x (inst b v))- VHPi (fresh -> (x, v)) a b -> Pi x (quoteE a) (quoteBind x (b v))-- VBool -> Bool- VBoolLit b -> BoolLit b- VBoolAnd t u -> BoolAnd (quoteE t) (quoteE u)- VBoolOr t u -> BoolOr (quoteE t) (quoteE u)- VBoolEQ t u -> BoolEQ (quoteE t) (quoteE u)- VBoolNE t u -> BoolNE (quoteE t) (quoteE u)- VBoolIf t u v -> BoolIf (quoteE t) (quoteE u) (quoteE v)-- VNatural -> Natural- VNaturalLit n -> NaturalLit n- VNaturalFold a t u v -> NaturalFold `qApp` a `qApp` t `qApp` u `qApp` v- VNaturalBuild t -> NaturalBuild `qApp` t- VNaturalIsZero t -> NaturalIsZero `qApp` t- VNaturalEven t -> NaturalEven `qApp` t- VNaturalOdd t -> NaturalOdd `qApp` t- VNaturalToInteger t -> NaturalToInteger `qApp` t- VNaturalShow t -> NaturalShow `qApp` t- VNaturalPlus t u -> NaturalPlus (quoteE t) (quoteE u)- VNaturalTimes t u -> NaturalTimes (quoteE t) (quoteE u)-- VInteger -> Integer- VIntegerLit n -> IntegerLit n- VIntegerShow t -> IntegerShow `qApp` t- VIntegerToDouble t -> IntegerToDouble `qApp` t-- VDouble -> Double- VDoubleLit n -> DoubleLit n- VDoubleShow t -> DoubleShow `qApp` t-- VText -> Text- VTextLit (VChunks xys z) -> TextLit (Chunks ((quoteE <$>) <$> xys) z)- VTextAppend t u -> TextAppend (quoteE t) (quoteE u)- VTextShow t -> TextShow `qApp` t-- VList t -> List `qApp` t- VListLit ma ts -> ListLit (quoteE <$> ma) (quoteE <$> ts)- VListAppend t u -> ListAppend (quoteE t) (quoteE u)- VListBuild a t -> ListBuild `qApp` a `qApp` t- VListFold a l t u v -> ListFold `qApp` a `qApp` l `qApp` t `qApp` u `qApp` v- VListLength a t -> ListLength `qApp` a `qApp` t- VListHead a t -> ListHead `qApp` a `qApp` t- VListLast a t -> ListLast `qApp` a `qApp` t- VListIndexed a t -> ListIndexed `qApp` a `qApp` t- VListReverse a t -> ListReverse `qApp` a `qApp` t-- VOptional a -> Optional `qApp` a- VSome t -> Some (quoteE t)- VNone t -> None `qApp` t- VOptionalFold a o t u v -> OptionalFold `qApp` a `qApp` o `qApp` t `qApp` u `qApp` v- VOptionalBuild a t -> OptionalBuild `qApp` a `qApp` t- VRecord m -> Record (quoteE <$> m)- VRecordLit m -> RecordLit (quoteE <$> m)- VUnion m -> Union ((quoteE <$>) <$> m)- VUnionLit k v m -> UnionLit k (quoteE v) ((quoteE <$>) <$> m)- VCombine t u -> Combine (quoteE t) (quoteE u)- VCombineTypes t u -> CombineTypes (quoteE t) (quoteE u)- VPrefer t u -> Prefer (quoteE t) (quoteE u)- VMerge t u ma -> Merge (quoteE t) (quoteE u) (quoteE <$> ma)- VField t k -> Field (quoteE t) k- VProject t p -> Project (quoteE t) (fmap quoteE p)- VInject m k Nothing -> Field (Union ((quoteE <$>) <$> m)) k- VInject m k (Just t) -> Field (Union ((quoteE <$>) <$> m)) k `qApp` t- VEmbed a -> Embed a- VPrimVar -> error errorMsg---- Normalization--------------------------------------------------------------------------------------------------------- | Normalize an expression in an environment of values. Any variable pointing out of--- the environment is treated as opaque free variable.-nf :: Eq a => Env a -> Expr s a -> Expr t a-nf !env = coeExprVoid . quote (envNames env) . eval env . denote---- | Normalize an expression in an empty environment.-nfEmpty :: Eq a => Expr s a -> Expr t a-nfEmpty = nf Empty---- Alpha-renaming------------------------------------------------------------------------------------- | Rename all binders to "_".-alphaNormalize :: Expr s a -> Expr s a-alphaNormalize = goEnv NEmpty where-- goVar :: Names -> Text -> Integer -> Expr s a- goVar e topX topI = go 0 e topI where- go !acc (NBind env x) !i- | x == topX = if i == 0 then Var (V "_" acc) else go (acc + 1) env (i - 1)- | otherwise = go (acc + 1) env i- go acc NEmpty i = Var (V topX i)-- goEnv :: Names -> Expr s a -> Expr s a- goEnv !e t = let-- go = goEnv e- goBind x = goEnv (NBind e x)- goChunks (Chunks ts x) = Chunks ((go <$>) <$> ts) x-- in case t of- Const k -> Const k- Var (V x i) -> goVar e x i- Lam x t u -> Lam "_" (go t) (goBind x u)- Pi x a b -> Pi "_" (go a) (goBind x b)- App t u -> App (go t) (go u)-- Let (b :| bs) u ->- let Binding x a t = b-- nil = (NBind e x, Binding "_" (goEnv e <$> a) (goEnv e t) :| [])-- snoc (e, bs) (Binding x a t) =- (NBind e x, cons (Binding "_" (goEnv e <$> a) (goEnv e t)) bs)-- (e', Data.List.NonEmpty.reverse -> bs') = foldl' snoc nil bs-- in Let bs' (goEnv e' u)-- Annot t u -> Annot (go t) (go u)- Bool -> Bool- BoolLit b -> BoolLit b- BoolAnd t u -> BoolAnd (go t) (go u)- BoolOr t u -> BoolOr (go t) (go u)- BoolEQ t u -> BoolEQ (go t) (go u)- BoolNE t u -> BoolNE (go t) (go u)- BoolIf b t f -> BoolIf (go b) (go t) (go f)- Natural -> Natural- NaturalLit n -> NaturalLit n- NaturalFold -> NaturalFold- NaturalBuild -> NaturalBuild- NaturalIsZero -> NaturalIsZero- NaturalEven -> NaturalEven- NaturalOdd -> NaturalOdd- NaturalToInteger -> NaturalToInteger- NaturalShow -> NaturalShow- NaturalPlus t u -> NaturalPlus (go t) (go u)- NaturalTimes t u -> NaturalTimes (go t) (go u)- Integer -> Integer- IntegerLit n -> IntegerLit n- IntegerShow -> IntegerShow- IntegerToDouble -> IntegerToDouble- Double -> Double- DoubleLit n -> DoubleLit n- DoubleShow -> DoubleShow- Text -> Text- TextLit cs -> TextLit (goChunks cs)- TextAppend t u -> TextAppend (go t) (go u)- TextShow -> TextShow- List -> List- ListLit ma ts -> ListLit (go <$> ma) (go <$> ts)- ListAppend t u -> ListAppend (go t) (go u)- ListBuild -> ListBuild- ListFold -> ListFold- ListLength -> ListLength- ListHead -> ListHead- ListLast -> ListLast- ListIndexed -> ListIndexed- ListReverse -> ListReverse- Optional -> Optional- OptionalLit a mt -> OptionalLit (go a) (go <$> mt)- Some t -> Some (go t)- None -> None- OptionalFold -> OptionalFold- OptionalBuild -> OptionalBuild- Record kts -> Record (go <$> kts)- RecordLit kts -> RecordLit (go <$> kts)- Union kts -> Union ((go <$>) <$> kts)- UnionLit k v kts -> UnionLit k (go v) ((go <$>) <$> kts)- Combine t u -> Combine (go t) (go u)- CombineTypes t u -> CombineTypes (go t) (go u)- Prefer t u -> Prefer (go t) (go u)- Merge x y ma -> Merge (go x) (go y) (go <$> ma)- Field t k -> Field (go t) k- Project t ks -> Project (go t) ks- Note s e -> Note s (go e)- ImportAlt t u -> ImportAlt (go t) (go u)- Embed a -> Embed a+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-}++{-| Eval-apply environment machine with conversion checking and quoting to+ normal forms. Fairly similar to GHCI's STG machine algorithmically, but much+ simpler, with no known call optimization or environment trimming.++ Potential optimizations without changing Expr:++ * In conversion checking, get non-shadowing variables not by linear+ Env-walking, but by keeping track of Env size, and generating names which+ are known to be illegal as source-level names (to rule out shadowing).++ * Use HashMap Text chunks for large let-definitions blocks. "Large" vs+ "Small" is fairly cheap to determine at evaluation time.++ Potential optimizations with changing Expr:++ * Use actual full de Bruijn indices in Var instead of Text counting indices.+ Then, we'd switch to full de Bruijn levels in Val as well, and use proper+ constant time non-shadowing name generation.+-}++module Dhall.Eval (+ judgmentallyEqual+ , normalize+ , alphaNormalize+ , eval+ , quote+ , envNames+ , countNames+ , conv+ , toVHPi+ , Closure(..)+ , Names(..)+ , Environment(..)+ , Val(..)+ , (~>)+ , textShow+ , dateShow+ , timeShow+ , timezoneShow+ ) where++import Data.Bifunctor (first)+import Data.ByteString (ByteString)+import Data.Foldable (foldr', toList)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Sequence (Seq, ViewL (..), ViewR (..))+import Data.Text (Text)+import Data.Time (Day, TimeOfDay (..), TimeZone)+import Data.Void (Void)+import Dhall.Map (Map)+import Dhall.Set (Set)+import GHC.Natural (Natural)+import Prelude hiding (succ)++import Dhall.Syntax+ ( Binding (..)+ , Chunks (..)+ , Const (..)+ , DhallDouble (..)+ , Expr (..)+ , FunctionBinding (..)+ , PreferAnnotation (..)+ , RecordField (..)+ , Var (..)+ , WithComponent (..)+ )++import qualified Data.Char+import qualified Data.Sequence as Sequence+import qualified Data.Set+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Dhall.Map as Map+import qualified Dhall.Set+import qualified Dhall.Syntax as Syntax+import qualified Text.Printf as Printf++data Environment a+ = Empty+ | Skip !(Environment a) {-# UNPACK #-} !Text+ | Extend !(Environment a) {-# UNPACK #-} !Text (Val a)++deriving instance (Show a, Show (Val a -> Val a)) => Show (Environment a)++errorMsg :: String+errorMsg = unlines+ [ _ERROR <> ": Compiler bug "+ , " "+ , "An ill-typed expression was encountered during normalization. "+ , "Explanation: This error message means that there is a bug in the Dhall compiler."+ , "You didn't do anything wrong, but if you would like to see this problem fixed "+ , "then you should report the bug at: "+ , " "+ , "https://github.com/dhall-lang/dhall-haskell/issues "+ ]+ where+ _ERROR :: String+ _ERROR = "\ESC[1;31mError\ESC[0m"+++data Closure a = Closure !Text !(Environment a) !(Expr Void a)++deriving instance (Show a, Show (Val a -> Val a)) => Show (Closure a)++data VChunks a = VChunks ![(Text, Val a)] !Text++deriving instance (Show a, Show (Val a -> Val a)) => Show (VChunks a)++instance Semigroup (VChunks a) where+ VChunks xys z <> VChunks [] z' = VChunks xys (z <> z')+ VChunks xys z <> VChunks ((x', y'):xys') z' = VChunks (xys ++ (z <> x', y'):xys') z'++instance Monoid (VChunks a) where+ mempty = VChunks [] mempty++{-| Some information is lost when `eval` converts a `Lam` or a built-in function+ from the `Expr` type to a `VHLam` of the `Val` type and `quote` needs that+ information in order to reconstruct an equivalent `Expr`. This `HLamInfo`+ type holds that extra information necessary to perform that reconstruction+-}+data HLamInfo a+ = Prim+ -- ^ Don't store any information+ | Typed !Text (Val a)+ -- ^ Store the original name and type of the variable bound by the `Lam`+ | NaturalSubtractZero+ -- ^ The original function was a @Natural/subtract 0@. We need to preserve+ -- this information in case the @Natural/subtract@ ends up not being fully+ -- saturated, in which case we need to recover the unsaturated built-in+ | TextReplaceEmpty+ -- ^ The original function was a @Text/replace ""@+ | TextReplaceEmptyArgument (Val a)+ -- ^ The original function was a @Text/replace "" replacement@++deriving instance (Show a, Show (Val a -> Val a)) => Show (HLamInfo a)++pattern VPrim :: (Val a -> Val a) -> Val a+pattern VPrim f = VHLam Prim f++toVHPi :: Eq a => Val a -> Maybe (Text, Val a, Val a -> Val a)+toVHPi (VPi a b@(Closure x _ _)) = Just (x, a, instantiate b)+toVHPi (VHPi x a b ) = Just (x, a, b)+toVHPi _ = Nothing+{-# INLINABLE toVHPi #-}++data Val a+ = VConst !Const+ | VVar !Text !Int+ | VPrimVar+ | VApp !(Val a) !(Val a)++ | VLam (Val a) {-# UNPACK #-} !(Closure a)+ | VHLam !(HLamInfo a) !(Val a -> Val a)++ | VPi (Val a) {-# UNPACK #-} !(Closure a)+ | VHPi !Text (Val a) !(Val a -> Val a)++ | VBool+ | VBoolLit !Bool+ | VBoolAnd !(Val a) !(Val a)+ | VBoolOr !(Val a) !(Val a)+ | VBoolEQ !(Val a) !(Val a)+ | VBoolNE !(Val a) !(Val a)+ | VBoolIf !(Val a) !(Val a) !(Val a)++ | VBytes+ | VBytesLit ByteString++ | VNatural+ | VNaturalLit !Natural+ | VNaturalFold !(Val a) !(Val a) !(Val a) !(Val a)+ | VNaturalBuild !(Val a)+ | VNaturalIsZero !(Val a)+ | VNaturalEven !(Val a)+ | VNaturalOdd !(Val a)+ | VNaturalToInteger !(Val a)+ | VNaturalShow !(Val a)+ | VNaturalSubtract !(Val a) !(Val a)+ | VNaturalPlus !(Val a) !(Val a)+ | VNaturalTimes !(Val a) !(Val a)++ | VInteger+ | VIntegerLit !Integer+ | VIntegerClamp !(Val a)+ | VIntegerNegate !(Val a)+ | VIntegerShow !(Val a)+ | VIntegerToDouble !(Val a)++ | VDouble+ | VDoubleLit !DhallDouble+ | VDoubleShow !(Val a)++ | VText+ | VTextLit !(VChunks a)+ | VTextAppend !(Val a) !(Val a)+ | VTextShow !(Val a)+ | VTextReplace !(Val a) !(Val a) !(Val a)++ | VDate+ | VDateLiteral Time.Day+ | VDateShow !(Val a)+ | VTime+ | VTimeLiteral Time.TimeOfDay Word+ | VTimeShow !(Val a)+ | VTimeZone+ | VTimeZoneLiteral Time.TimeZone+ | VTimeZoneShow !(Val a)++ | VList !(Val a)+ | VListLit !(Maybe (Val a)) !(Seq (Val a))+ | VListAppend !(Val a) !(Val a)+ | VListBuild (Val a) !(Val a)+ | VListFold (Val a) !(Val a) !(Val a) !(Val a) !(Val a)+ | VListLength (Val a) !(Val a)+ | VListHead (Val a) !(Val a)+ | VListLast (Val a) !(Val a)+ | VListIndexed (Val a) !(Val a)+ | VListReverse (Val a) !(Val a)++ | VOptional (Val a)+ | VSome (Val a)+ | VNone (Val a)+ | VRecord !(Map Text (Val a))+ | VRecordLit !(Map Text (Val a))+ | VUnion !(Map Text (Maybe (Val a)))+ | VCombine !(Maybe Text) !(Val a) !(Val a)+ | VCombineTypes !(Val a) !(Val a)+ | VPrefer !(Val a) !(Val a)+ | VMerge !(Val a) !(Val a) !(Maybe (Val a))+ | VToMap !(Val a) !(Maybe (Val a))+ | VShowConstructor !(Val a)+ | VField !(Val a) !Text+ | VInject !(Map Text (Maybe (Val a))) !Text !(Maybe (Val a))+ | VProject !(Val a) !(Either (Set Text) (Val a))+ | VAssert !(Val a)+ | VEquivalent !(Val a) !(Val a)+ | VWith !(Val a) (NonEmpty WithComponent) !(Val a)+ | VEmbed a++-- | For use with "Text.Show.Functions".+deriving instance (Show a, Show (Val a -> Val a)) => Show (Val a)++(~>) :: Val a -> Val a -> Val a+(~>) a b = VHPi "_" a (\_ -> b)+{-# INLINE (~>) #-}++infixr 5 ~>++countEnvironment :: Text -> Environment a -> Int+countEnvironment x = go (0 :: Int)+ where+ go !acc Empty = acc+ go acc (Skip env x' ) = go (if x == x' then acc + 1 else acc) env+ go acc (Extend env x' _) = go (if x == x' then acc + 1 else acc) env++instantiate :: Eq a => Closure a -> Val a -> Val a+instantiate (Closure x env t) !u = eval (Extend env x u) t+{-# INLINE instantiate #-}++-- Out-of-env variables have negative de Bruijn levels.+vVar :: Environment a -> Var -> Val a+vVar env0 (V x i0) = go env0 i0+ where+ go (Extend env x' v) i+ | x == x' =+ if i == 0 then v else go env (i - 1)+ | otherwise =+ go env i+ go (Skip env x') i+ | x == x' =+ if i == 0 then VVar x (countEnvironment x env) else go env (i - 1)+ | otherwise =+ go env i+ go Empty i =+ VVar x (negate i - 1)++vApp :: Eq a => Val a -> Val a -> Val a+vApp !t !u =+ case t of+ VLam _ t' -> instantiate t' u+ VHLam _ t' -> t' u+ t' -> VApp t' u+{-# INLINE vApp #-}++vPrefer :: Eq a => Environment a -> Val a -> Val a -> Val a+vPrefer env t u =+ case (t, u) of+ (VRecordLit m, u') | null m ->+ u'+ (t', VRecordLit m) | null m ->+ t'+ (VRecordLit m, VRecordLit m') ->+ VRecordLit (Map.union m' m)+ (t', u') | conv env t' u' ->+ t'+ (t', u') ->+ VPrefer t' u'+{-# INLINE vPrefer #-}++vCombine :: Maybe Text -> Val a -> Val a -> Val a+vCombine mk t u =+ case (t, u) of+ (VRecordLit m, u') | null m ->+ u'+ (t', VRecordLit m) | null m ->+ t'+ (VRecordLit m, VRecordLit m') ->+ VRecordLit (Map.unionWith (vCombine Nothing) m m')+ (t', u') ->+ VCombine mk t' u'++vCombineTypes :: Val a -> Val a -> Val a+vCombineTypes t u =+ case (t, u) of+ (VRecord m, u') | null m ->+ u'+ (t', VRecord m) | null m ->+ t'+ (VRecord m, VRecord m') ->+ VRecord (Map.unionWith vCombineTypes m m')+ (t', u') ->+ VCombineTypes t' u'++vListAppend :: Val a -> Val a -> Val a+vListAppend t u =+ case (t, u) of+ (VListLit _ xs, u') | null xs ->+ u'+ (t', VListLit _ ys) | null ys ->+ t'+ (VListLit t' xs, VListLit _ ys) ->+ VListLit t' (xs <> ys)+ (t', u') ->+ VListAppend t' u'+{-# INLINE vListAppend #-}++vNaturalPlus :: Val a -> Val a -> Val a+vNaturalPlus t u =+ case (t, u) of+ (VNaturalLit 0, u') ->+ u'+ (t', VNaturalLit 0) ->+ t'+ (VNaturalLit m, VNaturalLit n) ->+ VNaturalLit (m + n)+ (t', u') ->+ VNaturalPlus t' u'+{-# INLINE vNaturalPlus #-}++vField :: Val a -> Text -> Val a+vField t0 k = go t0+ where+ go = \case+ VUnion m -> case Map.lookup k m of+ Just (Just _) -> VPrim $ \ ~u -> VInject m k (Just u)+ Just Nothing -> VInject m k Nothing+ _ -> error errorMsg+ VRecordLit m+ | Just v <- Map.lookup k m -> v+ | otherwise -> error errorMsg+ VProject t _ -> go t+ VPrefer (VRecordLit m) r -> case Map.lookup k m of+ Just v -> VField (VPrefer (singletonVRecordLit v) r) k+ Nothing -> go r+ VPrefer l (VRecordLit m) -> case Map.lookup k m of+ Just v -> v+ Nothing -> go l+ VCombine mk (VRecordLit m) r -> case Map.lookup k m of+ Just v -> VField (VCombine mk (singletonVRecordLit v) r) k+ Nothing -> go r+ VCombine mk l (VRecordLit m) -> case Map.lookup k m of+ Just v -> VField (VCombine mk l (singletonVRecordLit v)) k+ Nothing -> go l+ t -> VField t k++ singletonVRecordLit v = VRecordLit (Map.singleton k v)+{-# INLINE vField #-}++vTextReplace :: Text -> Val a -> Text -> VChunks a+vTextReplace needle replacement haystack = go haystack+ where+ go t+ | Text.null suffix = VChunks [] t+ | otherwise =+ let remainder = Text.drop (Text.length needle) suffix++ rest = go remainder++ in case replacement of+ VTextLit replacementChunks ->+ VChunks [] prefix <> replacementChunks <> rest+ _ ->+ VChunks [(prefix, replacement)] "" <> rest+ where+ (prefix, suffix) = Text.breakOn needle t++vProjectByFields :: Eq a => Environment a -> Val a -> Set Text -> Val a+vProjectByFields env t ks =+ if null ks+ then VRecordLit mempty+ else case t of+ VRecordLit kvs ->+ let kvs' = Map.restrictKeys kvs (Dhall.Set.toSet ks)+ in VRecordLit kvs'+ VProject t' _ ->+ vProjectByFields env t' ks+ VPrefer l (VRecordLit kvs) ->+ let ksSet = Dhall.Set.toSet ks++ kvs' = Map.restrictKeys kvs ksSet++ ks' =+ Dhall.Set.fromSet+ (Data.Set.difference ksSet (Map.keysSet kvs'))++ in vPrefer env (vProjectByFields env l ks') (VRecordLit kvs')+ t' ->+ VProject t' (Left ks)++vWith :: Val a -> NonEmpty WithComponent -> Val a -> Val a+vWith (VRecordLit kvs) (WithLabel k :| [] ) v = VRecordLit (Map.insert k v kvs)+vWith (VRecordLit kvs) (WithLabel k₀ :| k₁ : ks) v = VRecordLit (Map.insert k₀ e₂ kvs)+ where+ e₁ =+ case Map.lookup k₀ kvs of+ Nothing -> VRecordLit mempty+ Just e₁' -> e₁'++ e₂ = vWith e₁ (k₁ :| ks) v+vWith (VNone _T) (WithQuestion :| _ ) _ = VNone _T+vWith (VSome _) (WithQuestion :| [] ) v = VSome v+vWith (VSome t) (WithQuestion :| k₁ : ks) v = VSome (vWith t (k₁ :| ks) v)+vWith e₀ ks v₀ = VWith e₀ ks v₀++eval :: forall a. Eq a => Environment a -> Expr Void a -> Val a+eval !env t0 =+ case t0 of+ Const k ->+ VConst k+ Var v ->+ vVar env v+ Lam _ (FunctionBinding { functionBindingVariable = x, functionBindingAnnotation = a }) t ->+ VLam (eval env a) (Closure x env t)+ Pi _ x a b ->+ VPi (eval env a) (Closure x env b)+ App t u ->+ vApp (eval env t) (eval env u)+ Let (Binding _ x _ _mA _ a) b ->+ let !env' = Extend env x (eval env a)+ in eval env' b+ Annot t _ ->+ eval env t+ Bool ->+ VBool+ BoolLit b ->+ VBoolLit b+ BoolAnd t u ->+ case (eval env t, eval env u) of+ (VBoolLit True, u') -> u'+ (VBoolLit False, _) -> VBoolLit False+ (t', VBoolLit True) -> t'+ (_ , VBoolLit False) -> VBoolLit False+ (t', u') | conv env t' u' -> t'+ (t', u') -> VBoolAnd t' u'+ BoolOr t u ->+ case (eval env t, eval env u) of+ (VBoolLit False, u') -> u'+ (VBoolLit True, _) -> VBoolLit True+ (t', VBoolLit False) -> t'+ (_ , VBoolLit True) -> VBoolLit True+ (t', u') | conv env t' u' -> t'+ (t', u') -> VBoolOr t' u'+ BoolEQ t u ->+ case (eval env t, eval env u) of+ (VBoolLit True, u') -> u'+ (t', VBoolLit True) -> t'+ (t', u') | conv env t' u' -> VBoolLit True+ (t', u') -> VBoolEQ t' u'+ BoolNE t u ->+ case (eval env t, eval env u) of+ (VBoolLit False, u') -> u'+ (t', VBoolLit False) -> t'+ (t', u') | conv env t' u' -> VBoolLit False+ (t', u') -> VBoolNE t' u'+ BoolIf b t f ->+ case (eval env b, eval env t, eval env f) of+ (VBoolLit True, t', _ ) -> t'+ (VBoolLit False, _ , f') -> f'+ (b', VBoolLit True, VBoolLit False) -> b'+ (_, t', f') | conv env t' f' -> t'+ (b', t', f') -> VBoolIf b' t' f'+ Bytes ->+ VBytes+ BytesLit b ->+ VBytesLit b+ Natural ->+ VNatural+ NaturalLit n ->+ VNaturalLit n+ NaturalFold ->+ VPrim $ \n ->+ VPrim $ \natural ->+ VPrim $ \succ ->+ VPrim $ \zero ->+ let inert = VNaturalFold n natural succ zero+ in case zero of+ VPrimVar -> inert+ _ -> case succ of+ VPrimVar -> inert+ _ -> case natural of+ VPrimVar -> inert+ _ -> case n of+ VNaturalLit n' ->+ -- Use an `Integer` for the loop, due to the+ -- following issue:+ --+ -- https://github.com/ghcjs/ghcjs/issues/782+ go zero (fromIntegral n' :: Integer) where+ go !acc 0 = acc+ go acc m =+ -- Detect a shortcut: if succ acc == acc then return acc immediately.+ let next = vApp succ acc+ in if conv env next acc then acc else go next (m - 1)+ _ -> inert+ NaturalBuild ->+ VPrim $ \case+ VPrimVar ->+ VNaturalBuild VPrimVar+ t -> t+ `vApp` VNatural+ `vApp` VHLam (Typed "n" VNatural) (\n -> vNaturalPlus n (VNaturalLit 1))+ `vApp` VNaturalLit 0++ NaturalIsZero -> VPrim $ \case+ VNaturalLit n -> VBoolLit (n == 0)+ n -> VNaturalIsZero n+ NaturalEven -> VPrim $ \case+ VNaturalLit n -> VBoolLit (even n)+ n -> VNaturalEven n+ NaturalOdd -> VPrim $ \case+ VNaturalLit n -> VBoolLit (odd n)+ n -> VNaturalOdd n+ NaturalToInteger -> VPrim $ \case+ VNaturalLit n -> VIntegerLit (fromIntegral n)+ n -> VNaturalToInteger n+ NaturalShow -> VPrim $ \case+ VNaturalLit n -> VTextLit (VChunks [] (Text.pack (show n)))+ n -> VNaturalShow n+ NaturalSubtract -> VPrim $ \case+ VNaturalLit 0 ->+ VHLam NaturalSubtractZero id+ x@(VNaturalLit m) ->+ VPrim $ \case+ VNaturalLit n+ | n >= m ->+ -- Use an `Integer` for the subtraction, due to the+ -- following issue:+ --+ -- https://github.com/ghcjs/ghcjs/issues/782+ VNaturalLit (fromIntegral (subtract (fromIntegral m :: Integer) (fromIntegral n :: Integer)))+ | otherwise -> VNaturalLit 0+ y -> VNaturalSubtract x y+ x ->+ VPrim $ \case+ VNaturalLit 0 -> VNaturalLit 0+ y | conv env x y -> VNaturalLit 0+ y -> VNaturalSubtract x y+ NaturalPlus t u ->+ vNaturalPlus (eval env t) (eval env u)+ NaturalTimes t u ->+ case (eval env t, eval env u) of+ (VNaturalLit 1, u' ) -> u'+ (t' , VNaturalLit 1) -> t'+ (VNaturalLit 0, _ ) -> VNaturalLit 0+ (_ , VNaturalLit 0) -> VNaturalLit 0+ (VNaturalLit m, VNaturalLit n) -> VNaturalLit (m * n)+ (t' , u' ) -> VNaturalTimes t' u'+ Integer ->+ VInteger+ IntegerLit n ->+ VIntegerLit n+ IntegerClamp ->+ VPrim $ \case+ VIntegerLit n+ | 0 <= n -> VNaturalLit (fromInteger n)+ | otherwise -> VNaturalLit 0+ n -> VIntegerClamp n+ IntegerNegate ->+ VPrim $ \case+ VIntegerLit n -> VIntegerLit (negate n)+ n -> VIntegerNegate n+ IntegerShow ->+ VPrim $ \case+ VIntegerLit n+ | 0 <= n -> VTextLit (VChunks [] (Text.pack ('+':show n)))+ | otherwise -> VTextLit (VChunks [] (Text.pack (show n)))+ n -> VIntegerShow n+ IntegerToDouble ->+ VPrim $ \case+ VIntegerLit n -> VDoubleLit (DhallDouble (read (show n)))+ -- `(read . show)` is used instead of `fromInteger`+ -- because `read` uses the correct rounding rule.+ -- See https://gitlab.haskell.org/ghc/ghc/issues/17231.+ n -> VIntegerToDouble n+ Double ->+ VDouble+ DoubleLit n ->+ VDoubleLit n+ DoubleShow ->+ VPrim $ \case+ VDoubleLit (DhallDouble n) -> VTextLit (VChunks [] (Text.pack (show n)))+ n -> VDoubleShow n+ Text ->+ VText+ TextLit cs ->+ case evalChunks cs of+ VChunks [("", t)] "" -> t+ vcs -> VTextLit vcs+ TextAppend t u ->+ eval env (TextLit (Chunks [("", t), ("", u)] ""))+ TextShow ->+ VPrim $ \case+ VTextLit (VChunks [] x) -> VTextLit (VChunks [] (textShow x))+ t -> VTextShow t+ TextReplace ->+ VPrim $ \needle ->+ let hLamInfo0 = case needle of+ VTextLit (VChunks [] "") -> TextReplaceEmpty+ _ -> Prim++ in VHLam hLamInfo0 $ \replacement ->+ let hLamInfo1 = case needle of+ VTextLit (VChunks [] "") ->+ TextReplaceEmptyArgument replacement+ _ ->+ Prim+ in VHLam hLamInfo1 $ \haystack ->+ case needle of+ VTextLit (VChunks [] "") ->+ haystack++ VTextLit (VChunks [] needleText) ->+ case haystack of+ VTextLit (VChunks [] haystackText) ->+ case replacement of+ VTextLit (VChunks [] replacementText) ->+ VTextLit $ VChunks []+ (Text.replace+ needleText+ replacementText+ haystackText+ )+ _ ->+ VTextLit+ (vTextReplace+ needleText+ replacement+ haystackText+ )+ _ ->+ VTextReplace needle replacement haystack+ _ ->+ VTextReplace needle replacement haystack+ Date ->+ VDate+ DateLiteral d ->+ VDateLiteral d+ DateShow ->+ VPrim $ \case+ VDateLiteral d -> VTextLit (VChunks [] (dateShow d))+ t -> VDateShow t+ Time ->+ VTime+ TimeLiteral t p ->+ VTimeLiteral t p+ TimeShow ->+ VPrim $ \case+ VTimeLiteral d p -> VTextLit (VChunks [] (timeShow d p))+ t -> VTimeShow t+ TimeZone ->+ VTimeZone+ TimeZoneLiteral z ->+ VTimeZoneLiteral z+ TimeZoneShow ->+ VPrim $ \case+ VTimeZoneLiteral d -> VTextLit (VChunks [] (timezoneShow d))+ t -> VTimeZoneShow t+ List ->+ VPrim VList+ ListLit ma ts ->+ VListLit (fmap (eval env) ma) (fmap (eval env) ts)+ ListAppend t u ->+ vListAppend (eval env t) (eval env u)+ ListBuild ->+ VPrim $ \a ->+ VPrim $ \case+ VPrimVar ->+ VListBuild a VPrimVar+ t -> t+ `vApp` VList a+ `vApp` VHLam (Typed "a" a) (\x ->+ VHLam (Typed "as" (VList a)) (\as ->+ vListAppend (VListLit Nothing (pure x)) as))+ `vApp` VListLit (Just (VList a)) mempty++ ListFold ->+ VPrim $ \a ->+ VPrim $ \as ->+ VPrim $ \list ->+ VPrim $ \cons ->+ VPrim $ \nil ->+ let inert = VListFold a as list cons nil+ in case nil of+ VPrimVar -> inert+ _ -> case cons of+ VPrimVar -> inert+ _ -> case list of+ VPrimVar -> inert+ _ -> case a of+ VPrimVar -> inert+ _ -> case as of+ VListLit _ as' ->+ foldr' (\x b -> cons `vApp` x `vApp` b) nil as'+ _ -> inert+ ListLength ->+ VPrim $ \ a ->+ VPrim $ \case+ VListLit _ as -> VNaturalLit (fromIntegral (Sequence.length as))+ as -> VListLength a as+ ListHead ->+ VPrim $ \ a ->+ VPrim $ \case+ VListLit _ as ->+ case Sequence.viewl as of+ y :< _ -> VSome y+ _ -> VNone a+ as ->+ VListHead a as+ ListLast ->+ VPrim $ \ a ->+ VPrim $ \case+ VListLit _ as ->+ case Sequence.viewr as of+ _ :> t -> VSome t+ _ -> VNone a+ as -> VListLast a as+ ListIndexed ->+ VPrim $ \ a ->+ VPrim $ \case+ VListLit _ as ->+ let a' =+ if null as+ then Just (VList (VRecord (Map.unorderedFromList [("index", VNatural), ("value", a)])))+ else Nothing++ as' =+ Sequence.mapWithIndex+ (\i t ->+ VRecordLit+ (Map.unorderedFromList+ [ ("index", VNaturalLit (fromIntegral i))+ , ("value", t)+ ]+ )+ )+ as++ in VListLit a' as'+ t ->+ VListIndexed a t+ ListReverse ->+ VPrim $ \ ~a ->+ VPrim $ \case+ VListLit t as | null as ->+ VListLit t as+ VListLit _ as ->+ VListLit Nothing (Sequence.reverse as)+ t ->+ VListReverse a t+ Optional ->+ VPrim VOptional+ Some t ->+ VSome (eval env t)+ None ->+ VPrim $ \ ~a -> VNone a+ Record kts ->+ VRecord (Map.sort (eval env . recordFieldValue <$> kts))+ RecordLit kts ->+ VRecordLit (Map.sort (eval env . recordFieldValue <$> kts))+ Union kts ->+ VUnion (Map.sort (fmap (fmap (eval env)) kts))+ Combine _ mk t u ->+ vCombine mk (eval env t) (eval env u)+ CombineTypes _ t u ->+ vCombineTypes (eval env t) (eval env u)+ Prefer _ _ t u ->+ vPrefer env (eval env t) (eval env u)+ RecordCompletion t u ->+ eval env (Annot (Prefer mempty PreferFromCompletion (Field t def) u) (Field t typ))+ where+ def = Syntax.makeFieldSelection "default"+ typ = Syntax.makeFieldSelection "Type"+ Merge x y ma ->+ case (eval env x, eval env y, fmap (eval env) ma) of+ (VRecordLit m, VInject _ k mt, _)+ | Just f <- Map.lookup k m -> maybe f (vApp f) mt+ | otherwise -> error errorMsg+ (VRecordLit m, VSome t, _)+ | Just f <- Map.lookup "Some" m -> vApp f t+ | otherwise -> error errorMsg+ (VRecordLit m, VNone _, _)+ | Just t <- Map.lookup "None" m -> t+ | otherwise -> error errorMsg+ (x', y', ma') -> VMerge x' y' ma'+ ToMap x ma ->+ case (eval env x, fmap (eval env) ma) of+ (VRecordLit m, ma'@(Just _)) | null m ->+ VListLit ma' Sequence.empty+ (VRecordLit m, _) ->+ let entry (k, v) =+ VRecordLit+ (Map.unorderedFromList+ [ ("mapKey", VTextLit $ VChunks [] k)+ , ("mapValue", v)+ ]+ )++ s = (Sequence.fromList . map entry . Map.toAscList) m++ in VListLit Nothing s+ (x', ma') ->+ VToMap x' ma'+ ShowConstructor x ->+ case eval env x of+ VInject m k _+ | Just _ <- Map.lookup k m -> VTextLit (VChunks [] k)+ | otherwise -> error errorMsg+ VSome _ -> VTextLit (VChunks [] "Some")+ VNone _ -> VTextLit (VChunks [] "None")+ x' -> VShowConstructor x'+ Field t (Syntax.fieldSelectionLabel -> k) ->+ vField (eval env t) k+ Project t (Left ks) ->+ vProjectByFields env (eval env t) (Dhall.Set.sort (Dhall.Set.fromList ks))+ Project t (Right e) ->+ case eval env e of+ VRecord kts ->+ vProjectByFields env (eval env t) (Dhall.Set.fromSet (Map.keysSet kts))+ e' ->+ VProject (eval env t) (Right e')+ Assert t ->+ VAssert (eval env t)+ Equivalent _ t u ->+ VEquivalent (eval env t) (eval env u)+ With e₀ ks v ->+ vWith (eval env e₀) ks (eval env v)+ Note _ e ->+ eval env e+ ImportAlt t _ ->+ eval env t+ Embed a ->+ VEmbed a+ where+ evalChunks :: Chunks Void a -> VChunks a+ evalChunks (Chunks xys z) = foldr' cons nil xys+ where+ cons (x, t) vcs =+ case eval env t of+ VTextLit vcs' -> VChunks [] x <> vcs' <> vcs+ t' -> VChunks [(x, t')] mempty <> vcs++ nil = VChunks [] z+ {-# INLINE evalChunks #-}++eqListBy :: (a -> a -> Bool) -> [a] -> [a] -> Bool+eqListBy f = go+ where+ go (x:xs) (y:ys) | f x y = go xs ys+ go [] [] = True+ go _ _ = False+{-# INLINE eqListBy #-}++eqMapsBy :: Ord k => (v -> v -> Bool) -> Map k v -> Map k v -> Bool+eqMapsBy f mL mR =+ Map.size mL == Map.size mR+ && eqListBy eq (Map.toAscList mL) (Map.toAscList mR)+ where+ eq (kL, vL) (kR, vR) = kL == kR && f vL vR+{-# INLINE eqMapsBy #-}++eqMaybeBy :: (a -> a -> Bool) -> Maybe a -> Maybe a -> Bool+eqMaybeBy f = go+ where+ go (Just x) (Just y) = f x y+ go Nothing Nothing = True+ go _ _ = False+{-# INLINE eqMaybeBy #-}++-- | Utility that powers the @Text/show@ built-in+textShow :: Text -> Text+textShow text = "\"" <> Text.concatMap f text <> "\""+ where+ f '"' = "\\\""+ f '$' = "\\u0024"+ f '\\' = "\\\\"+ f '\b' = "\\b"+ f '\n' = "\\n"+ f '\r' = "\\r"+ f '\t' = "\\t"+ f '\f' = "\\f"+ f c | c <= '\x1F' = Text.pack (Printf.printf "\\u%04x" (Data.Char.ord c))+ | otherwise = Text.singleton c++-- | Utility that powers the @Date/show@ built-in+dateShow :: Day -> Text+dateShow = Text.pack . Time.formatTime Time.defaultTimeLocale "%0Y-%m-%d"++-- | Utility that powers the @Time/show@ built-in+timeShow :: TimeOfDay -> Word -> Text+timeShow (TimeOfDay hh mm seconds) precision =+ Text.pack (Printf.printf "%02d:%02d:%02d" hh mm ss <> suffix)+ where+ magnitude :: Integer+ magnitude = 10 ^ precision++ (ss, fraction) =+ truncate (seconds * fromInteger magnitude) `divMod` magnitude++ suffix+ | precision == 0 = ""+ | otherwise = Printf.printf ".%0*d" precision fraction++-- | Utility that powers the @TimeZone/show@ built-in+timezoneShow :: TimeZone -> Text+timezoneShow = Text.pack . Time.formatTime Time.defaultTimeLocale "%Ez"++conv :: forall a. Eq a => Environment a -> Val a -> Val a -> Bool+conv !env t0 t0' =+ case (t0, t0') of+ (VConst k, VConst k') ->+ k == k'+ (VVar x i, VVar x' i') ->+ x == x' && i == i'+ (VLam _ (freshClosure -> (x, v, t)), VLam _ t' ) ->+ convSkip x (instantiate t v) (instantiate t' v)+ (VLam _ (freshClosure -> (x, v, t)), VHLam _ t') ->+ convSkip x (instantiate t v) (t' v)+ (VLam _ (freshClosure -> (x, v, t)), t' ) ->+ convSkip x (instantiate t v) (vApp t' v)+ (VHLam _ t, VLam _ (freshClosure -> (x, v, t'))) ->+ convSkip x (t v) (instantiate t' v)+ (VHLam _ t, VHLam _ t' ) ->+ let (x, v) = fresh "x" in convSkip x (t v) (t' v)+ (VHLam _ t, t' ) ->+ let (x, v) = fresh "x" in convSkip x (t v) (vApp t' v)+ (t, VLam _ (freshClosure -> (x, v, t'))) ->+ convSkip x (vApp t v) (instantiate t' v)+ (t, VHLam _ t' ) ->+ let (x, v) = fresh "x" in convSkip x (vApp t v) (t' v)+ (VApp t u, VApp t' u') ->+ conv env t t' && conv env u u'+ (VPi a b, VPi a' (freshClosure -> (x, v, b'))) ->+ conv env a a' && convSkip x (instantiate b v) (instantiate b' v)+ (VPi a b, VHPi (fresh -> (x, v)) a' b') ->+ conv env a a' && convSkip x (instantiate b v) (b' v)+ (VHPi _ a b, VPi a' (freshClosure -> (x, v, b'))) ->+ conv env a a' && convSkip x (b v) (instantiate b' v)+ (VHPi _ a b, VHPi (fresh -> (x, v)) a' b') ->+ conv env a a' && convSkip x (b v) (b' v)+ (VBool, VBool) ->+ True+ (VBoolLit b, VBoolLit b') ->+ b == b'+ (VBoolAnd t u, VBoolAnd t' u') ->+ conv env t t' && conv env u u'+ (VBoolOr t u, VBoolOr t' u') ->+ conv env t t' && conv env u u'+ (VBoolEQ t u, VBoolEQ t' u') ->+ conv env t t' && conv env u u'+ (VBoolNE t u, VBoolNE t' u') ->+ conv env t t' && conv env u u'+ (VBoolIf t u v, VBoolIf t' u' v') ->+ conv env t t' && conv env u u' && conv env v v'+ (VBytes, VBytes) ->+ True+ (VBytesLit l, VBytesLit r) ->+ l == r+ (VNatural, VNatural) ->+ True+ (VNaturalLit n, VNaturalLit n') ->+ n == n'+ (VNaturalFold t _ u v, VNaturalFold t' _ u' v') ->+ conv env t t' && conv env u u' && conv env v v'+ (VNaturalBuild t, VNaturalBuild t') ->+ conv env t t'+ (VNaturalIsZero t, VNaturalIsZero t') ->+ conv env t t'+ (VNaturalEven t, VNaturalEven t') ->+ conv env t t'+ (VNaturalOdd t, VNaturalOdd t') ->+ conv env t t'+ (VNaturalToInteger t, VNaturalToInteger t') ->+ conv env t t'+ (VNaturalShow t, VNaturalShow t') ->+ conv env t t'+ (VNaturalSubtract x y, VNaturalSubtract x' y') ->+ conv env x x' && conv env y y'+ (VNaturalPlus t u, VNaturalPlus t' u') ->+ conv env t t' && conv env u u'+ (VNaturalTimes t u, VNaturalTimes t' u') ->+ conv env t t' && conv env u u'+ (VInteger, VInteger) ->+ True+ (VIntegerLit t, VIntegerLit t') ->+ t == t'+ (VIntegerClamp t, VIntegerClamp t') ->+ conv env t t'+ (VIntegerNegate t, VIntegerNegate t') ->+ conv env t t'+ (VIntegerShow t, VIntegerShow t') ->+ conv env t t'+ (VIntegerToDouble t, VIntegerToDouble t') ->+ conv env t t'+ (VDouble, VDouble) ->+ True+ (VDoubleLit n, VDoubleLit n') ->+ n == n'+ (VDoubleShow t, VDoubleShow t') ->+ conv env t t'+ (VText, VText) ->+ True+ (VTextLit cs, VTextLit cs') ->+ convChunks cs cs'+ (VTextAppend t u, VTextAppend t' u') ->+ conv env t t' && conv env u u'+ (VTextShow t, VTextShow t') ->+ conv env t t'+ (VTextReplace a b c, VTextReplace a' b' c') ->+ conv env a a' && conv env b b' && conv env c c'+ (VDate, VDate) ->+ True+ (VDateLiteral l, VDateLiteral r) ->+ l == r+ (VDateShow t, VDateShow t') ->+ conv env t t'+ (VTime, VTime) ->+ True+ (VTimeLiteral tl pl, VTimeLiteral tr pr) ->+ tl == tr && pl == pr+ (VTimeShow t, VTimeShow t') ->+ conv env t t'+ (VTimeZone, VTimeZone) ->+ True+ (VTimeZoneLiteral l, VTimeZoneLiteral r) ->+ l == r+ (VTimeZoneShow t, VTimeZoneShow t') ->+ conv env t t'+ (VList a, VList a') ->+ conv env a a'+ (VListLit _ xs, VListLit _ xs') ->+ eqListBy (conv env) (toList xs) (toList xs')+ (VListAppend t u, VListAppend t' u') ->+ conv env t t' && conv env u u'+ (VListBuild _ t, VListBuild _ t') ->+ conv env t t'+ (VListLength a t, VListLength a' t') ->+ conv env a a' && conv env t t'+ (VListHead _ t, VListHead _ t') ->+ conv env t t'+ (VListLast _ t, VListLast _ t') ->+ conv env t t'+ (VListIndexed _ t, VListIndexed _ t') ->+ conv env t t'+ (VListReverse _ t, VListReverse _ t') ->+ conv env t t'+ (VListFold a l _ t u, VListFold a' l' _ t' u') ->+ conv env a a' && conv env l l' && conv env t t' && conv env u u'+ (VOptional a, VOptional a') ->+ conv env a a'+ (VSome t, VSome t') ->+ conv env t t'+ (VNone _, VNone _) ->+ True+ (VRecord m, VRecord m') ->+ eqMapsBy (conv env) m m'+ (VRecordLit m, VRecordLit m') ->+ eqMapsBy (conv env) m m'+ (VUnion m, VUnion m') ->+ eqMapsBy (eqMaybeBy (conv env)) m m'+ (VCombine _ t u, VCombine _ t' u') ->+ conv env t t' && conv env u u'+ (VCombineTypes t u, VCombineTypes t' u') ->+ conv env t t' && conv env u u'+ (VPrefer t u, VPrefer t' u') ->+ conv env t t' && conv env u u'+ (VMerge t u _, VMerge t' u' _) ->+ conv env t t' && conv env u u'+ (VToMap t _, VToMap t' _) ->+ conv env t t'+ (VShowConstructor t, VShowConstructor t') ->+ conv env t t'+ (VField t k, VField t' k') ->+ conv env t t' && k == k'+ (VProject t (Left ks), VProject t' (Left ks')) ->+ conv env t t' && ks == ks'+ (VProject t (Right e), VProject t' (Right e')) ->+ conv env t t' && conv env e e'+ (VAssert t, VAssert t') ->+ conv env t t'+ (VEquivalent t u, VEquivalent t' u') ->+ conv env t t' && conv env u u'+ (VInject m k mt, VInject m' k' mt') ->+ eqMapsBy (eqMaybeBy (conv env)) m m' && k == k' && eqMaybeBy (conv env) mt mt'+ (VEmbed a, VEmbed a') ->+ a == a'+ (_, _) ->+ False+ where+ fresh :: Text -> (Text, Val a)+ fresh x = (x, VVar x (countEnvironment x env))+ {-# INLINE fresh #-}++ freshClosure :: Closure a -> (Text, Val a, Closure a)+ freshClosure closure@(Closure x _ _) = (x, snd (fresh x), closure)+ {-# INLINE freshClosure #-}++ convChunks :: VChunks a -> VChunks a -> Bool+ convChunks (VChunks xys z) (VChunks xys' z') =+ eqListBy (\(x, y) (x', y') -> x == x' && conv env y y') xys xys' && z == z'+ {-# INLINE convChunks #-}++ convSkip :: Text -> Val a -> Val a -> Bool+ convSkip x = conv (Skip env x)+ {-# INLINE convSkip #-}++judgmentallyEqual :: Eq a => Expr s a -> Expr t a -> Bool+judgmentallyEqual (Syntax.denote -> t) (Syntax.denote -> u) =+ conv Empty (eval Empty t) (eval Empty u)+{-# INLINABLE judgmentallyEqual #-}++data Names+ = EmptyNames+ | Bind !Names {-# UNPACK #-} !Text+ deriving Show++envNames :: Environment a -> Names+envNames Empty = EmptyNames+envNames (Skip env x ) = Bind (envNames env) x+envNames (Extend env x _) = Bind (envNames env) x++countNames :: Text -> Names -> Int+countNames x = go 0+ where+ go !acc EmptyNames = acc+ go acc (Bind env x') = go (if x == x' then acc + 1 else acc) env++-- | Quote a value into beta-normal form.+quote :: forall a. Eq a => Names -> Val a -> Expr Void a+quote !env !t0 =+ case t0 of+ VConst k ->+ Const k+ VVar !x !i ->+ Var (V x (countNames x env - i - 1))+ VApp t u ->+ quote env t `qApp` u+ VLam a (freshClosure -> (x, v, t)) ->+ Lam+ mempty+ (Syntax.makeFunctionBinding x (quote env a))+ (quoteBind x (instantiate t v))+ VHLam i t ->+ case i of+ Typed (fresh -> (x, v)) a ->+ Lam mempty+ (Syntax.makeFunctionBinding x (quote env a))+ (quoteBind x (t v))+ Prim ->+ quote env (t VPrimVar)+ NaturalSubtractZero ->+ App NaturalSubtract (NaturalLit 0)+ TextReplaceEmpty ->+ App TextReplace (TextLit (Chunks [] ""))+ TextReplaceEmptyArgument replacement ->+ App (App TextReplace (TextLit (Chunks [] "")))+ (quote env replacement)++ VPi a (freshClosure -> (x, v, b)) ->+ Pi mempty x (quote env a) (quoteBind x (instantiate b v))+ VHPi (fresh -> (x, v)) a b ->+ Pi mempty x (quote env a) (quoteBind x (b v))+ VBool ->+ Bool+ VBoolLit b ->+ BoolLit b+ VBoolAnd t u ->+ BoolAnd (quote env t) (quote env u)+ VBoolOr t u ->+ BoolOr (quote env t) (quote env u)+ VBoolEQ t u ->+ BoolEQ (quote env t) (quote env u)+ VBoolNE t u ->+ BoolNE (quote env t) (quote env u)+ VBoolIf t u v ->+ BoolIf (quote env t) (quote env u) (quote env v)+ VBytes ->+ Bytes+ VBytesLit b ->+ BytesLit b+ VNatural ->+ Natural+ VNaturalLit n ->+ NaturalLit n+ VNaturalFold a t u v ->+ NaturalFold `qApp` a `qApp` t `qApp` u `qApp` v+ VNaturalBuild t ->+ NaturalBuild `qApp` t+ VNaturalIsZero t ->+ NaturalIsZero `qApp` t+ VNaturalEven t ->+ NaturalEven `qApp` t+ VNaturalOdd t ->+ NaturalOdd `qApp` t+ VNaturalToInteger t ->+ NaturalToInteger `qApp` t+ VNaturalShow t ->+ NaturalShow `qApp` t+ VNaturalPlus t u ->+ NaturalPlus (quote env t) (quote env u)+ VNaturalTimes t u ->+ NaturalTimes (quote env t) (quote env u)+ VNaturalSubtract x y ->+ NaturalSubtract `qApp` x `qApp` y+ VInteger ->+ Integer+ VIntegerLit n ->+ IntegerLit n+ VIntegerClamp t ->+ IntegerClamp `qApp` t+ VIntegerNegate t ->+ IntegerNegate `qApp` t+ VIntegerShow t ->+ IntegerShow `qApp` t+ VIntegerToDouble t ->+ IntegerToDouble `qApp` t+ VDouble ->+ Double+ VDoubleLit n ->+ DoubleLit n+ VDoubleShow t ->+ DoubleShow `qApp` t+ VText ->+ Text+ VTextLit (VChunks xys z) ->+ TextLit (Chunks (fmap (fmap (quote env)) xys) z)+ VTextAppend t u ->+ TextAppend (quote env t) (quote env u)+ VTextShow t ->+ TextShow `qApp` t+ VTextReplace a b c ->+ TextReplace `qApp` a `qApp` b `qApp` c+ VDate ->+ Date+ VDateLiteral d ->+ DateLiteral d+ VDateShow t ->+ DateShow `qApp` t+ VTime ->+ Time+ VTimeLiteral t p ->+ TimeLiteral t p+ VTimeShow t ->+ TimeShow `qApp` t+ VTimeZone ->+ TimeZone+ VTimeZoneLiteral z ->+ TimeZoneLiteral z+ VTimeZoneShow t ->+ TimeZoneShow `qApp` t+ VList t ->+ List `qApp` t+ VListLit ma ts ->+ ListLit (fmap (quote env) ma) (fmap (quote env) ts)+ VListAppend t u ->+ ListAppend (quote env t) (quote env u)+ VListBuild a t ->+ ListBuild `qApp` a `qApp` t+ VListFold a l t u v ->+ ListFold `qApp` a `qApp` l `qApp` t `qApp` u `qApp` v+ VListLength a t ->+ ListLength `qApp` a `qApp` t+ VListHead a t ->+ ListHead `qApp` a `qApp` t+ VListLast a t ->+ ListLast `qApp` a `qApp` t+ VListIndexed a t ->+ ListIndexed `qApp` a `qApp` t+ VListReverse a t ->+ ListReverse `qApp` a `qApp` t+ VOptional a ->+ Optional `qApp` a+ VSome t ->+ Some (quote env t)+ VNone t ->+ None `qApp` t+ VRecord m ->+ Record (fmap quoteRecordField m)+ VRecordLit m ->+ RecordLit (fmap quoteRecordField m)+ VUnion m ->+ Union (fmap (fmap (quote env)) m)+ VCombine mk t u ->+ Combine mempty mk (quote env t) (quote env u)+ VCombineTypes t u ->+ CombineTypes mempty (quote env t) (quote env u)+ VPrefer t u ->+ Prefer mempty PreferFromSource (quote env t) (quote env u)+ VMerge t u ma ->+ Merge (quote env t) (quote env u) (fmap (quote env) ma)+ VToMap t ma ->+ ToMap (quote env t) (fmap (quote env) ma)+ VShowConstructor t ->+ ShowConstructor (quote env t)+ VField t k ->+ Field (quote env t) $ Syntax.makeFieldSelection k+ VProject t p ->+ Project (quote env t) (first Dhall.Set.toList (fmap (quote env) p))+ VAssert t ->+ Assert (quote env t)+ VEquivalent t u ->+ Equivalent mempty (quote env t) (quote env u)+ VWith e ks v ->+ With (quote env e) ks (quote env v)+ VInject m k Nothing ->+ Field (Union (fmap (fmap (quote env)) m)) $ Syntax.makeFieldSelection k+ VInject m k (Just t) ->+ Field (Union (fmap (fmap (quote env)) m)) (Syntax.makeFieldSelection k) `qApp` t+ VEmbed a ->+ Embed a+ VPrimVar ->+ error errorMsg+ where+ fresh :: Text -> (Text, Val a)+ fresh x = (x, VVar x (countNames x env))+ {-# INLINE fresh #-}++ freshClosure :: Closure a -> (Text, Val a, Closure a)+ freshClosure closure@(Closure x _ _) = (x, snd (fresh x), closure)+ {-# INLINE freshClosure #-}++ quoteBind :: Text -> Val a -> Expr Void a+ quoteBind x = quote (Bind env x)+ {-# INLINE quoteBind #-}++ qApp :: Expr Void a -> Val a -> Expr Void a+ qApp t VPrimVar = t+ qApp t u = App t (quote env u)+ {-# INLINE qApp #-}++ quoteRecordField :: Val a -> RecordField Void a+ quoteRecordField = Syntax.makeRecordField . quote env+ {-# INLINE quoteRecordField #-}++-- | Normalize an expression in an environment of values. Any variable pointing out of+-- the environment is treated as opaque free variable.+nf :: Eq a => Environment a -> Expr s a -> Expr t a+nf !env = Syntax.renote . quote (envNames env) . eval env . Syntax.denote++normalize :: Eq a => Expr s a -> Expr t a+normalize = nf Empty+{-# INLINABLE normalize #-}++alphaNormalize :: Expr s a -> Expr s a+alphaNormalize = goEnv EmptyNames+ where+ goVar :: Names -> Text -> Int -> Expr s a+ goVar e topX topI = go 0 e topI+ where+ go !acc (Bind env x) !i+ | x == topX = if i == 0 then Var (V "_" acc) else go (acc + 1) env (i - 1)+ | otherwise = go (acc + 1) env i+ go _ EmptyNames i = Var (V topX i)++ goEnv :: Names -> Expr s a -> Expr s a+ goEnv !e0 t0 =+ case t0 of+ Const k ->+ Const k+ Var (V x i) ->+ goVar e0 x i+ Lam cs (FunctionBinding src0 x src1 src2 t) u ->+ Lam cs (FunctionBinding src0 "_" src1 src2 (go t)) (goBind x u)+ Pi cs x a b ->+ Pi cs "_" (go a) (goBind x b)+ App t u ->+ App (go t) (go u)+ Let (Binding src0 x src1 mA src2 a) b ->+ Let (Binding src0 "_" src1 (fmap (fmap go) mA) src2 (go a)) (goBind x b)+ Annot t u ->+ Annot (go t) (go u)+ Bool ->+ Bool+ BoolLit b ->+ BoolLit b+ BoolAnd t u ->+ BoolAnd (go t) (go u)+ BoolOr t u ->+ BoolOr (go t) (go u)+ BoolEQ t u ->+ BoolEQ (go t) (go u)+ BoolNE t u ->+ BoolNE (go t) (go u)+ BoolIf b t f ->+ BoolIf (go b) (go t) (go f)+ Bytes ->+ Bytes+ BytesLit b ->+ BytesLit b+ Natural ->+ Natural+ NaturalLit n ->+ NaturalLit n+ NaturalFold ->+ NaturalFold+ NaturalBuild ->+ NaturalBuild+ NaturalIsZero ->+ NaturalIsZero+ NaturalEven ->+ NaturalEven+ NaturalOdd ->+ NaturalOdd+ NaturalToInteger ->+ NaturalToInteger+ NaturalShow ->+ NaturalShow+ NaturalSubtract ->+ NaturalSubtract+ NaturalPlus t u ->+ NaturalPlus (go t) (go u)+ NaturalTimes t u ->+ NaturalTimes (go t) (go u)+ Integer ->+ Integer+ IntegerLit n ->+ IntegerLit n+ IntegerClamp ->+ IntegerClamp+ IntegerNegate ->+ IntegerNegate+ IntegerShow ->+ IntegerShow+ IntegerToDouble ->+ IntegerToDouble+ Double ->+ Double+ DoubleLit n ->+ DoubleLit n+ DoubleShow ->+ DoubleShow+ Text ->+ Text+ TextLit cs ->+ TextLit (goChunks cs)+ TextAppend t u ->+ TextAppend (go t) (go u)+ TextShow ->+ TextShow+ TextReplace ->+ TextReplace+ Date ->+ Date+ DateLiteral d ->+ DateLiteral d+ DateShow ->+ DateShow+ Time ->+ Time+ TimeLiteral t p ->+ TimeLiteral t p+ TimeShow ->+ TimeShow+ TimeZone ->+ TimeZone+ TimeZoneLiteral z ->+ TimeZoneLiteral z+ TimeZoneShow ->+ TimeZoneShow+ List ->+ List+ ListLit ma ts ->+ ListLit (fmap go ma) (fmap go ts)+ ListAppend t u ->+ ListAppend (go t) (go u)+ ListBuild ->+ ListBuild+ ListFold ->+ ListFold+ ListLength ->+ ListLength+ ListHead ->+ ListHead+ ListLast ->+ ListLast+ ListIndexed ->+ ListIndexed+ ListReverse ->+ ListReverse+ Optional ->+ Optional+ Some t ->+ Some (go t)+ None ->+ None+ Record kts ->+ Record (goRecordField <$> kts)+ RecordLit kts ->+ RecordLit (goRecordField <$> kts)+ Union kts ->+ Union (fmap (fmap go) kts)+ Combine cs m t u ->+ Combine cs m (go t) (go u)+ CombineTypes cs t u ->+ CombineTypes cs (go t) (go u)+ Prefer cs b t u ->+ Prefer cs b (go t) (go u)+ RecordCompletion t u ->+ RecordCompletion (go t) (go u)+ Merge x y ma ->+ Merge (go x) (go y) (fmap go ma)+ ToMap x ma ->+ ToMap (go x) (fmap go ma)+ ShowConstructor x ->+ ShowConstructor (go x)+ Field t k ->+ Field (go t) k+ Project t ks ->+ Project (go t) (fmap go ks)+ Assert t ->+ Assert (go t)+ Equivalent cs t u ->+ Equivalent cs (go t) (go u)+ With e k v ->+ With (go e) k (go v)+ Note s e ->+ Note s (go e)+ ImportAlt t u ->+ ImportAlt (go t) (go u)+ Embed a ->+ Embed a+ where+ go = goEnv e0+ goBind x = goEnv (Bind e0 x)+ goChunks (Chunks ts x) = Chunks (fmap (fmap go) ts) x+ goRecordField (RecordField s0 e s1 s2) = RecordField s0 (go e) s1 s2
@@ -1,8 +0,0 @@--module Dhall.Eval where--import {-# SOURCE #-} Dhall.Core--convEmpty :: Eq a => Expr s a -> Expr t a -> Bool-nfEmpty :: Eq a => Expr s a -> Expr t a-alphaNormalize :: Expr s a -> Expr s a
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -7,104 +6,117 @@ module Dhall.Format ( -- * Format Format(..)- , FormatMode(..) , format ) where -import Control.Exception (Exception)-import Dhall.Parser (exprAndHeaderFromText)-import Dhall.Pretty (CharacterSet(..), annToAnsiStyle, layoutOpts)--import Data.Monoid ((<>))+import Data.Foldable (for_)+import Data.List.NonEmpty (NonEmpty)+import Data.Maybe (fromMaybe)+import Dhall.Pretty (CharacterSet, annToAnsiStyle, detectCharacterSet)+import Dhall.Util+ ( Censor+ , CheckFailed (..)+ , Header (..)+ , Input (..)+ , OutputMode (..)+ , Transitivity (..)+ , handleMultipleChecksFailed+ ) -import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty.Terminal-import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty.Text-import qualified Control.Exception import qualified Data.Text.IO-import qualified Dhall.Core+import qualified Dhall.Import import qualified Dhall.Pretty+import qualified Dhall.Util+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty.Terminal+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified System.AtomicWrite.Writer.LazyText as AtomicWrite.LazyText import qualified System.Console.ANSI+import qualified System.FilePath import qualified System.IO -data NotFormatted = NotFormatted- deriving (Exception)--instance Show NotFormatted where- show _ = ""- -- | Arguments to the `format` subcommand data Format = Format- { characterSet :: CharacterSet- , formatMode :: FormatMode+ { chosenCharacterSet :: Maybe CharacterSet+ , censor :: Censor+ , transitivity :: Transitivity+ , inputs :: NonEmpty Input+ , outputMode :: OutputMode } -{-| The `format` subcommand can either `Modify` its input or simply `Check`- that the input is already formatted--}-data FormatMode- = Modify- { inplace :: Maybe FilePath- -- ^ Modify file in-place if present, otherwise read from @stdin@ and- -- write to @stdout@- }- | Check- { path :: Maybe FilePath- -- ^ Read from the given file if present, otherwise read from @stdin@- }- -- | Implementation of the @dhall format@ subcommand-format- :: Format- -> IO ()-format (Format {..}) =- case formatMode of- Modify {..} ->- case inplace of- Just file -> do- text <- Data.Text.IO.readFile file+format :: Format -> IO ()+format (Format { inputs = inputs0, transitivity = transitivity0, ..}) =+ handleMultipleChecksFailed "format" "formatted" go inputs0+ where+ go input = do+ let directory = case input of+ StandardInput ->+ "."+ InputFile file ->+ System.FilePath.takeDirectory file - (header, expr) <- Dhall.Core.throws (exprAndHeaderFromText "(stdin)" text)+ let status = Dhall.Import.emptyStatus directory - let doc = Pretty.pretty header- <> Pretty.unAnnotate (Dhall.Pretty.prettyCharacterSet characterSet expr)- <> "\n"- System.IO.withFile file System.IO.WriteMode (\handle -> do- Pretty.Terminal.renderIO handle (Pretty.layoutSmart layoutOpts doc))- Nothing -> do- inText <- Data.Text.IO.getContents+ let layoutHeaderAndExpr (Header header, expr) =+ let characterSet = fromMaybe (detectCharacterSet expr) chosenCharacterSet+ in+ Dhall.Pretty.layout+ ( Pretty.pretty header+ <> Dhall.Pretty.prettyCharacterSet characterSet expr+ <> "\n") - (header, expr) <- Dhall.Core.throws (exprAndHeaderFromText "(stdin)" inText)+ (inputName, originalText, transitivity) <- case input of+ InputFile file -> do+ text <- Data.Text.IO.readFile file - let doc = Pretty.pretty header- <> Dhall.Pretty.prettyCharacterSet characterSet expr- <> "\n"+ return (file, text, transitivity0)+ StandardInput -> do+ text <- Data.Text.IO.getContents - supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout+ return ("(input)", text, NonTransitive) - if supportsANSI- then- Pretty.Terminal.renderIO- System.IO.stdout- (fmap annToAnsiStyle (Pretty.layoutSmart layoutOpts doc))- else- Pretty.Terminal.renderIO- System.IO.stdout- (Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc))- Check {..} -> do- originalText <- case path of- Just file -> Data.Text.IO.readFile file- Nothing -> Data.Text.IO.getContents - (header, expr) <- Dhall.Core.throws (exprAndHeaderFromText "(stdin)" originalText)+ headerAndExpr@(_, parsedExpression) <- Dhall.Util.getExpressionAndHeaderFromStdinText censor inputName originalText - let doc = Pretty.pretty header- <> Pretty.unAnnotate (Dhall.Pretty.prettyCharacterSet characterSet expr)- <> "\n"+ case transitivity of+ Transitive ->+ for_ parsedExpression $ \import_ -> do+ maybeFilepath <- Dhall.Import.dependencyToFile status import_ - let formattedText =- Pretty.Text.renderStrict (Pretty.layoutSmart layoutOpts doc)+ for_ maybeFilepath $ \filepath ->+ go (InputFile filepath) - if originalText == formattedText- then return ()- else Control.Exception.throwIO NotFormatted+ NonTransitive ->+ return ()++ let docStream = layoutHeaderAndExpr headerAndExpr++ let formattedText = Pretty.Text.renderStrict docStream++ case outputMode of+ Write -> do+ case input of+ InputFile file ->+ if originalText == formattedText+ then return ()+ else AtomicWrite.LazyText.atomicWriteFile+ file+ (Pretty.Text.renderLazy docStream)++ StandardInput -> do+ supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout++ Pretty.Terminal.renderIO+ System.IO.stdout+ (if supportsANSI+ then (fmap annToAnsiStyle docStream)+ else (Pretty.unAnnotateS docStream))++ return (Right ())++ Check ->+ return $+ if originalText == formattedText+ then Right ()+ else Left CheckFailed{..}
@@ -1,52 +1,188 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-} -- | This module contains the implementation of the @dhall freeze@ subcommand module Dhall.Freeze ( -- * Freeze freeze+ , freezeExpression , freezeImport , freezeRemoteImport + -- * Freeze with custom evaluation settings+ , freezeWithSettings+ , freezeExpressionWithSettings+ , freezeImportWithSettings+ , freezeRemoteImportWithSettings+ -- * Types , Scope(..) , Intent(..)++ -- * Deprecated functions+ , freezeWithManager+ , freezeExpressionWithManager+ , freezeImportWithManager+ , freezeRemoteImportWithManager ) where -import Control.Exception (SomeException)-import Data.Monoid ((<>))-import Data.Maybe (fromMaybe)-import Data.Text-import Dhall.Binary (StandardVersion(..))-import Dhall.Core (Expr(..), Import(..), ImportHashed(..), ImportType(..))-import Dhall.Import (standardVersion)-import Dhall.Parser (exprAndHeaderFromText, Src)-import Dhall.Pretty (CharacterSet, annToAnsiStyle, layoutOpts, prettyCharacterSet)-import Dhall.TypeCheck (X)-import Lens.Family (set)+import Data.Foldable (for_)+import Data.List.NonEmpty (NonEmpty)+import Data.Maybe (fromMaybe)+import Dhall (EvaluateSettings)+import Dhall.Pretty (CharacterSet, detectCharacterSet)+import Dhall.Syntax+ ( Expr (..)+ , Import (..)+ , ImportHashed (..)+ , ImportType (..)+ )+import Dhall.Util+ ( Censor+ , CheckFailed (..)+ , Header (..)+ , Input (..)+ , OutputMode (..)+ , Transitivity (..)+ , handleMultipleChecksFailed+ )+import Lens.Micro (set, transformMOf, transformOf)+import Lens.Micro.Extras (view) import System.Console.ANSI (hSupportsANSI) -import qualified Control.Exception-import qualified Control.Monad.Trans.State.Strict as State-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty-import qualified Data.Text.IO-import qualified Dhall.Core+import qualified Control.Exception as Exception+import qualified Control.Monad.Trans.State.Strict as State+import qualified Data.Text.IO as Text.IO+import qualified Dhall+import qualified Dhall.Core as Core import qualified Dhall.Import-import qualified Dhall.Optics+import qualified Dhall.Pretty import qualified Dhall.TypeCheck+import qualified Dhall.Util as Util+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified System.AtomicWrite.Writer.LazyText as AtomicWrite.LazyText import qualified System.FilePath import qualified System.IO +-- | Specifies which imports to freeze+data Scope+ = OnlyRemoteImports+ -- ^ Freeze only remote imports (i.e. URLs)+ | AllImports+ -- ^ Freeze all imports (including paths and environment variables)++-- | Specifies why we are adding semantic integrity checks+data Intent+ = Secure+ -- ^ Protect imports with an integrity check without a fallback so that+ -- import resolution fails if the import changes+ | Cache+ -- ^ Protect imports with an integrity check and also add a fallback import+ -- import without an integrity check. This is useful if you only want to+ -- cache imports when possible but still gracefully degrade to resolving+ -- them if the semantic integrity check has changed.+ -- | Retrieve an `Import` and update the hash to match the latest contents freezeImport :: FilePath -- ^ Current working directory- -> StandardVersion -> Import -> IO Import-freezeImport directory _standardVersion import_ = do+freezeImport = freezeImportWithSettings Dhall.defaultEvaluateSettings++-- | See 'freezeImport'.+freezeImportWithManager+ :: IO Dhall.Import.Manager+ -> FilePath+ -> Import+ -> IO Import+freezeImportWithManager newManager = freezeImportWithSettings (set Dhall.newManager newManager Dhall.defaultEvaluateSettings)+{-# DEPRECATED freezeImportWithManager "Use freezeImportWithSettings directly" #-}++-- | Freeze an import only if the import is a `Remote` import+freezeRemoteImport+ :: FilePath+ -- ^ Current working directory+ -> Import+ -> IO Import+freezeRemoteImport = freezeRemoteImportWithSettings Dhall.defaultEvaluateSettings++-- | See 'freezeRemoteImport'.+freezeRemoteImportWithManager+ :: IO Dhall.Import.Manager+ -> FilePath+ -> Import+ -> IO Import+freezeRemoteImportWithManager newManager = freezeRemoteImportWithSettings (set Dhall.newManager newManager Dhall.defaultEvaluateSettings)+{-# DEPRECATED freezeRemoteImportWithManager "Use freezeRemoteImportWithSettings directly" #-}++-- | Implementation of the @dhall freeze@ subcommand+freeze+ :: OutputMode+ -> Transitivity+ -> NonEmpty Input+ -> Scope+ -> Intent+ -> Maybe CharacterSet+ -> Censor+ -> IO ()+freeze = freezeWithSettings Dhall.defaultEvaluateSettings++-- | See 'freeze'.+freezeWithManager+ :: IO Dhall.Import.Manager+ -> OutputMode+ -> Transitivity+ -> NonEmpty Input+ -> Scope+ -> Intent+ -> Maybe CharacterSet+ -> Censor+ -> IO ()+freezeWithManager newManager = freezeWithSettings (set Dhall.newManager newManager Dhall.defaultEvaluateSettings)+{-# DEPRECATED freezeWithManager "Use freezeWithSettings directly" #-}++{-| Slightly more pure version of the `freeze` function++ This still requires `IO` to freeze the import, but now the input and output+ expression are passed in explicitly+-}+freezeExpression+ :: FilePath+ -- ^ Starting directory+ -> Scope+ -> Intent+ -> Expr s Import+ -> IO (Expr s Import)+freezeExpression = freezeExpressionWithSettings Dhall.defaultEvaluateSettings++-- | See 'freezeExpression'.+freezeExpressionWithManager+ :: IO Dhall.Import.Manager+ -> FilePath+ -> Scope+ -> Intent+ -> Expr s Import+ -> IO (Expr s Import)+freezeExpressionWithManager newManager = freezeExpressionWithSettings (set Dhall.newManager newManager Dhall.defaultEvaluateSettings)+{-# DEPRECATED freezeExpressionWithManager "Use freezeExpressionWithSettings directly" #-}++--------------------------------------------------------------------------------+-- Versions that take EvaluateSettings+--------------------------------------------------------------------------------++-- | See 'freezeImport'.+freezeImportWithSettings+ :: EvaluateSettings+ -> FilePath+ -> Import+ -> IO Import+freezeImportWithSettings settings directory import_ = do let unprotectedImport = import_ { importHashed =@@ -55,133 +191,186 @@ } } - let status =- set standardVersion- _standardVersion- (Dhall.Import.emptyStatus directory)-- let download =- State.evalStateT (Dhall.Import.loadWith (Embed import_)) status-- -- Try again without the semantic integrity check if decoding fails- let handler :: SomeException -> IO (Expr Src X)- handler _ = do- State.evalStateT (Dhall.Import.loadWith (Embed unprotectedImport)) status+ let status = Dhall.Import.emptyStatusWithManager (view Dhall.newManager settings) directory - expression <- Control.Exception.handle handler download+ expression <- State.evalStateT (Dhall.Import.loadWith (Embed unprotectedImport)) status - case Dhall.TypeCheck.typeOf expression of- Left exception -> Control.Exception.throwIO exception+ case Dhall.TypeCheck.typeWith (view Dhall.startingContext settings) expression of+ Left exception -> Exception.throwIO exception Right _ -> return () - let normalizedExpression =- Dhall.Core.alphaNormalize (Dhall.Core.normalize expression)+ let normalizedExpression = Core.alphaNormalize (Core.normalizeWith (view Dhall.normalizer settings) expression) - let expressionHash =- Just (Dhall.Import.hashExpression _standardVersion normalizedExpression)+ -- make sure the frozen import is present in the semantic cache+ Dhall.Import.writeExpressionToSemanticCache (Core.denote expression) - let newImportHashed = (importHashed import_) { hash = expressionHash }+ let expressionHash = Dhall.Import.hashExpression normalizedExpression - let newImport = import_ { importHashed = newImportHashed }+ let newImportHashed = (importHashed import_) { hash = Just expressionHash } - State.evalStateT (Dhall.Import.exprToImport newImport normalizedExpression) status+ let newImport = import_ { importHashed = newImportHashed } return newImport --- | Freeze an import only if the import is a `Remote` import-freezeRemoteImport- :: FilePath- -- ^ Current working directory- -> StandardVersion+-- | See 'freezeRemoteImport'.+freezeRemoteImportWithSettings+ :: EvaluateSettings+ -> FilePath -> Import -> IO Import-freezeRemoteImport directory _standardVersion import_ = do+freezeRemoteImportWithSettings settings directory import_ = case importType (importHashed import_) of- Remote {} -> freezeImport directory _standardVersion import_+ Remote {} -> freezeImportWithSettings settings directory import_ _ -> return import_ -writeExpr :: Maybe FilePath -> (Text, Expr s Import) -> CharacterSet -> IO ()-writeExpr inplace (header, expr) characterSet = do- let doc = Pretty.pretty header- <> Dhall.Pretty.prettyCharacterSet characterSet expr+-- | See 'freezeRemoteImport'.+freezeNonMissingImportWithSettings+ :: EvaluateSettings+ -> FilePath+ -> Import+ -> IO Import+freezeNonMissingImportWithSettings settings directory import_ =+ case importType (importHashed import_) of+ Missing -> return import_+ _ -> freezeImportWithSettings settings directory import_ - let unAnnotated = Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc)+-- | See 'freeze'.+freezeWithSettings+ :: EvaluateSettings+ -> OutputMode+ -> Transitivity+ -> NonEmpty Input+ -> Scope+ -> Intent+ -> Maybe CharacterSet+ -> Censor+ -> IO ()+freezeWithSettings settings outputMode transitivity0 inputs scope intent chosenCharacterSet censor =+ handleMultipleChecksFailed "freeze" "frozen" go inputs+ where+ go input = do+ let directory = case input of+ StandardInput ->+ "."+ InputFile file ->+ System.FilePath.takeDirectory file - case inplace of- Just f ->- System.IO.withFile f System.IO.WriteMode (\handle -> do- Pretty.renderIO handle unAnnotated- Data.Text.IO.hPutStrLn handle "" )+ let status = Dhall.Import.emptyStatusWithManager (view Dhall.newManager settings) directory - Nothing -> do- supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout- if supportsANSI- then- Pretty.renderIO System.IO.stdout (annToAnsiStyle <$> Pretty.layoutSmart layoutOpts doc)- else- Pretty.renderIO System.IO.stdout unAnnotated+ (inputName, originalText, transitivity) <- case input of+ InputFile file -> do+ text <- Text.IO.readFile file --- | Specifies which imports to freeze-data Scope- = OnlyRemoteImports- -- ^ Freeze only remote imports (i.e. URLs)- | AllImports- -- ^ Freeze all imports (including paths and environment variables)+ return (file, text, transitivity0) --- | Specifies why we are adding semantic integrity checks-data Intent- = Secure- -- ^ Protect imports with an integrity check without a fallback so that- -- import resolution fails if the import changes- | Cache- -- ^ Protect imports with an integrity check and also add a fallback import- -- import without an integrity check. This is useful if you only want to- -- cache imports when possible but still gracefully degrade to resolving- -- them if the semantic integrity check has changed.+ StandardInput -> do+ text <- Text.IO.getContents --- | Implementation of the @dhall freeze@ subcommand-freeze- :: Maybe FilePath- -- ^ Modify file in-place if present, otherwise read from @stdin@ and write- -- to @stdout@- -> Scope- -> Intent- -> CharacterSet- -> StandardVersion- -> IO ()-freeze inplace scope intent characterSet _standardVersion = do- (text, directory) <- case inplace of- Nothing -> do- text <- Data.Text.IO.getContents+ return ("(input)", text, NonTransitive) - return (text, ".")+ (Header header, parsedExpression) <- Util.getExpressionAndHeaderFromStdinText censor inputName originalText - Just file -> do- text <- Data.Text.IO.readFile file+ let characterSet = fromMaybe (detectCharacterSet parsedExpression) chosenCharacterSet - return (text, System.FilePath.takeDirectory file)+ case transitivity of+ Transitive ->+ for_ parsedExpression $ \import_ -> do+ maybeFilepath <- Dhall.Import.dependencyToFile status import_ - (header, parsedExpression) <- Dhall.Core.throws (exprAndHeaderFromText srcInfo text)+ for_ maybeFilepath $ \filepath ->+ go (InputFile filepath) + NonTransitive ->+ return ()++ frozenExpression <- freezeExpressionWithSettings settings directory scope intent parsedExpression++ let doc = Pretty.pretty header+ <> Dhall.Pretty.prettyCharacterSet characterSet frozenExpression+ <> "\n"++ let stream = Dhall.Pretty.layout doc++ let modifiedText = Pretty.Text.renderStrict stream++ case outputMode of+ Write -> do+ let unAnnotated = Pretty.unAnnotateS stream++ case input of+ InputFile file ->+ if originalText == modifiedText+ then return ()+ else+ AtomicWrite.LazyText.atomicWriteFile+ file+ (Pretty.Text.renderLazy unAnnotated)++ StandardInput -> do+ supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout+ if supportsANSI+ then+ Pretty.renderIO System.IO.stdout (Dhall.Pretty.annToAnsiStyle <$> stream)+ else+ Pretty.renderIO System.IO.stdout unAnnotated++ return (Right ())++ Check ->+ return $+ if originalText == modifiedText+ then Right ()+ else Left CheckFailed{..}++-- | See 'freezeExpression'.+freezeExpressionWithSettings+ :: EvaluateSettings+ -> FilePath+ -> Scope+ -> Intent+ -> Expr s Import+ -> IO (Expr s Import)+freezeExpressionWithSettings settings directory scope intent expression = do let freezeScope = case scope of- AllImports -> freezeImport- OnlyRemoteImports -> freezeRemoteImport+ AllImports -> freezeNonMissingImportWithSettings+ OnlyRemoteImports -> freezeRemoteImportWithSettings - let freezeFunction = freezeScope directory _standardVersion+ let freezeFunction = freezeScope settings directory let cache+ -- This case is necessary because `transformOf` is a bottom-up+ -- rewrite rule. Without this rule, if you were to transform a+ -- file that already has a cached expression, like this:+ --+ -- someImport sha256:… ? someImport+ --+ -- ... then you would get:+ --+ -- (someImport sha256:… ? someImport)+ -- ? (someImport sha256:… ? someImport)+ --+ -- ... and this rule fixes that by collapsing that back to:+ --+ -- (someImport sha256:… ? someImport) (ImportAlt- (Embed- (Import { importHashed = ImportHashed { hash = Just _expectedHash } })+ (Core.shallowDenote -> ImportAlt+ (Core.shallowDenote -> Embed+ Import{ importHashed = ImportHashed{ hash = Just _expectedHash } }+ )+ (Core.shallowDenote -> Embed+ Import{ importHashed = ImportHashed{ hash = Nothing } }+ ) )- import_@(ImportAlt- (Embed- (Import { importHashed = ImportHashed { hash = Just _actualHash } })+ import_@(Core.shallowDenote -> ImportAlt+ (Core.shallowDenote -> Embed+ Import{ importHashed = ImportHashed{ hash = Just _actualHash } } )- _+ (Core.shallowDenote -> Embed+ Import{ importHashed = ImportHashed{ hash = Nothing } }+ ) )- ) = do+ ) = {- Here we could actually compare the `_expectedHash` and `_actualHash` to see if they differ, but we choose not to do so and instead automatically accept the `_actualHash`. This@@ -195,27 +384,62 @@ (Embed import_@(Import { importHashed = ImportHashed { hash = Nothing } })) = do frozenImport <- freezeFunction import_ + let frozenMissing = toMissing frozenImport+ {- The two imports can be the same if the import is local and- `freezeFunction` only freezes remote imports+ `freezeFunction` only freezes remote imports by default -} if frozenImport /= import_- then return (ImportAlt (Embed frozenImport) (Embed import_))+ then return (ImportAlt (Embed frozenMissing) (Embed import_)) else return (Embed import_)- cache expression = do- return expression+ cache+ (Embed import_@(Import { importHashed = ImportHashed { hash = Just _ } })) = do+ -- Regenerate the integrity check, just in case it's wrong+ frozenImport <- freezeFunction import_ - let rewrite expression =- case intent of- Secure ->- traverse freezeFunction expression- Cache ->- Dhall.Optics.transformMOf- Dhall.Core.subExpressions- cache- (Dhall.Core.denote expression)+ let frozenMissing = toMissing frozenImport - frozenExpression <- rewrite parsedExpression+ -- `dhall freeze --cache` also works the other way around, adding an+ -- unprotected fallback import to imports that are already+ -- protected+ let thawedImport = import_+ { importHashed = (importHashed import_)+ { hash = Nothing+ }+ } - writeExpr inplace (header, frozenExpression) characterSet- where- srcInfo = fromMaybe "(stdin)" inplace+ return (ImportAlt (Embed frozenMissing) (Embed thawedImport))+ cache expression_ =+ return expression_++ let uncache+ (ImportAlt+ (Core.shallowDenote -> Embed+ Import{ importHashed = ImportHashed { hash = Just expectedHash, importType = Missing } }+ )+ (Core.shallowDenote -> Embed+ import_@Import{ importHashed = ImportHashed{ hash = Nothing } }+ )+ ) = Embed+ (import_+ { importHashed = (importHashed import_)+ { hash = Just expectedHash+ }+ }+ )+ uncache expression_ = expression_++ let simplify (ImportAlt (Core.shallowDenote -> Embed import1) (Core.shallowDenote -> Embed import2))+ | import1 == import2 = Embed import1+ simplify expression_ = expression_++ transformOf Core.subExpressions simplify <$> case intent of+ Secure ->+ traverse freezeFunction (transformOf Core.subExpressions uncache expression)+ Cache ->+ transformMOf Core.subExpressions cache expression++-- https://github.com/dhall-lang/dhall-haskell/issues/2347+toMissing :: Import -> Import+toMissing import_ =+ import_ { importHashed = (importHashed import_) { importType = Missing } }
@@ -1,44 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- | This module contains the implementation of the @dhall hash@ subcommand--module Dhall.Hash- ( -- * Hash- hash- ) where--import Dhall.Binary (StandardVersion)-import Dhall.Parser (exprFromText)-import Dhall.Import (hashExpressionToCode, standardVersion)-import Lens.Family (set)--import qualified Control.Monad.Trans.State.Strict as State-import qualified Control.Exception-import qualified Dhall.Core-import qualified Dhall.Import-import qualified Dhall.TypeCheck-import qualified Data.Text.IO---- | Implementation of the @dhall hash@ subcommand-hash :: StandardVersion -> IO ()-hash _standardVersion = do- inText <- Data.Text.IO.getContents-- parsedExpression <- case exprFromText "(stdin)" inText of- Left exception -> Control.Exception.throwIO exception- Right parsedExpression -> return parsedExpression-- let status =- set standardVersion _standardVersion (Dhall.Import.emptyStatus ".")-- resolvedExpression <- State.evalStateT (Dhall.Import.loadWith parsedExpression) status-- case Dhall.TypeCheck.typeOf resolvedExpression of- Left exception -> Control.Exception.throwIO exception- Right _ -> return ()-- let normalizedExpression =- Dhall.Core.alphaNormalize (Dhall.Core.normalize resolvedExpression)-- Data.Text.IO.putStrLn- (hashExpressionToCode _standardVersion normalizedExpression)
@@ -1,988 +1,1401 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# OPTIONS_GHC -Wall #-}--{-| Dhall lets you import external expressions located either in local files or- hosted on network endpoints.-- To import a local file as an expression, just insert the path to the file,- prepending a @./@ if the path is relative to the current directory. For- example, if you create a file named @id@ with the following contents:-- > $ cat id- > λ(a : Type) → λ(x : a) → x-- Then you can use the file directly within a @dhall@ program just by- referencing the file's path:-- > $ dhall- > ./id Bool True- > <Ctrl-D>- > Bool- >- > True-- Imported expressions may contain imports of their own, too, which will- continue to be resolved. However, Dhall will prevent cyclic imports. For- example, if you had these two files:-- > $ cat foo- > ./bar-- > $ cat bar- > ./foo-- ... Dhall would throw the following exception if you tried to import @foo@:-- > $ dhall- > ./foo- > ^D- > ↳ ./foo- > ↳ ./bar- >- > Cyclic import: ./foo-- You can also import expressions hosted on network endpoints. Just use the- URL-- > http://host[:port]/path-- The compiler expects the downloaded expressions to be in the same format- as local files, specifically UTF8-encoded source code text.-- For example, if our @id@ expression were hosted at @http://example.com/id@,- then we would embed the expression within our code using:-- > http://example.com/id-- You can also import expressions stored within environment variables using- @env:NAME@, where @NAME@ is the name of the environment variable. For- example:-- > $ export FOO=1- > $ export BAR='"Hi"'- > $ export BAZ='λ(x : Bool) → x == False'- > $ dhall <<< "{ foo = env:FOO , bar = env:BAR , baz = env:BAZ }"- > { bar : Text, baz : ∀(x : Bool) → Bool, foo : Integer }- >- > { bar = "Hi", baz = λ(x : Bool) → x == False, foo = 1 }-- If you wish to import the raw contents of an impoert as @Text@ then add- @as Text@ to the end of the import:-- > $ dhall <<< "http://example.com as Text"- > Text- >- > "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta- > charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html- > ; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,- > initial-scale=1\" />\n <style type=\"text/css\">\n body {\n backgro- > und-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-famil- > y: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n- > }\n div {\n width: 600px;\n margin: 5em auto;\n paddi- > ng: 50px;\n background-color: #fff;\n border-radius: 1em;\n }\n- > a:link, a:visited {\n color: #38488f;\n text-decoration: none;- > \n }\n @media (max-width: 700px) {\n body {\n background- > -color: #fff;\n }\n div {\n width: auto;\n m- > argin: 0 auto;\n border-radius: 0;\n padding: 1em;\n- > }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</- > h1>\n <p>This domain is established to be used for illustrative examples in d- > ocuments. You may use this\n domain in examples without prior coordination or- > asking for permission.</p>\n <p><a href=\"http://www.iana.org/domains/exampl- > e\">More information...</a></p>\n</div>\n</body>\n</html>\n"--}--module Dhall.Import (- -- * Import- exprFromImport- , exprToImport- , load- , loadWith- , hashExpression- , hashExpressionToCode- , assertNoImports- , Status- , emptyStatus- , stack- , cache- , manager- , standardVersion- , normalizer- , startingContext- , resolver- , cacher- , Cycle(..)- , ReferentiallyOpaque(..)- , Imported(..)- , ImportResolutionDisabled(..)- , PrettyHttpException(..)- , MissingFile(..)- , MissingEnvironmentVariable(..)- , MissingImports(..)- , HashMismatch(..)- ) where--import Control.Applicative (Alternative(..))-import Codec.CBOR.Term (Term(..))-import Control.Exception (Exception, SomeException, throwIO, toException)-import Control.Monad (guard)-import Control.Monad.Catch (throwM, MonadCatch(catch), catches, Handler(..))-import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Trans.State.Strict (StateT)-import Crypto.Hash (SHA256)-import Data.CaseInsensitive (CI)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Semigroup (Semigroup(..))-import Data.Text (Text)-#if MIN_VERSION_base(4,8,0)-#else-import Data.Traversable (traverse)-#endif-import Data.Typeable (Typeable)-import System.FilePath ((</>))-import Dhall.Binary (StandardVersion(..))-import Dhall.Core- ( Expr(..)- , Binding(..)- , Chunks(..)- , Directory(..)- , File(..)- , FilePrefix(..)- , ImportHashed(..)- , ImportType(..)- , ImportMode(..)- , Import(..)- , URL(..)- )-#ifdef MIN_VERSION_http_client-import Dhall.Import.HTTP-#endif-import Dhall.Import.Types-import Text.Dot ((.->.), userNodeId)--import Dhall.Parser (Parser(..), ParseError(..), Src(..), SourcedException(..))-import Dhall.TypeCheck (X(..))-import Lens.Family.State.Strict (zoom)--import qualified Codec.Serialise-import qualified Control.Monad.Trans.Maybe as Maybe-import qualified Control.Monad.Trans.State.Strict as State-import qualified Crypto.Hash-import qualified Data.ByteString-import qualified Data.ByteString.Lazy-import qualified Data.CaseInsensitive-import qualified Data.Foldable-import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Map.Strict as Map-import qualified Data.Text.Encoding-import qualified Data.Text as Text-import qualified Data.Text.IO-import qualified Dhall.Binary-import qualified Dhall.Core-import qualified Dhall.Map-import qualified Dhall.Parser-import qualified Dhall.Pretty.Internal-import qualified Dhall.TypeCheck-import qualified System.Environment-import qualified System.Directory as Directory-import qualified System.FilePath as FilePath-import qualified Text.Megaparsec-import qualified Text.Parser.Combinators-import qualified Text.Parser.Token---- | An import failed because of a cycle in the import graph-newtype Cycle = Cycle- { cyclicImport :: Import -- ^ The offending cyclic import- }- deriving (Typeable)--instance Exception Cycle--instance Show Cycle where- show (Cycle import_) =- "\nCyclic import: " ++ Dhall.Pretty.Internal.prettyToString import_--{-| Dhall tries to ensure that all expressions hosted on network endpoints are- weakly referentially transparent, meaning roughly that any two clients will- compile the exact same result given the same URL.-- To be precise, a strong interpretaton of referential transparency means that- if you compiled a URL you could replace the expression hosted at that URL- with the compiled result. Let's call this \"static linking\". Dhall (very- intentionally) does not satisfy this stronger interpretation of referential- transparency since \"statically linking\" an expression (i.e. permanently- resolving all imports) means that the expression will no longer update if- its dependencies change.-- In general, either interpretation of referential transparency is not- enforceable in a networked context since one can easily violate referential- transparency with a custom DNS, but Dhall can still try to guard against- common unintentional violations. To do this, Dhall enforces that a- non-local import may not reference a local import.-- Local imports are defined as:-- * A file-- * A URL with a host of @localhost@ or @127.0.0.1@-- All other imports are defined to be non-local--}-newtype ReferentiallyOpaque = ReferentiallyOpaque- { opaqueImport :: Import -- ^ The offending opaque import- } deriving (Typeable)--instance Exception ReferentiallyOpaque--instance Show ReferentiallyOpaque where- show (ReferentiallyOpaque import_) =- "\nReferentially opaque import: " ++ Dhall.Pretty.Internal.prettyToString import_---- | Extend another exception with the current import stack-data Imported e = Imported- { importStack :: NonEmpty Import -- ^ Imports resolved so far, in reverse order- , nested :: e -- ^ The nested exception- } deriving (Typeable)--instance Exception e => Exception (Imported e)--instance Show e => Show (Imported e) where- show (Imported canonicalizedImports e) =- concat (zipWith indent [0..] toDisplay)- ++ "\n"- ++ show e- where- indent n import_ =- "\n" ++ replicate (2 * n) ' ' ++ "↳ " ++ Dhall.Pretty.Internal.prettyToString import_-- canonical = NonEmpty.toList canonicalizedImports-- -- Tthe final (outermost) import is fake to establish the base- -- directory. Also, we need outermost-first.- toDisplay = drop 1 (reverse canonical)---- | Exception thrown when an imported file is missing-data MissingFile = MissingFile FilePath- deriving (Typeable)--instance Exception MissingFile--instance Show MissingFile where- show (MissingFile path) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Missing file "- <> path---- | Exception thrown when an environment variable is missing-newtype MissingEnvironmentVariable = MissingEnvironmentVariable { name :: Text }- deriving (Typeable)--instance Exception MissingEnvironmentVariable--instance Show MissingEnvironmentVariable where- show (MissingEnvironmentVariable {..}) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Missing environment variable\n"- <> "\n"- <> "↳ " <> Text.unpack name---- | List of Exceptions we encounter while resolving Import Alternatives-newtype MissingImports = MissingImports [SomeException]--instance Exception MissingImports--instance Show MissingImports where- show (MissingImports []) =- "\n"- <> "\ESC[1;31mError\ESC[0m: No valid imports"- show (MissingImports [e]) = show e- show (MissingImports es) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Failed to resolve imports. Error list:"- <> "\n"- <> concatMap (\e -> "\n" <> show e <> "\n") es--throwMissingImport :: (MonadCatch m, Exception e) => e -> m a-throwMissingImport e = throwM (MissingImports [toException e])---- | Exception thrown when a HTTP url is imported but dhall was built without--- the @with-http@ Cabal flag.-data CannotImportHTTPURL =- CannotImportHTTPURL- String- (Maybe [(CI Data.ByteString.ByteString, Data.ByteString.ByteString)])- deriving (Typeable)--instance Exception CannotImportHTTPURL--instance Show CannotImportHTTPURL where- show (CannotImportHTTPURL url _mheaders) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Cannot import HTTP URL.\n"- <> "\n"- <> "Dhall was compiled without the 'with-http' flag.\n"- <> "\n"- <> "The requested URL was: "- <> url- <> "\n"--{-|-> canonicalize . canonicalize = canonicalize--> canonicalize (a <> b) = canonicalize a <> canonicalize b--}-class Semigroup path => Canonicalize path where- canonicalize :: path -> path---- |--- >>> canonicalize (Directory {components = ["..",".."]})--- Directory {components = ["..",".."]}-instance Canonicalize Directory where- canonicalize (Directory []) = Directory []-- canonicalize (Directory ("." : components₀)) =- canonicalize (Directory components₀)-- canonicalize (Directory (".." : components₀)) =- case canonicalize (Directory components₀) of- Directory [] ->- Directory [ ".." ]- Directory (".." : components₁) ->- Directory (".." : ".." : components₁)- Directory (_ : components₁) ->- Directory components₁-- canonicalize (Directory (component : components₀)) =- Directory (component : components₁)- where- Directory components₁ = canonicalize (Directory components₀)--instance Canonicalize File where- canonicalize (File { directory, .. }) =- File { directory = canonicalize directory, .. }--instance Canonicalize ImportType where- canonicalize (Local prefix file) =- Local prefix (canonicalize file)-- canonicalize (Remote (URL {..})) =- Remote (URL { path = canonicalize path, headers = fmap (fmap canonicalize) headers, ..})-- canonicalize (Env name) =- Env name-- canonicalize Missing =- Missing--instance Canonicalize ImportHashed where- canonicalize (ImportHashed hash importType) =- ImportHashed hash (canonicalize importType)--instance Canonicalize Import where- canonicalize (Import importHashed importMode) =- Import (canonicalize importHashed) importMode--toHeaders- :: Expr s a- -> Maybe [(CI Data.ByteString.ByteString, Data.ByteString.ByteString)]-toHeaders (ListLit _ hs) = do- hs' <- mapM toHeader hs- return (Data.Foldable.toList hs')-toHeaders _ = do- empty--toHeader- :: Expr s a- -> Maybe (CI Data.ByteString.ByteString, Data.ByteString.ByteString)-toHeader (RecordLit m) = do- TextLit (Chunks [] keyText ) <- Dhall.Map.lookup "header" m- TextLit (Chunks [] valueText) <- Dhall.Map.lookup "value" m- let keyBytes = Data.Text.Encoding.encodeUtf8 keyText- let valueBytes = Data.Text.Encoding.encodeUtf8 valueText- return (Data.CaseInsensitive.mk keyBytes, valueBytes)-toHeader _ = do- empty----- | Exception thrown when an integrity check fails-data HashMismatch = HashMismatch- { expectedHash :: Crypto.Hash.Digest SHA256- , actualHash :: Crypto.Hash.Digest SHA256- } deriving (Typeable)--instance Exception HashMismatch--instance Show HashMismatch where- show (HashMismatch {..}) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Import integrity check failed\n"- <> "\n"- <> "Expected hash:\n"- <> "\n"- <> "↳ " <> show expectedHash <> "\n"- <> "\n"- <> "Actual hash:\n"- <> "\n"- <> "↳ " <> show actualHash <> "\n"--localToPath :: MonadIO io => FilePrefix -> File -> io FilePath-localToPath prefix file_ = liftIO $ do- let File {..} = file_-- let Directory {..} = directory-- prefixPath <- case prefix of- Home -> do- Directory.getHomeDirectory-- Absolute -> do- return "/"-- Parent -> do- pwd <- Directory.getCurrentDirectory- return (FilePath.takeDirectory pwd)-- Here -> do- Directory.getCurrentDirectory-- let cs = map Text.unpack (file : components)-- let cons component dir = dir </> component-- return (foldr cons prefixPath cs)---- | Parse an expression from a `Import` containing a Dhall program-exprFromImport :: Import -> StateT (Status IO) IO Resolved-exprFromImport here@(Import {..}) = do- let ImportHashed {..} = importHashed-- Status {..} <- State.get-- result <- Maybe.runMaybeT $ do- Just expectedHash <- return hash- cacheFile <- getCacheFile expectedHash- True <- liftIO (Directory.doesFileExist cacheFile)-- bytesStrict <- liftIO (Data.ByteString.readFile cacheFile)-- let actualHash = Crypto.Hash.hash bytesStrict-- if expectedHash == actualHash- then return ()- else throwMissingImport (Imported _stack (HashMismatch {..}))-- let bytesLazy = Data.ByteString.Lazy.fromStrict bytesStrict-- term <- Dhall.Core.throws (Codec.Serialise.deserialiseOrFail bytesLazy)-- Dhall.Core.throws (Dhall.Binary.decodeExpression term)-- case result of- Just resolvedExpression -> do- let newImport = here-- return (Resolved {..})- Nothing -> do- exprFromUncachedImport here--{-| Save an expression to the specified `Import`-- Currently this only works for cached imports and ignores other types of- imports, but could conceivably work for uncached imports in the future-- The main reason for this more general type is for symmetry with- `exprFromImport` and to support doing more clever things in the future,- like doing \"the right thing\" for uncached imports (i.e. exporting- environment variables or creating files)--}-exprToImport :: Import -> Expr Src X -> StateT (Status IO) IO ()-exprToImport here expression = do- Status {..} <- State.get-- let Import {..} = here-- let ImportHashed {..} = importHashed-- _ <- Maybe.runMaybeT $ do- Just expectedHash <- return hash- cacheFile <- getCacheFile expectedHash-- _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith _startingContext expression)-- let normalizedExpression =- Dhall.Core.alphaNormalize- (Dhall.Core.normalizeWith- _normalizer- expression- )-- let check version = do- let bytes = encodeExpression version normalizedExpression-- let actualHash = Crypto.Hash.hash bytes-- guard (expectedHash == actualHash)-- liftIO (Data.ByteString.writeFile cacheFile bytes)-- let fallback = do- let actualHash = hashExpression NoVersion normalizedExpression-- throwMissingImport (Imported _stack (HashMismatch {..}))-- Data.Foldable.asum (map check [ minBound .. maxBound ]) <|> fallback-- return ()--getCacheFile- :: (Alternative m, MonadIO m) => Crypto.Hash.Digest SHA256 -> m FilePath-getCacheFile hash = do- let assertDirectory directory = do- let private = transform Directory.emptyPermissions- where- transform =- Directory.setOwnerReadable True- . Directory.setOwnerWritable True- . Directory.setOwnerSearchable True-- let accessible path =- Directory.readable path- && Directory.writable path- && Directory.searchable path-- directoryExists <- liftIO (Directory.doesDirectoryExist directory)-- if directoryExists- then do- permissions <- liftIO (Directory.getPermissions directory)-- guard (accessible permissions)-- else do- assertDirectory (FilePath.takeDirectory directory)-- liftIO (Directory.createDirectory directory)-- liftIO (Directory.setPermissions directory private)-- cacheDirectory <- getCacheDirectory-- let dhallDirectory = cacheDirectory </> "dhall"-- assertDirectory dhallDirectory-- let cacheFile = dhallDirectory </> show hash-- return cacheFile--getCacheDirectory :: (Alternative m, MonadIO m) => m FilePath-getCacheDirectory = alternative₀ <|> alternative₁- where- alternative₀ = do- maybeXDGCacheHome <- do- liftIO (System.Environment.lookupEnv "XDG_CACHE_HOME")-- case maybeXDGCacheHome of- Just xdgCacheHome -> return xdgCacheHome- Nothing -> empty-- alternative₁ = do- maybeHomeDirectory <- liftIO (System.Environment.lookupEnv "HOME")-- case maybeHomeDirectory of- Just homeDirectory -> return (homeDirectory </> ".cache")- Nothing -> empty--exprFromUncachedImport :: Import -> StateT (Status IO) IO Resolved-exprFromUncachedImport import_@(Import {..}) = do- let ImportHashed {..} = importHashed-- (path, text, newImport) <- case importType of- Local prefix file -> liftIO $ do- path <- localToPath prefix file- exists <- Directory.doesFileExist path-- if exists- then return ()- else throwMissingImport (MissingFile path)-- text <- Data.Text.IO.readFile path-- return (path, text, import_)-- Remote url@URL { headers = maybeHeadersExpression } -> do- maybeHeadersAndExpression <- case maybeHeadersExpression of- Nothing -> do- return Nothing- Just headersExpression -> do- expr <- loadWith headersExpression-- let expected :: Expr Src X- expected =- App List- ( Record- ( Dhall.Map.fromList- [("header", Text), ("value", Text)]- )- )- let suffix_ = Dhall.Pretty.Internal.prettyToStrictText expected- let annot = case expr of- Note (Src begin end bytes) _ ->- Note (Src begin end bytes') (Annot expr expected)- where- bytes' = bytes <> " : " <> suffix_- _ ->- Annot expr expected-- case Dhall.TypeCheck.typeOf annot of- Left err -> liftIO (throwIO err)- Right _ -> return ()-- let expr' = Dhall.Core.normalize expr-- case toHeaders expr' of- Just headers -> do- return (Just (headers, expr'))- Nothing -> do- liftIO (throwIO InternalError)--#ifdef MIN_VERSION_http_client- let maybeHeaders = fmap fst maybeHeadersAndExpression-- let newHeaders =- fmap (fmap absurd . snd) maybeHeadersAndExpression-- (path, text) <- fetchFromHttpUrl url maybeHeaders-- let newImport = Import- { importHashed = ImportHashed- { importType =- Remote (url { headers = newHeaders })- , ..- }- , ..- }-- return (path, text, newImport)-#else- let urlString = Text.unpack (Dhall.Core.pretty url)-- liftIO (throwIO (CannotImportHTTPURL urlString mheaders))-#endif-- Env env -> liftIO $ do- x <- System.Environment.lookupEnv (Text.unpack env)- case x of- Just string -> do- return (Text.unpack env, Text.pack string, import_)- Nothing -> do- throwMissingImport (MissingEnvironmentVariable env)-- Missing -> liftIO $ do- throwM (MissingImports [])-- case importMode of- Code -> do- let parser = unParser $ do- Text.Parser.Token.whiteSpace- r <- Dhall.Parser.expr- Text.Parser.Combinators.eof- return r-- case Text.Megaparsec.parse parser path text of- Left errInfo -> do- liftIO (throwIO (ParseError errInfo text))- Right resolvedExpression -> do- return (Resolved {..})-- RawText -> do- let resolvedExpression = TextLit (Chunks [] text)-- return (Resolved {..})---- | Default starting `Status`, importing relative to the given directory.-emptyStatus :: FilePath -> Status IO-emptyStatus = emptyStatusWith exprFromImport exprToImport--{-| Generalized version of `load`-- You can configure the desired behavior through the initial `Status` that you- supply--}-loadWith :: MonadCatch m => Expr Src Import -> StateT (Status m) m (Expr Src X)-loadWith expr₀ = case expr₀ of- Embed import₀ -> do- Status {..} <- State.get-- let parent = NonEmpty.head _stack-- let import₁ = parent <> import₀-- let child = canonicalize import₁-- let local (Import (ImportHashed _ (Remote {})) _) = False- local (Import (ImportHashed _ (Local {})) _) = True- local (Import (ImportHashed _ (Env {})) _) = True- local (Import (ImportHashed _ (Missing {})) _) = True-- let referentiallySane = not (local child) || local parent-- if referentiallySane- then return ()- else throwMissingImport (Imported _stack (ReferentiallyOpaque import₀))-- let _stack' = NonEmpty.cons child _stack-- expr <- if child `elem` _stack- then throwMissingImport (Imported _stack (Cycle import₀))- else do- case Map.lookup child _cache of- Just (childNode, expr) -> do- zoom dot . State.modify $ \getDot -> do- parentNode <- getDot-- -- Add edge between parent and child- parentNode .->. childNode-- -- Return parent NodeId- pure parentNode-- pure expr- Nothing -> do- -- Here we have to match and unwrap the @MissingImports@- -- in a separate handler, otherwise we'd have it wrapped- -- in another @Imported@ when parsing a @missing@, because- -- we are representing it with an empty exception list- -- (which would not be empty if this would happen).- -- TODO: restructure the Exception hierarchy to prevent- -- this nesting from happening in the first place.- let handler₀- :: (MonadCatch m)- => MissingImports- -> StateT (Status m) m Resolved- handler₀ (MissingImports es) =- throwM- (MissingImports- (map- (\e -> toException (Imported _stack' e))- es- )- )-- handler₁- :: (MonadCatch m)- => SomeException- -> StateT (Status m) m Resolved- handler₁ e =- throwMissingImport (Imported _stack' e)-- -- This loads a \"dynamic\" expression (i.e. an expression- -- that might still contain imports)- let loadDynamic = _resolver child-- Resolved {..} <- loadDynamic `catches` [ Handler handler₀, Handler handler₁ ]-- let stackWithNewImport = NonEmpty.cons newImport _stack-- let childNodeId = userNodeId _nextNodeId-- -- Increment the next node id- zoom nextNodeId $ State.modify succ-- -- Make current node the dot graph- zoom dot . State.put $ importNode childNodeId child-- zoom stack (State.put stackWithNewImport)- expr'' <- loadWith resolvedExpression- zoom stack (State.put _stack)-- zoom dot . State.modify $ \getSubDot -> do- parentNode <- _dot-- -- Get current node back from sub-graph- childNode <- getSubDot-- -- Add edge between parent and child- parentNode .->. childNode-- -- Return parent NodeId- pure parentNode-- _cacher child expr''-- -- Type-check expressions here for three separate reasons:- --- -- * to verify that they are closed- -- * to catch type errors as early in the import process- -- as possible- -- * to avoid normalizing ill-typed expressions that need- -- to be hashed- --- -- There is no need to check expressions that have been- -- cached, since they have already been checked- expr''' <- case Dhall.TypeCheck.typeWith _startingContext expr'' of- Left err -> throwM (Imported _stack' err)- Right _ -> return (Dhall.Core.normalizeWith _normalizer expr'')- zoom cache (State.modify' (Map.insert child (childNodeId, expr''')))- return expr'''-- case hash (importHashed import₀) of- Nothing -> do- return ()- Just expectedHash -> do- let matches version =- let actualHash =- hashExpression version (Dhall.Core.alphaNormalize expr)-- in expectedHash == actualHash-- if any matches [ minBound .. maxBound ]- then return ()- else do- let actualHash =- hashExpression NoVersion (Dhall.Core.alphaNormalize expr)-- throwMissingImport (Imported _stack' (HashMismatch {..}))-- return expr- ImportAlt a b -> loadWith a `catch` handler₀- where- handler₀ (SourcedException (Src begin _ text₀) (MissingImports es₀)) =- loadWith b `catch` handler₁- where- handler₁ (SourcedException (Src _ end text₁) (MissingImports es₁)) =- throwM (SourcedException (Src begin end text₂) (MissingImports (es₀ ++ es₁)))- where- text₂ = text₀ <> " ? " <> text₁-- Const a -> pure (Const a)- Var a -> pure (Var a)- Lam a b c -> Lam <$> pure a <*> loadWith b <*> loadWith c- Pi a b c -> Pi <$> pure a <*> loadWith b <*> loadWith c- App a b -> App <$> loadWith a <*> loadWith b- Let as b -> Let <$> traverse f as <*> loadWith b- where- f (Binding c d e) = Binding c <$> traverse loadWith d <*> loadWith e- Annot a b -> Annot <$> loadWith a <*> loadWith b- Bool -> pure Bool- BoolLit a -> pure (BoolLit a)- BoolAnd a b -> BoolAnd <$> loadWith a <*> loadWith b- BoolOr a b -> BoolOr <$> loadWith a <*> loadWith b- BoolEQ a b -> BoolEQ <$> loadWith a <*> loadWith b- BoolNE a b -> BoolNE <$> loadWith a <*> loadWith b- BoolIf a b c -> BoolIf <$> loadWith a <*> loadWith b <*> loadWith c- Natural -> pure Natural- NaturalLit a -> pure (NaturalLit a)- NaturalFold -> pure NaturalFold- NaturalBuild -> pure NaturalBuild- NaturalIsZero -> pure NaturalIsZero- NaturalEven -> pure NaturalEven- NaturalOdd -> pure NaturalOdd- NaturalToInteger -> pure NaturalToInteger- NaturalShow -> pure NaturalShow- NaturalPlus a b -> NaturalPlus <$> loadWith a <*> loadWith b- NaturalTimes a b -> NaturalTimes <$> loadWith a <*> loadWith b- Integer -> pure Integer- IntegerLit a -> pure (IntegerLit a)- IntegerShow -> pure IntegerShow- IntegerToDouble -> pure IntegerToDouble- Double -> pure Double- DoubleLit a -> pure (DoubleLit a)- DoubleShow -> pure DoubleShow- Text -> pure Text- TextLit (Chunks a b) -> fmap TextLit (Chunks <$> mapM (mapM loadWith) a <*> pure b)- TextAppend a b -> TextAppend <$> loadWith a <*> loadWith b- TextShow -> pure TextShow- List -> pure List- ListLit a b -> ListLit <$> mapM loadWith a <*> mapM loadWith b- ListAppend a b -> ListAppend <$> loadWith a <*> loadWith b- ListBuild -> pure ListBuild- ListFold -> pure ListFold- ListLength -> pure ListLength- ListHead -> pure ListHead- ListLast -> pure ListLast- ListIndexed -> pure ListIndexed- ListReverse -> pure ListReverse- Optional -> pure Optional- None -> pure None- Some a -> Some <$> loadWith a- OptionalLit a b -> OptionalLit <$> loadWith a <*> mapM loadWith b- OptionalFold -> pure OptionalFold- OptionalBuild -> pure OptionalBuild- Record a -> Record <$> mapM loadWith a- RecordLit a -> RecordLit <$> mapM loadWith a- Union a -> Union <$> mapM (mapM loadWith) a- UnionLit a b c -> UnionLit <$> pure a <*> loadWith b <*> mapM (mapM loadWith) c- Combine a b -> Combine <$> loadWith a <*> loadWith b- CombineTypes a b -> CombineTypes <$> loadWith a <*> loadWith b- Prefer a b -> Prefer <$> loadWith a <*> loadWith b- Merge a b c -> Merge <$> loadWith a <*> loadWith b <*> mapM loadWith c- Field a b -> Field <$> loadWith a <*> pure b- Project a b -> Project <$> loadWith a <*> mapM loadWith b- Note a b -> do- let handler e = throwM (SourcedException a (e :: MissingImports))-- (Note <$> pure a <*> loadWith b) `catch` handler---- | Resolve all imports within an expression-load :: Expr Src Import -> IO (Expr Src X)-load expression = State.evalStateT (loadWith expression) (emptyStatus ".")--encodeExpression- :: forall s- . StandardVersion- -- ^ `Nothing` means to encode without the version tag- -> Expr s X- -> Data.ByteString.ByteString-encodeExpression _standardVersion expression = bytesStrict- where- intermediateExpression :: Expr s Import- intermediateExpression = fmap absurd expression-- term :: Term- term = Dhall.Binary.encode intermediateExpression-- taggedTerm :: Term- taggedTerm =- case _standardVersion of- NoVersion -> term- s -> TList [ TString v, term ]- where- v = Dhall.Binary.renderStandardVersion s-- bytesLazy = Codec.Serialise.serialise taggedTerm-- bytesStrict = Data.ByteString.Lazy.toStrict bytesLazy---- | Hash a fully resolved expression-hashExpression- :: StandardVersion -> Expr s X -> (Crypto.Hash.Digest SHA256)-hashExpression _standardVersion expression =- Crypto.Hash.hash (encodeExpression _standardVersion expression)--{-| Convenience utility to hash a fully resolved expression and return the- base-16 encoded hash with the @sha256:@ prefix-- In other words, the output of this function can be pasted into Dhall- source code to add an integrity check to an import--}-hashExpressionToCode :: StandardVersion -> Expr s X -> Text-hashExpressionToCode _standardVersion expr =- "sha256:" <> Text.pack (show (hashExpression _standardVersion expr))---- | A call to `assertNoImports` failed because there was at least one import-data ImportResolutionDisabled = ImportResolutionDisabled deriving (Exception)--instance Show ImportResolutionDisabled where- show _ = "\nImport resolution is disabled"---- | Assert than an expression is import-free-assertNoImports :: MonadIO io => Expr Src Import -> io (Expr Src X)-assertNoImports expression =- Dhall.Core.throws (traverse (\_ -> Left ImportResolutionDisabled) expression)+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++{-# OPTIONS_GHC -Wall #-}++{-| Dhall lets you import external expressions located either in local files or+ hosted on network endpoints.++ To import a local file as an expression, just insert the path to the file,+ prepending a @./@ if the path is relative to the current directory. For+ example, if you create a file named @id@ with the following contents:++ > $ cat id+ > λ(a : Type) → λ(x : a) → x++ Then you can use the file directly within a @dhall@ program just by+ referencing the file's path:++ > $ dhall+ > ./id Bool True+ > <Ctrl-D>+ > Bool+ >+ > True++ Imported expressions may contain imports of their own, too, which will+ continue to be resolved. However, Dhall will prevent cyclic imports. For+ example, if you had these two files:++ > $ cat foo+ > ./bar++ > $ cat bar+ > ./foo++ ... Dhall would throw the following exception if you tried to import @foo@:++ > $ dhall+ > ./foo+ > ^D+ > ↳ ./foo+ > ↳ ./bar+ >+ > Cyclic import: ./foo++ You can also import expressions hosted on network endpoints. Just use the+ URL++ > http://host[:port]/path++ The compiler expects the downloaded expressions to be in the same format+ as local files, specifically UTF8-encoded source code text.++ For example, if our @id@ expression were hosted at @http://example.com/id@,+ then we would embed the expression within our code using:++ > http://example.com/id++ You can also import expressions stored within environment variables using+ @env:NAME@, where @NAME@ is the name of the environment variable. For+ example:++ > $ export FOO=1+ > $ export BAR='"Hi"'+ > $ export BAZ='λ(x : Bool) → x == False'+ > $ dhall <<< "{ foo = env:FOO , bar = env:BAR , baz = env:BAZ }"+ > { bar : Text, baz : ∀(x : Bool) → Bool, foo : Integer }+ >+ > { bar = "Hi", baz = λ(x : Bool) → x == False, foo = 1 }++ If you wish to import the raw contents of an impoert as @Text@ then add+ @as Text@ to the end of the import:++ > $ dhall <<< "http://example.com as Text"+ > Text+ >+ > "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta+ > charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html+ > ; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,+ > initial-scale=1\" />\n <style type=\"text/css\">\n body {\n backgro+ > und-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-famil+ > y: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n+ > }\n div {\n width: 600px;\n margin: 5em auto;\n paddi+ > ng: 50px;\n background-color: #fff;\n border-radius: 1em;\n }\n+ > a:link, a:visited {\n color: #38488f;\n text-decoration: none;+ > \n }\n @media (max-width: 700px) {\n body {\n background+ > -color: #fff;\n }\n div {\n width: auto;\n m+ > argin: 0 auto;\n border-radius: 0;\n padding: 1em;\n+ > }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</+ > h1>\n <p>This domain is established to be used for illustrative examples in d+ > ocuments. You may use this\n domain in examples without prior coordination or+ > asking for permission.</p>\n <p><a href=\"http://www.iana.org/domains/exampl+ > e\">More information...</a></p>\n</div>\n</body>\n</html>\n"+-}++module Dhall.Import (+ -- * Import+ load+ , loadWithManager+ , loadRelativeTo+ , loadWithStatus+ , loadWith+ , localToPath+ , hashExpression+ , hashExpressionToCode+ , writeExpressionToSemanticCache+ , assertNoImports+ , Manager+ , defaultNewManager+ , CacheWarning(..)+ , Status(..)+ , SemanticCacheMode(..)+ , Chained+ , chainedImport+ , chainedFromLocalHere+ , chainedChangeMode+ , emptyStatus+ , emptyStatusWithManager+ , envOriginHeaders+ , makeEmptyStatus+ , remoteStatus+ , remoteStatusWithManager+ , fetchRemote+ , stack+ , cache+ , Depends(..)+ , graph+ , remote+ , toHeaders+ , substitutions+ , normalizer+ , startingContext+ , chainImport+ , dependencyToFile+ , ImportSemantics+ , HTTPHeader+ , Cycle(..)+ , ReferentiallyOpaque(..)+ , Imported(..)+ , ImportResolutionDisabled(..)+ , PrettyHttpException(..)+ , MissingFile(..)+ , MissingEnvironmentVariable(..)+ , MissingImports(..)+ , HashMismatch(..)+ ) where++import Control.Applicative (Alternative (..))+import Control.Exception+ ( Exception+ , IOException+ , SomeException+ , toException+ )+import Control.Monad.Catch (MonadCatch (catch), handle, throwM)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Morph (hoist)+import Control.Monad.State.Strict (MonadState, StateT)+import Data.ByteString (ByteString)+import Data.List.NonEmpty (NonEmpty (..), nonEmpty)+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import Data.Typeable (Typeable)+import Data.Void (Void, absurd)+import Dhall.TypeCheck (TypeError)+import Dhall.Util (printWarning)++import Dhall.Syntax+ ( Chunks (..)+ , Directory (..)+ , Expr (..)+ , File (..)+ , FilePrefix (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , URL (..)+ , bindingExprs+ , functionBindingExprs+ , recordFieldExprs+ )++import System.FilePath ((</>))+import Text.Megaparsec (SourcePos (SourcePos), mkPos)++#ifdef WITH_HTTP+import Dhall.Import.HTTP+#endif+import Dhall.Import.Headers+ ( normalizeHeaders+ , originHeadersTypeExpr+ , toHeaders+ , toOriginHeaders+ )+import Dhall.Import.Types++import Dhall.Parser+ ( ParseError (..)+ , Parser (..)+ , SourcedException (..)+ , Src (..)+ )+import Lens.Micro.Mtl (zoom)++import qualified Codec.CBOR.Write as Write+import qualified Codec.Serialise+import qualified Control.Exception as Exception+import qualified Control.Monad.State.Strict as State+import qualified Control.Monad.Trans.Maybe as Maybe+import qualified Data.ByteString+import qualified Data.ByteString.Lazy+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Maybe as Maybe+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Encoding+import qualified Data.Text.IO+import qualified Dhall.Binary+import qualified Dhall.Core as Core+import qualified Dhall.Crypto+import qualified Dhall.Map+import qualified Dhall.Parser+import qualified Dhall.Pretty.Internal+import qualified Dhall.Substitution+import qualified Dhall.Syntax as Syntax+import qualified Dhall.TypeCheck+import qualified System.AtomicWrite.Writer.ByteString.Binary as AtomicWrite.Binary+import qualified System.Directory as Directory+import qualified System.Environment+import qualified System.FilePath as FilePath+import qualified System.Info+import qualified System.IO+import qualified Text.Megaparsec+import qualified Text.Parser.Combinators+import qualified Text.Parser.Token++{- $setup++ >>> import Dhall.Syntax+-}++-- | An import failed because of a cycle in the import graph+newtype Cycle = Cycle+ { cyclicImport :: Import -- ^ The offending cyclic import+ }+ deriving (Typeable)++instance Exception Cycle++instance Show Cycle where+ show (Cycle import_) =+ "\nCyclic import: " ++ Dhall.Pretty.Internal.prettyToString import_++{-| Dhall tries to ensure that all expressions hosted on network endpoints are+ weakly referentially transparent, meaning roughly that any two clients will+ compile the exact same result given the same URL.++ To be precise, a strong interpretaton of referential transparency means that+ if you compiled a URL you could replace the expression hosted at that URL+ with the compiled result. Let's call this \"static linking\". Dhall (very+ intentionally) does not satisfy this stronger interpretation of referential+ transparency since \"statically linking\" an expression (i.e. permanently+ resolving all imports) means that the expression will no longer update if+ its dependencies change.++ In general, either interpretation of referential transparency is not+ enforceable in a networked context since one can easily violate referential+ transparency with a custom DNS, but Dhall can still try to guard against+ common unintentional violations. To do this, Dhall enforces that a+ non-local import may not reference a local import.++ Local imports are defined as:++ * A file++ * A URL with a host of @localhost@ or @127.0.0.1@++ All other imports are defined to be non-local+-}+newtype ReferentiallyOpaque = ReferentiallyOpaque+ { opaqueImport :: Import -- ^ The offending opaque import+ } deriving (Typeable)++instance Exception ReferentiallyOpaque++instance Show ReferentiallyOpaque where+ show (ReferentiallyOpaque import_) =+ "\nLocal imports are not permitted from remote imports: " ++ Dhall.Pretty.Internal.prettyToString import_++-- | Extend another exception with the current import stack+data Imported e = Imported+ { importStack :: NonEmpty Chained -- ^ Imports resolved so far, in reverse order+ , nested :: e -- ^ The nested exception+ } deriving (Typeable)++instance Exception e => Exception (Imported e)++instance Show e => Show (Imported e) where+ show (Imported canonicalizedImports e) =+ concat (zipWith indent [0..] toDisplay)+ ++ "\n"+ ++ show e+ where+ indent n import_ =+ "\n" ++ replicate (2 * n) ' ' ++ "↳ " ++ Dhall.Pretty.Internal.prettyToString import_++ canonical = NonEmpty.toList canonicalizedImports++ -- Tthe final (outermost) import is fake to establish the base+ -- directory. Also, we need outermost-first.+ toDisplay = drop 1 (reverse canonical)++-- | Exception thrown when an imported file is missing+newtype MissingFile = MissingFile FilePath+ deriving (Typeable)++instance Exception MissingFile++instance Show MissingFile where+ show (MissingFile path) =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Missing file "+ <> path++-- | Exception thrown when an environment variable is missing+newtype MissingEnvironmentVariable = MissingEnvironmentVariable { name :: Text }+ deriving (Typeable)++instance Exception MissingEnvironmentVariable++instance Show MissingEnvironmentVariable where+ show MissingEnvironmentVariable{..} =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Missing environment variable\n"+ <> "\n"+ <> "↳ " <> Text.unpack name++-- | List of Exceptions we encounter while resolving Import Alternatives+newtype MissingImports = MissingImports [SomeException]++instance Exception MissingImports++instance Show MissingImports where+ show (MissingImports []) =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: No valid imports"+ show (MissingImports [e]) = show e+ show (MissingImports es) =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Failed to resolve imports. Error list:"+ <> "\n"+ <> concatMap (\e -> "\n" <> show e <> "\n") es++throwMissingImport :: (MonadCatch m, Exception e) => e -> m a+throwMissingImport e = throwM (MissingImports [toException e])++-- | Exception thrown when a HTTP url is imported but dhall was built without+-- the @with-http@ Cabal flag.+data CannotImportHTTPURL =+ CannotImportHTTPURL+ String+ (Maybe [HTTPHeader])+ deriving (Typeable)++instance Exception CannotImportHTTPURL++instance Show CannotImportHTTPURL where+ show (CannotImportHTTPURL url _mheaders) =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: Cannot import HTTP URL.\n"+ <> "\n"+ <> "Dhall was compiled without the 'with-http' flag.\n"+ <> "\n"+ <> "The requested URL was: "+ <> url+ <> "\n"++{-|+> canonicalize . canonicalize = canonicalize++> canonicalize (a <> b) = canonicalize (canonicalize a <> canonicalize b)+-}+class Semigroup path => Canonicalize path where+ canonicalize :: path -> path++-- |+-- >>> canonicalize (Directory {components = ["..",".."]})+-- Directory {components = ["..",".."]}+instance Canonicalize Directory where+ canonicalize (Directory []) = Directory []++ canonicalize (Directory ("." : components₀)) =+ canonicalize (Directory components₀)++ canonicalize (Directory (".." : components₀)) =+ case canonicalize (Directory components₀) of+ Directory [] ->+ Directory [ ".." ]+ Directory (".." : components₁) ->+ Directory (".." : ".." : components₁)+ Directory (_ : components₁) ->+ Directory components₁++ canonicalize (Directory (component : components₀)) =+ Directory (component : components₁)+ where+ Directory components₁ = canonicalize (Directory components₀)++instance Canonicalize File where+ canonicalize (File { directory, .. }) =+ File { directory = canonicalize directory, .. }++instance Canonicalize ImportType where+ canonicalize (Local prefix file) =+ Local prefix (canonicalize file)++ canonicalize (Remote (URL {..})) =+ Remote (URL { path = canonicalize path, headers = fmap (fmap canonicalize) headers, ..})++ canonicalize (Env name) =+ Env name++ canonicalize Missing =+ Missing++instance Canonicalize ImportHashed where+ canonicalize (ImportHashed hash importType) =+ ImportHashed hash (canonicalize importType)++instance Canonicalize Import where+ canonicalize (Import importHashed importMode) =+ Import (canonicalize importHashed) importMode++-- | Exception thrown when an integrity check fails+data HashMismatch = HashMismatch+ { expectedHash :: Dhall.Crypto.SHA256Digest+ , actualHash :: Dhall.Crypto.SHA256Digest+ } deriving (Typeable)++instance Exception HashMismatch++instance Show HashMismatch where+ show HashMismatch{..} =+ "\n"+ <> "\ESC[1;31mError\ESC[0m: " <> makeHashMismatchMessage expectedHash actualHash++makeHashMismatchMessage :: Dhall.Crypto.SHA256Digest -> Dhall.Crypto.SHA256Digest -> String+makeHashMismatchMessage expectedHash actualHash =+ "Import integrity check failed\n"+ <> "\n"+ <> "Expected hash:\n"+ <> "\n"+ <> "↳ " <> show expectedHash <> "\n"+ <> "\n"+ <> "Actual hash:\n"+ <> "\n"+ <> "↳ " <> show actualHash <> "\n"++-- | Construct the file path corresponding to a local import. If the import is+-- _relative_ then the resulting path is also relative.+localToPath :: MonadIO io => FilePrefix -> File -> io FilePath+localToPath prefix file_ = liftIO $ do+ let File {..} = file_++ let Directory {..} = directory++ prefixPath <- case prefix of+ Home ->+ Directory.getHomeDirectory++ Absolute ->+ return "/"++ Parent ->+ return ".."++ Here ->+ return "."++ let cs = map Text.unpack (file : components)++ let cons component dir = dir </> component++ return (foldr cons prefixPath cs)++-- | Given a `Local` import construct the corresponding unhashed `Chained`+-- import (interpreting relative path as relative to the current directory).+chainedFromLocalHere :: FilePrefix -> File -> ImportMode -> Chained+chainedFromLocalHere prefix file mode = Chained $+ Import (ImportHashed Nothing (Local prefix (canonicalize file))) mode++-- | Adjust the import mode of a chained import+chainedChangeMode :: ImportMode -> Chained -> Chained+chainedChangeMode mode (Chained (Import importHashed _)) =+ Chained (Import importHashed mode)++-- | Chain imports, also typecheck and normalize headers if applicable.+chainImport :: Chained -> Import -> StateT Status IO Chained+chainImport (Chained parent) child@(Import importHashed@(ImportHashed _ (Remote url)) _) = do+ url' <- normalizeHeadersIn url+ let child' = child { importHashed = importHashed { importType = Remote url' } }+ return (Chained (canonicalize (parent <> child')))++chainImport (Chained parent) child =+ return (Chained (canonicalize (parent <> child)))++-- | Load an import, resulting in a fully resolved, type-checked and normalised+-- expression. @loadImport@ handles the \"hot\" cache in @Status@ and defers+-- to @loadImportWithSemanticCache@ for imports that aren't in the @Status@+-- cache already.+loadImport :: Chained -> StateT Status IO ImportSemantics+loadImport import_ = do+ Status {..} <- State.get++ case Dhall.Map.lookup import_ _cache of+ Just importSemantics -> return importSemantics+ Nothing -> do+ importSemantics <- loadImportWithSemanticCache import_+ zoom cache (State.modify (Dhall.Map.insert import_ importSemantics))+ return importSemantics++-- | Load an import from the 'semantic cache'. Defers to+-- @loadImportWithSemisemanticCache@ for imports that aren't frozen (and+-- therefore not cached semantically), as well as those that aren't cached yet.+loadImportWithSemanticCache :: Chained -> StateT Status IO ImportSemantics+loadImportWithSemanticCache+ import_@(Chained (Import (ImportHashed Nothing _) _)) =+ loadImportWithSemisemanticCache import_++loadImportWithSemanticCache+ import_@(Chained (Import _ Location)) =+ loadImportWithSemisemanticCache import_++loadImportWithSemanticCache+ import_@(Chained (Import (ImportHashed (Just semanticHash) _) _)) = do+ Status { .. } <- State.get+ mCached <-+ case _semanticCacheMode of+ UseSemanticCache ->+ zoom cacheWarning (fetchFromSemanticCache semanticHash)+ IgnoreSemanticCache ->+ pure Nothing++ case mCached of+ Just bytesStrict -> do+ let actualHash = Dhall.Crypto.sha256Hash bytesStrict++ if semanticHash == actualHash+ then do+ let bytesLazy = Data.ByteString.Lazy.fromStrict bytesStrict++ importSemantics <- case Dhall.Binary.decodeExpression bytesLazy of+ Left err -> throwMissingImport (Imported _stack err)+ Right e -> return e++ return (ImportSemantics {..})+ else do+ printWarning $+ makeHashMismatchMessage semanticHash actualHash+ <> "\n"+ <> "The interpreter will attempt to fix the cached import\n"+ fetch+++ Nothing -> fetch+ where+ fetch = do+ ImportSemantics{ importSemantics } <- loadImportWithSemisemanticCache import_++ let bytes = encodeExpression (Core.alphaNormalize importSemantics)++ let actualHash = Dhall.Crypto.sha256Hash bytes++ let expectedHash = semanticHash++ if actualHash == expectedHash+ then do+ zoom cacheWarning (writeToSemanticCache semanticHash bytes)++ else do+ Status{ _stack } <- State.get++ throwMissingImport (Imported _stack HashMismatch{..})++ return ImportSemantics{..}++++-- Fetch encoded normal form from "semantic cache"+fetchFromSemanticCache+ :: (MonadState CacheWarning m, MonadCatch m, MonadIO m)+ => Dhall.Crypto.SHA256Digest+ -> m (Maybe Data.ByteString.ByteString)+fetchFromSemanticCache expectedHash = Maybe.runMaybeT $ do+ cacheFile <- getCacheFile "dhall" expectedHash+ True <- liftIO (Directory.doesFileExist cacheFile)+ liftIO (Data.ByteString.readFile cacheFile)++-- | Ensure that the given expression is present in the semantic cache. The+-- given expression should be alpha-beta-normal.+writeExpressionToSemanticCache :: Expr Void Void -> IO ()+writeExpressionToSemanticCache expression =+ -- Defaulting to not displaying the warning is for backwards compatibility+ -- with the old behavior+ State.evalStateT (writeToSemanticCache hash bytes) CacheWarned+ where+ bytes = encodeExpression expression++ hash = Dhall.Crypto.sha256Hash bytes++writeToSemanticCache+ :: (MonadState CacheWarning m, MonadCatch m, MonadIO m)+ => Dhall.Crypto.SHA256Digest+ -> Data.ByteString.ByteString+ -> m ()+writeToSemanticCache hash bytes = do+ _ <- Maybe.runMaybeT $ do+ cacheFile <- getCacheFile "dhall" hash+ liftIO (AtomicWrite.Binary.atomicWriteFile cacheFile bytes)+ return ()++-- Check the "semi-semantic" disk cache, otherwise typecheck and normalise from+-- scratch.+loadImportWithSemisemanticCache+ :: Chained -> StateT Status IO ImportSemantics+loadImportWithSemisemanticCache (Chained (Import (ImportHashed _ importType) Code)) = do+ text <- fetchFresh importType+ Status {..} <- State.get++ path <- case importType of+ Local prefix file -> liftIO $ do+ path <- localToPath prefix file+ absolutePath <- Directory.makeAbsolute path+ return absolutePath+ Remote url -> do+ let urlText = Core.pretty (url { headers = Nothing })+ return (Text.unpack urlText)+ Env env -> return $ Text.unpack env+ Missing -> throwM (MissingImports [])++ let parser = unParser $ do+ Text.Parser.Token.whiteSpace+ r <- Dhall.Parser.expr+ Text.Parser.Combinators.eof+ return r++ parsedImport <- case Text.Megaparsec.parse parser path text of+ Left errInfo ->+ throwMissingImport (Imported _stack (ParseError errInfo text))+ Right expr -> return expr++ resolvedExpr <- loadWith parsedImport -- we load imports recursively here++ -- Check the semi-semantic cache. See+ -- https://github.com/dhall-lang/dhall-haskell/issues/1098 for the reasoning+ -- behind semi-semantic caching.+ let semisemanticHash = computeSemisemanticHash (Core.denote resolvedExpr)++ mCached <- zoom cacheWarning (fetchFromSemisemanticCache semisemanticHash)++ importSemantics <- case mCached of+ Just bytesStrict -> do+ let bytesLazy = Data.ByteString.Lazy.fromStrict bytesStrict++ importSemantics <- case Dhall.Binary.decodeExpression bytesLazy of+ Left err -> throwMissingImport (Imported _stack err)+ Right sem -> return sem++ return importSemantics++ Nothing -> do+ let substitutedExpr =+ Dhall.Substitution.substitute resolvedExpr _substitutions++ case Core.shallowDenote parsedImport of+ -- If this import trivially wraps another import, we can skip+ -- the type-checking and normalization step as the transitive+ -- import was already type-checked and normalized+ Embed _ ->+ return (Core.denote substitutedExpr)++ _ -> do+ case Dhall.TypeCheck.typeWith _startingContext substitutedExpr of+ Left err -> throwMissingImport (Imported _stack err)+ Right _ -> return ()++ let betaNormal =+ Core.normalizeWith _normalizer substitutedExpr++ let bytes = encodeExpression betaNormal++ zoom cacheWarning (writeToSemisemanticCache semisemanticHash bytes)++ return betaNormal++ return (ImportSemantics {..})++-- `as Text` and `as Bytes` imports aren't cached since they are well-typed and+-- normal by construction+loadImportWithSemisemanticCache (Chained (Import (ImportHashed _ importType) RawText)) = do+ text <- fetchFresh importType++ -- importSemantics is alpha-beta-normal by construction!+ let importSemantics = TextLit (Chunks [] text)+ return (ImportSemantics {..})+loadImportWithSemisemanticCache (Chained (Import (ImportHashed _ importType) RawBytes)) = do+ bytes <- fetchBytes importType++ -- importSemantics is alpha-beta-normal by construction!+ let importSemantics = BytesLit bytes+ return (ImportSemantics {..})++-- `as Location` imports aren't cached since they are well-typed and normal by+-- construction+loadImportWithSemisemanticCache (Chained (Import (ImportHashed _ importType) Location)) = do+ let locationType = Union $ Dhall.Map.fromList+ [ ("Environment", Just Text)+ , ("Remote", Just Text)+ , ("Local", Just Text)+ , ("Missing", Nothing)+ ]++ -- importSemantics is alpha-beta-normal by construction!+ let importSemantics = case importType of+ Missing -> Field locationType $ Core.makeFieldSelection "Missing"+ local@(Local _ _) ->+ App (Field locationType $ Core.makeFieldSelection "Local")+ (TextLit (Chunks [] (Core.pretty local)))+ remote_@(Remote _) ->+ App (Field locationType $ Core.makeFieldSelection "Remote")+ (TextLit (Chunks [] (Core.pretty remote_)))+ Env env ->+ App (Field locationType $ Core.makeFieldSelection "Environment")+ (TextLit (Chunks [] (Core.pretty env)))++ return (ImportSemantics {..})++-- The semi-semantic hash of an expression is computed from the fully resolved+-- AST (without normalising or type-checking it first). See+-- https://github.com/dhall-lang/dhall-haskell/issues/1098 for further+-- discussion.+computeSemisemanticHash :: Expr Void Void -> Dhall.Crypto.SHA256Digest+computeSemisemanticHash resolvedExpr = hashExpression resolvedExpr++-- Fetch encoded normal form from "semi-semantic cache"+fetchFromSemisemanticCache+ :: (MonadState CacheWarning m, MonadCatch m, MonadIO m)+ => Dhall.Crypto.SHA256Digest+ -> m (Maybe Data.ByteString.ByteString)+fetchFromSemisemanticCache semisemanticHash = Maybe.runMaybeT $ do+ cacheFile <- getCacheFile "dhall-haskell" semisemanticHash+ True <- liftIO (Directory.doesFileExist cacheFile)+ liftIO (Data.ByteString.readFile cacheFile)++writeToSemisemanticCache+ :: (MonadState CacheWarning m, MonadCatch m, MonadIO m)+ => Dhall.Crypto.SHA256Digest+ -> Data.ByteString.ByteString+ -> m ()+writeToSemisemanticCache semisemanticHash bytes = do+ _ <- Maybe.runMaybeT $ do+ cacheFile <- getCacheFile "dhall-haskell" semisemanticHash+ liftIO (AtomicWrite.Binary.atomicWriteFile cacheFile bytes)+ return ()++-- | Fetch source code directly from disk/network+fetchFresh :: ImportType -> StateT Status IO Text+fetchFresh (Local prefix file) = do+ Status { _stack } <- State.get+ path <- liftIO $ localToPath prefix file+ exists <- liftIO $ Directory.doesFileExist path+ if exists+ then liftIO $ Data.Text.IO.readFile path+ else throwMissingImport (Imported _stack (MissingFile path))++fetchFresh (Remote url) = do+ Status { _remote } <- State.get+ _remote url++fetchFresh (Env env) = do+ Status { _stack } <- State.get+ x <- liftIO $ System.Environment.lookupEnv (Text.unpack env)+ case x of+ Just string ->+ return (Text.pack string)+ Nothing ->+ throwMissingImport (Imported _stack (MissingEnvironmentVariable env))++fetchFresh Missing = throwM (MissingImports [])++-- | Like `fetchFresh`, except for `Dhall.Syntax.Expr.Bytes`+fetchBytes :: ImportType -> StateT Status IO ByteString+fetchBytes (Local prefix file) = do+ Status { _stack } <- State.get+ path <- liftIO $ localToPath prefix file+ exists <- liftIO $ Directory.doesFileExist path+ if exists+ then liftIO $ Data.ByteString.readFile path+ else throwMissingImport (Imported _stack (MissingFile path))++fetchBytes (Remote url) = do+ Status { _remoteBytes } <- State.get+ _remoteBytes url++fetchBytes (Env env) = do+ Status { _stack } <- State.get+ x <- liftIO $ System.Environment.lookupEnv (Text.unpack env)+ case x of+ Just string ->+ return (Encoding.encodeUtf8 (Text.pack string))+ Nothing ->+ throwMissingImport (Imported _stack (MissingEnvironmentVariable env))+fetchBytes Missing = throwM (MissingImports [])++-- | Fetch the text contents of a URL+fetchRemote :: URL -> StateT Status IO Data.Text.Text+#ifndef WITH_HTTP+fetchRemote (url@URL { headers = maybeHeadersExpression }) = do+ let maybeHeaders = fmap toHeaders maybeHeadersExpression+ let urlString = Text.unpack (Core.pretty url)+ Status { _stack } <- State.get+ throwMissingImport (Imported _stack (CannotImportHTTPURL urlString maybeHeaders))+#else+fetchRemote url = do+ zoom remote (State.put fetchFromHTTP)+ fetchFromHTTP url+ where+ fetchFromHTTP :: URL -> StateT Status IO Data.Text.Text+ fetchFromHTTP (url'@URL { headers = maybeHeadersExpression }) = do+ let maybeHeaders = fmap toHeaders maybeHeadersExpression+ fetchFromHttpUrl url' maybeHeaders+#endif++-- | Fetch the text contents of a URL+fetchRemoteBytes :: URL -> StateT Status IO Data.ByteString.ByteString+#ifndef WITH_HTTP+fetchRemoteBytes (url@URL { headers = maybeHeadersExpression }) = do+ let maybeHeaders = fmap toHeaders maybeHeadersExpression+ let urlString = Text.unpack (Core.pretty url)+ Status { _stack } <- State.get+ throwMissingImport (Imported _stack (CannotImportHTTPURL urlString maybeHeaders))+#else+fetchRemoteBytes url = do+ zoom remoteBytes (State.put fetchFromHTTP)+ fetchFromHTTP url+ where+ fetchFromHTTP :: URL -> StateT Status IO Data.ByteString.ByteString+ fetchFromHTTP (url'@URL { headers = maybeHeadersExpression }) = do+ let maybeHeaders = fmap toHeaders maybeHeadersExpression+ fetchFromHttpUrlBytes url' maybeHeaders+#endif++getCacheFile+ :: (MonadCatch m, Alternative m, MonadState CacheWarning m, MonadIO m)+ => FilePath -> Dhall.Crypto.SHA256Digest -> m FilePath+getCacheFile cacheName hash = do+ cacheDirectory <- getOrCreateCacheDirectory cacheName++ let cacheFile = cacheDirectory </> ("1220" <> show hash)++ return cacheFile++getOrCreateCacheDirectory+ :: (MonadCatch m, Alternative m, MonadState CacheWarning m, MonadIO m)+ => FilePath -> m FilePath+getOrCreateCacheDirectory cacheName = do+ let warn message = do+ cacheWarningStatus <- State.get++ case cacheWarningStatus of+ CacheWarned -> printWarning message+ CacheNotWarned -> return ()++ State.put CacheWarned++ empty++ let handler action dir (ioex :: IOException) = do+ let ioExMsg =+ "When trying to " <> action <> ":\n"+ <> "\n"+ <> "↳ " <> dir <> "\n"+ <> "\n"+ <> "... the following exception was thrown:\n"+ <> "\n"+ <> "↳ " <> show ioex <> "\n"++ warn ioExMsg++ let setPermissions dir = do+ let private = transform Directory.emptyPermissions+ where+ transform =+ Directory.setOwnerReadable True+ . Directory.setOwnerWritable True+ . Directory.setOwnerSearchable True++ catch+ (liftIO (Directory.setPermissions dir private))+ (handler "correct the permissions for" dir)++ let assertPermissions dir = do+ let accessible path =+ Directory.readable path+ && Directory.writable path+ && Directory.searchable path++ permissions <-+ catch (liftIO (Directory.getPermissions dir))+ (handler "get permissions of" dir)++ if accessible permissions+ then+ return ()+ else do+ let render f = if f permissions then "✓" else "✗"+ let message =+ "The directory:\n"+ <> "\n"+ <> "↳ " <> dir <> "\n"+ <> "\n"+ <> "... does not give you permission to read, write, or search files.\n\n"+ <> "\n"+ <> "The directory's current permissions are:\n"+ <> "\n"+ <> "• " <> render Directory.readable <> " readable\n"+ <> "• " <> render Directory.writable <> " writable\n"+ <> "• " <> render Directory.searchable <> " searchable\n"++ warn message++ let existsDirectory dir =+ catch (liftIO (Directory.doesDirectoryExist dir))+ (handler "check the existence of" dir)++ let existsFile path =+ catch (liftIO (Directory.doesFileExist path))+ (handler "check the existence of" path)++ let createDirectory dir =+ catch (liftIO (Directory.createDirectory dir))+ (handler "create" dir)++ let assertDirectory dir = do+ existsDir <- existsDirectory dir++ if existsDir+ then+ assertPermissions dir++ else do+ existsFile' <- existsFile dir++ if existsFile'+ then do+ let message =+ "The given path:\n"+ <> "\n"+ <> "↳ " <> dir <> "\n"+ <> "\n"+ <> "... already exists but is not a directory.\n"++ warn message++ else do+ assertDirectory (FilePath.takeDirectory dir)++ createDirectory dir++ setPermissions dir++ cacheBaseDirectory <- getCacheBaseDirectory++ let directory = cacheBaseDirectory </> cacheName++ let message =+ "Could not get or create the default cache directory:\n"+ <> "\n"+ <> "↳ " <> directory <> "\n"+ <> "\n"+ <> "You can enable caching by creating it if needed and setting read,\n"+ <> "write and search permissions on it or providing another cache base\n"+ <> "directory by setting the $XDG_CACHE_HOME environment variable.\n"+ <> "\n"++ assertDirectory directory <|> warn message++ return directory++getCacheBaseDirectory+ :: (MonadState CacheWarning m, Alternative m, MonadIO m) => m FilePath+getCacheBaseDirectory = alternative₀ <|> alternative₁ <|> alternative₂+ where+ alternative₀ = do+ maybeXDGCacheHome <-+ liftIO (System.Environment.lookupEnv "XDG_CACHE_HOME")++ case maybeXDGCacheHome of+ Just xdgCacheHome -> return xdgCacheHome+ Nothing -> empty++ alternative₁+ | isWindows = do+ maybeLocalAppDirectory <-+ liftIO (System.Environment.lookupEnv "LOCALAPPDATA")++ case maybeLocalAppDirectory of+ Just localAppDirectory -> return localAppDirectory+ Nothing -> empty++ | otherwise = do+ maybeHomeDirectory <-+ liftIO (System.Environment.lookupEnv "HOME")++ case maybeHomeDirectory of+ Just homeDirectory -> return (homeDirectory </> ".cache")+ Nothing -> empty++ where isWindows = System.Info.os == "mingw32"++ alternative₂ = do+ cacheWarningStatus <- State.get++ let message =+ "\n"+ <> "\ESC[1;33mWarning\ESC[0m: "+ <> "Could not locate a cache base directory from the environment.\n"+ <> "\n"+ <> "You can provide a cache base directory by pointing the $XDG_CACHE_HOME\n"+ <> "environment variable to a directory with read and write permissions.\n"++ case cacheWarningStatus of+ CacheNotWarned ->+ liftIO (System.IO.hPutStrLn System.IO.stderr message)+ CacheWarned ->+ return ()++ State.put CacheWarned++ empty++-- If the URL contains headers typecheck them and replace them with their normal+-- forms.+normalizeHeadersIn :: URL -> StateT Status IO URL+normalizeHeadersIn url@URL { headers = Just headersExpression } = do+ Status { _stack } <- State.get+ loadedExpr <- loadWith headersExpression+ let handler (e :: SomeException) = throwMissingImport (Imported _stack e)+ normalized <- liftIO $ handle handler (normalizeHeaders loadedExpr)+ return url { headers = Just (fmap absurd normalized) }++normalizeHeadersIn url = return url++-- | Empty origin headers used for remote contexts+-- (and fallback when nothing is set in env or config file)+emptyOriginHeaders :: Expr Src Import+emptyOriginHeaders = ListLit (Just (fmap absurd originHeadersTypeExpr)) mempty++-- | A fake Src to annotate headers expressions with.+-- We need to wrap headers expressions in a Note for nice error reporting,+-- and because ImportAlt handling only catches SourcedExceptions+headersSrc :: Src+headersSrc = Src {+ srcStart = SourcePos {+ sourceName = fakeSrcName,+ sourceLine = mkPos 1,+ sourceColumn = mkPos 1+ },+ srcEnd = SourcePos {+ sourceName = fakeSrcName,+ sourceLine = mkPos 1,+ sourceColumn = mkPos (Text.length fakeSrcText)+ },+ srcText = fakeSrcText+ }+ where+ fakeSrcText = "«Origin Header Configuration»"+ fakeSrcName = "[builtin]"++-- | Load headers only from the environment (used in tests)+envOriginHeaders :: Expr Src Import+envOriginHeaders = Note headersSrc (Embed (Import (ImportHashed Nothing (Env "DHALL_HEADERS")) Code))++-- | Load headers in env, falling back to config file+defaultOriginHeaders :: IO (Expr Src Import)+#ifndef WITH_HTTP+defaultOriginHeaders = return emptyOriginHeaders+#else+defaultOriginHeaders = do+ fromFile <- originHeadersFileExpr+ return (Note headersSrc (ImportAlt envOriginHeaders (Note headersSrc fromFile)))+#endif++-- | Given a headers expression, return an origin headers loader+originHeadersLoader :: IO (Expr Src Import) -> StateT Status IO OriginHeaders+originHeadersLoader headersExpr = do++ -- Load the headers using the parent stack, which should always be a local+ -- import (we only load headers for the first remote import)++ status <- State.get++ let parentStack = fromMaybe abortEmptyStack (nonEmpty (NonEmpty.tail (_stack status)))++ let headerLoadStatus = status { _stack = parentStack }++ (headers, _) <- liftIO (State.runStateT doLoad headerLoadStatus)++ -- return cached headers next time+ _ <- State.modify (\state -> state { _loadOriginHeaders = return headers })++ return headers+ where+ abortEmptyStack = Core.internalError "Origin headers loaded with an empty stack"++ doLoad = do+ partialExpr <- liftIO headersExpr+ loaded <- loadWith (Note headersSrc (ImportAlt partialExpr emptyOriginHeaders))+ liftIO (toOriginHeaders loaded)++-- | Default starting `Status`, importing relative to the given directory.+emptyStatus :: FilePath -> Status+emptyStatus = makeEmptyStatus defaultNewManager defaultOriginHeaders++-- | See 'emptyStatus'+emptyStatusWithManager+ :: IO Manager+ -> FilePath+ -> Status+emptyStatusWithManager newManager = makeEmptyStatus newManager defaultOriginHeaders++-- | See 'emptyStatus'.+makeEmptyStatus+ :: IO Manager+ -> IO (Expr Src Import)+ -> FilePath+ -> Status+makeEmptyStatus newManager headersExpr rootDirectory =+ emptyStatusWith newManager (originHeadersLoader headersExpr) fetchRemote fetchRemoteBytes rootImport+ where+ prefix = if FilePath.isRelative rootDirectory+ then Here+ else Absolute++ pathComponents =+ fmap Text.pack (reverse (FilePath.splitDirectories rootDirectory))++ directoryAsFile = File (Directory pathComponents) "."++ rootImport = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local prefix directoryAsFile+ }+ , importMode = Code+ }++{-| Default `Status` appropriate for a server interpreting Dhall code++ Using this `Status` ensures that interpreted Dhall code cannot access+ server-local resources (like files or environment variables)+-}+remoteStatus+ :: URL+ -- ^ Public address of the server+ -> Status+remoteStatus = remoteStatusWithManager defaultNewManager++-- | See `remoteStatus`+remoteStatusWithManager :: IO Manager -> URL -> Status+remoteStatusWithManager newManager url =+ emptyStatusWith newManager (originHeadersLoader (pure emptyOriginHeaders)) fetchRemote fetchRemoteBytes rootImport+ where+ rootImport = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Remote url+ }+ , importMode = Code+ }++{-| Generalized version of `load`++ You can configure the desired behavior through the initial `Status` that you+ supply+-}+loadWith :: Expr Src Import -> StateT Status IO (Expr Src Void)+loadWith expr₀ = case expr₀ of+ Embed import₀ -> do+ Status {..} <- State.get++ let parent = NonEmpty.head _stack++ child <- chainImport parent import₀++ let local (Chained (Import (ImportHashed _ (Remote {})) _)) = False+ local (Chained (Import (ImportHashed _ (Local {})) _)) = True+ local (Chained (Import (ImportHashed _ (Env {})) _)) = True+ local (Chained (Import (ImportHashed _ (Missing {})) _)) = False++ let referentiallySane = not (local child) || local parent++ if importMode import₀ == Location || referentiallySane+ then return ()+ else throwMissingImport (Imported _stack (ReferentiallyOpaque import₀))++ let _stack' = NonEmpty.cons child _stack++ if child `elem` _stack+ then throwMissingImport (Imported _stack (Cycle import₀))+ else return ()++ zoom graph . State.modify $+ -- Add the edge `parent -> child` to the import graph+ \edges -> Depends parent child : edges++ let stackWithChild = NonEmpty.cons child _stack++ zoom stack (State.put stackWithChild)+ ImportSemantics {..} <- loadImport child+ zoom stack (State.put _stack)++ return (Core.renote importSemantics)++ ImportAlt a b -> loadWith a `catch` handler₀+ where+ is :: forall e . Exception e => SomeException -> Bool+ is exception = Maybe.isJust (Exception.fromException @e exception)++ isNotResolutionError exception =+ is @(Imported (TypeError Src Void)) exception+ || is @(Imported Cycle ) exception+ || is @(Imported HashMismatch ) exception+ || is @(Imported ParseError ) exception++ handler₀ exception₀@(SourcedException (Src begin _ text₀) (MissingImports es₀))+ | any isNotResolutionError es₀ =+ throwM exception₀+ | otherwise = do+ loadWith b `catch` handler₁+ where+ handler₁ exception₁@(SourcedException (Src _ end text₁) (MissingImports es₁))+ | any isNotResolutionError es₁ =+ throwM exception₁+ | otherwise =+ -- Fix the source span for the error message to encompass both+ -- alternatives, since both are equally to blame for the+ -- failure if neither succeeds.+ throwM (SourcedException (Src begin end text₂) (MissingImports (es₀ ++ es₁)))+ where+ text₂ = text₀ <> " ? " <> text₁++ Note a b -> do+ let handler e = throwM (SourcedException a (e :: MissingImports))++ (Note <$> pure a <*> loadWith b) `catch` handler+ Let a b -> Let <$> bindingExprs loadWith a <*> loadWith b+ Record m -> Record <$> traverse (recordFieldExprs loadWith) m+ RecordLit m -> RecordLit <$> traverse (recordFieldExprs loadWith) m+ Lam cs a b -> Lam cs <$> functionBindingExprs loadWith a <*> loadWith b+ Field a b -> Field <$> loadWith a <*> pure b+ expression -> Syntax.unsafeSubExpressions loadWith expression++-- | Resolve all imports within an expression+load :: Expr Src Import -> IO (Expr Src Void)+load = loadWithManager defaultNewManager++-- | See 'load'.+loadWithManager :: IO Manager -> Expr Src Import -> IO (Expr Src Void)+loadWithManager newManager =+ loadWithStatus+ (makeEmptyStatus newManager defaultOriginHeaders ".")+ UseSemanticCache++-- | Resolve all imports within an expression, importing relative to the given+-- directory.+loadRelativeTo :: FilePath -> SemanticCacheMode -> Expr Src Import -> IO (Expr Src Void)+loadRelativeTo parentDirectory = loadWithStatus+ (makeEmptyStatus defaultNewManager defaultOriginHeaders parentDirectory)++-- | See 'loadRelativeTo'.+loadWithStatus+ :: Status+ -> SemanticCacheMode+ -> Expr Src Import+ -> IO (Expr Src Void)+loadWithStatus status semanticCacheMode expression =+ State.evalStateT+ (loadWith expression)+ status { _semanticCacheMode = semanticCacheMode }++encodeExpression :: Expr Void Void -> Data.ByteString.ByteString+encodeExpression expression = bytesStrict+ where+ intermediateExpression :: Expr Void Import+ intermediateExpression = fmap absurd expression++ encoding = Codec.Serialise.encode intermediateExpression++ bytesStrict = Write.toStrictByteString encoding++-- | Hash a fully resolved expression+hashExpression :: Expr Void Void -> Dhall.Crypto.SHA256Digest+hashExpression = Dhall.Crypto.sha256Hash . encodeExpression++{-| Convenience utility to hash a fully resolved expression and return the+ base-16 encoded hash with the @sha256:@ prefix++ In other words, the output of this function can be pasted into Dhall+ source code to add an integrity check to an import+-}+hashExpressionToCode :: Expr Void Void -> Text+hashExpressionToCode expr =+ "sha256:" <> Text.pack (show (hashExpression expr))++-- | A call to `assertNoImports` failed because there was at least one import+data ImportResolutionDisabled = ImportResolutionDisabled deriving (Exception)++instance Show ImportResolutionDisabled where+ show _ = "\nImport resolution is disabled"++-- | Assert than an expression is import-free+assertNoImports :: MonadIO io => Expr Src Import -> io (Expr Src Void)+assertNoImports expression =+ Core.throws (traverse (\_ -> Left ImportResolutionDisabled) expression)+{-# INLINABLE assertNoImports #-}++{-| This function is used by the @--transitive@ option of the+ @dhall {freeze,format,lint}@ subcommands to determine which dependencies+ to descend into++#ifndef mingw32_HOST_OS+ >>> dependencyToFile (emptyStatus ".") Import{ importHashed = ImportHashed{ hash = Nothing, importType = Local Here (File (Directory []) "foo") }, importMode = Code }+ Just "./foo"++ >>> dependencyToFile (emptyStatus "./foo") Import{ importHashed = ImportHashed{ hash = Nothing, importType = Local Here (File (Directory []) "bar") }, importMode = Code }+ Just "./foo/bar"+++ >>> dependencyToFile (emptyStatus "./foo") Import{ importHashed = ImportHashed{ hash = Nothing, importType = Remote (URL HTTPS "example.com" (File (Directory []) "") Nothing Nothing) }, importMode = Code }+ Nothing++ >>> dependencyToFile (emptyStatus ".") Import{ importHashed = ImportHashed{ hash = Nothing, importType = Env "foo" }, importMode = Code }+ Nothing+#endif+-}+dependencyToFile :: Status -> Import -> IO (Maybe FilePath)+dependencyToFile status import_ = flip State.evalStateT status $ do+ parent :| _ <- zoom stack State.get++ child <- fmap chainedImport (hoist liftIO (chainImport parent import_))++ let ignore = return Nothing++ -- We only need to transitively modify code imports since other import+ -- types are not interpreted and therefore don't need to be modified+ case importMode child of+ RawText ->+ ignore++ RawBytes ->+ ignore++ Location ->+ ignore++ Code ->+ case importType (importHashed child) of+ Local filePrefix file -> do+ let descend = liftIO $ do+ path <- localToPath filePrefix file++ return (Just path)++ -- Only follow relative imports when modifying dependencies.+ -- Carefully note that we check the file prefix of the+ -- original import (before chaining), since the chained+ -- import will inherit the file prefix of the parent import.+ case importType (importHashed import_) of+ Local Here _ -> descend+ Local Parent _ -> descend+ _ -> ignore++ -- Don't transitively modify any other type of import+ Remote{} ->+ ignore++ Missing ->+ ignore++ Env{} ->+ ignore
@@ -1,290 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}--module Dhall.Import.HTTP where--import Control.Exception (Exception)-import Control.Monad (join)-import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Trans.State.Strict (StateT)-import Data.ByteString (ByteString)-import Data.CaseInsensitive (CI)-import Data.Dynamic (fromDynamic, toDyn)-import Data.Semigroup ((<>))-import Data.Text (Text)-import Lens.Family.State.Strict (zoom)--import Dhall.Core- ( Directory(..)- , File(..)- , Import(..)- , ImportHashed(..)- , ImportType(..)- , Scheme(..)- , URL(..)- )--import qualified Control.Monad.Trans.State.Strict as State-import qualified Data.Text as Text-import qualified Data.Text.Encoding-import qualified Dhall.Util-import qualified Network.URI.Encode as URI.Encode--import Dhall.Import.Types--import qualified Control.Exception-#ifdef __GHCJS__-import qualified JavaScript.XHR-#else-import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Encoding-#endif--#if MIN_VERSION_http_client(0,5,0)-import Network.HTTP.Client- (HttpException(..), HttpExceptionContent(..), Manager)-#else-import Network.HTTP.Client (HttpException(..), Manager)-#endif--import qualified Network.HTTP.Client as HTTP-import qualified Network.HTTP.Client.TLS as HTTP-import qualified Network.HTTP.Types.Status--mkPrettyHttpException :: HttpException -> PrettyHttpException-mkPrettyHttpException ex =- PrettyHttpException (renderPrettyHttpException ex) (toDyn ex)--renderPrettyHttpException :: HttpException -> String-#if MIN_VERSION_http_client(0,5,0)-renderPrettyHttpException (InvalidUrlException _ r) =- "\n"- <> "\ESC[1;31mError\ESC[0m: Invalid URL\n"- <> "\n"- <> "↳ " <> show r-renderPrettyHttpException (HttpExceptionRequest _ e) =- case e of- ConnectionFailure _ ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Remote host not found\n"- InvalidDestinationHost host ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Invalid remote host name\n"- <> "\n"- <> "↳ " <> show host- ResponseTimeout ->- "\n"- <> "\ESC[1;31mError\ESC[0m: The remote host took too long to respond"- StatusCodeException response _- | statusCode == 404 ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Remote file not found"- | otherwise ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Unexpected HTTP status code:\n"- <> "\n"- <> "↳ " <> show statusCode- where- statusCode =- Network.HTTP.Types.Status.statusCode- (HTTP.responseStatus response)- e' -> "\n" <> show e'-#else-renderPrettyHttpException e = case e of- FailedConnectionException2 _ _ _ e' ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Wrong host\n"- <> "\n"- <> "↳ " <> show e'- InvalidDestinationHost host ->- "\n"- <> "\ESC[1;31mError\ESC[0m: Invalid host name\n"- <> "\n"- <> "↳ " <> show host- ResponseTimeout ->- "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"- e' -> "\n"- <> show e'-#endif--needManager :: StateT (Status m) IO Manager-needManager = do- x <- zoom manager State.get- case join (fmap fromDynamic x) of- Just m -> return m- Nothing -> do- let settings = HTTP.tlsManagerSettings--#ifdef MIN_VERSION_http_client-#if MIN_VERSION_http_client(0,5,0)- { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro (30 * 1000 * 1000) } -- 30 seconds-#else- { HTTP.managerResponseTimeout = Just (30 * 1000 * 1000) } -- 30 seconds-#endif-#endif- m <- liftIO (HTTP.newManager settings)- zoom manager (State.put (Just (toDyn m)))- return m--data NotCORSCompliant = NotCORSCompliant- { expectedOrigins :: [ByteString]- , actualOrigin :: ByteString- }--instance Exception NotCORSCompliant--instance Show NotCORSCompliant where- show (NotCORSCompliant {..}) =- Dhall.Util._ERROR <> ": Not CORS compliant\n"- <> "\n"- <> "Dhall supports transitive imports, meaning that an imported expression can\n"- <> "import other expressions. However, a remote import (the \"parent\" import)\n"- <> "cannot import another remote import (the \"child\" import) unless the child\n"- <> "import grants permission to do using CORS. The child import must respond with\n"- <> "an `Access-Control-Allow-Origin` response header that matches the parent\n"- <> "import, otherwise Dhall rejects the import.\n"- <> "\n" <> prologue- where- prologue =- case expectedOrigins of- [ expectedOrigin ] ->- "The following parent import:\n"- <> "\n"- <> "↳ " <> show actualOrigin <> "\n"- <> "\n"- <> "... did not match the expected origin:\n"- <> "\n"- <> "↳ " <> show expectedOrigin <> "\n"- <> "\n"- <> "... so import resolution failed.\n"- [] ->- "The child response did not include any `Access-Control-Allow-Origin` header,\n"- <> "so import resolution failed.\n"- _:_:_ ->- "The child response included more than one `Access-Control-Allow-Origin` header,\n"- <> "when only one such header should have been present, so import resolution\n"- <> "failed.\n"- <> "\n"- <> "This may indicate that the server for the child import is misconfigured.\n"--corsCompliant- :: MonadIO io- => ImportType -> URL -> [(CI ByteString, ByteString)] -> io ()-corsCompliant (Remote parentURL) childURL responseHeaders = liftIO $ do- let toOrigin (URL {..}) =- Data.Text.Encoding.encodeUtf8 (prefix <> "://" <> authority)- where- prefix =- case scheme of- HTTP -> "http"- HTTPS -> "https"-- let actualOrigin = toOrigin parentURL-- let childOrigin = toOrigin childURL-- let predicate (header, _) = header == "Access-Control-Allow-Origin"-- let originHeaders = filter predicate responseHeaders-- let expectedOrigins = map snd originHeaders-- case expectedOrigins of- [expectedOrigin]- | expectedOrigin == "*" ->- return ()- | expectedOrigin == actualOrigin ->- return ()- _ | actualOrigin == childOrigin ->- return ()- | otherwise ->- Control.Exception.throwIO (NotCORSCompliant {..})-corsCompliant _ _ _ = return ()--renderComponent :: Text -> Text-renderComponent component = "/" <> URI.Encode.encodeText component--renderQuery :: Text -> Text-renderQuery query = "?" <> query--renderURL :: URL -> Text-renderURL url =- schemeText- <> authority- <> pathText- <> queryText- where- URL {..} = url-- File {..} = path-- Directory {..} = directory-- schemeText = case scheme of- HTTP -> "http://"- HTTPS -> "https://"-- pathText =- foldMap renderComponent (reverse components)- <> renderComponent file-- queryText = foldMap renderQuery query--fetchFromHttpUrl- :: URL- -> Maybe [(CI ByteString, ByteString)]- -> StateT (Status m) IO (String, Text.Text)-#ifdef __GHCJS__-fetchFromHttpUrl childURL Nothing = do- let childURLText = renderURL childURL-- let childURLString = Text.unpack childURLText-- -- No need to add a CORS compliance check when using GHCJS. The browser- -- will already check the CORS compliance of the following XHR- (statusCode, body) <- liftIO (JavaScript.XHR.get childURLText)-- case statusCode of- 200 -> return ()- _ -> fail (childURLString <> " returned a non-200 status code: " <> show statusCode)-- return (childURLString, body)-fetchFromHttpUrl _ _ = do- fail "Dhall does not yet support custom headers when built using GHCJS"-#else-fetchFromHttpUrl childURL mheaders = do- let childURLString = Text.unpack (renderURL childURL)-- m <- needManager-- request <- liftIO (HTTP.parseUrlThrow childURLString)-- let requestWithHeaders =- case mheaders of- Nothing -> request- Just headers -> request { HTTP.requestHeaders = headers }-- let io = HTTP.httpLbs requestWithHeaders m-- let handler e = do- let _ = e :: HttpException- Control.Exception.throwIO (mkPrettyHttpException e)-- response <- liftIO (Control.Exception.handle handler io)-- Status {..} <- State.get-- let parentImport = NonEmpty.head _stack-- let parentImportType = importType (importHashed parentImport)-- corsCompliant parentImportType childURL (HTTP.responseHeaders response)-- let bytes = HTTP.responseBody response-- case Data.Text.Lazy.Encoding.decodeUtf8' bytes of- Left err -> liftIO (Control.Exception.throwIO err)- Right text -> return (childURLString, Data.Text.Lazy.toStrict text)-#endif
@@ -0,0 +1,129 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns #-}++module Dhall.Import.Headers+ ( normalizeHeaders+ , originHeadersTypeExpr+ , toHeaders+ , toOriginHeaders+ ) where++import Control.Applicative (Alternative (..), liftA2)+import Control.Exception (SomeException)+import Control.Monad.Catch (handle, throwM)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Core (Chunks (..), Expr (..))+import Dhall.Import.Types (HTTPHeader, OriginHeaders)+import Dhall.Parser (Src (..))++import qualified Data.CaseInsensitive+import qualified Data.Foldable+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text.Encoding+import qualified Dhall.Core as Core+import qualified Dhall.Map+import qualified Dhall.Pretty.Internal+import qualified Dhall.TypeCheck++-- | Given a well-typed (of type `List { header : Text, value Text }` or+-- `List { mapKey : Text, mapValue Text }`) headers expressions in normal form+-- construct the corresponding binary http headers; otherwise return the empty+-- list.+toHeaders :: Expr s a -> [HTTPHeader]+toHeaders (ListLit _ hs) = Data.Foldable.toList (Data.Foldable.fold maybeHeaders)+ where+ maybeHeaders = mapM toHeader hs+toHeaders _ = []++toHeader :: Expr s a -> Maybe HTTPHeader+toHeader (RecordLit m) = do+ (Core.recordFieldValue -> TextLit (Chunks [] keyText), Core.recordFieldValue -> TextLit (Chunks [] valueText))+ <- lookupHeader <|> lookupMapKey+ let keyBytes = Data.Text.Encoding.encodeUtf8 keyText+ let valueBytes = Data.Text.Encoding.encodeUtf8 valueText+ return (Data.CaseInsensitive.mk keyBytes, valueBytes)+ where+ lookupHeader = liftA2 (,) (Dhall.Map.lookup "header" m) (Dhall.Map.lookup "value" m)+ lookupMapKey = liftA2 (,) (Dhall.Map.lookup "mapKey" m) (Dhall.Map.lookup "mapValue" m)+toHeader _ =+ empty++-- | Normalize, typecheck and return OriginHeaders from a given expression.+toOriginHeaders :: Expr Src Void -> IO OriginHeaders+toOriginHeaders expr = fmap convert (normalizeOriginHeaders expr)+ where+ convert :: Expr s a -> OriginHeaders+ convert (ListLit _ hs) = HashMap.fromList (originPairs hs)+ convert _ = mempty++ originPairs hs = Data.Foldable.toList (Data.Foldable.fold (mapM toOriginPair hs))++ toOriginPair :: Expr s a -> Maybe (Text, [HTTPHeader])+ toOriginPair (RecordLit m) = do+ (Core.recordFieldValue -> TextLit (Chunks [] keyText), Core.recordFieldValue -> value)+ <- lookupMapKey+ return (keyText, toHeaders value)+ where+ lookupMapKey = liftA2 (,) (Dhall.Map.lookup "mapKey" m) (Dhall.Map.lookup "mapValue" m)+ toOriginPair _ = Nothing++makeHeadersTypeExpr :: Text -> Text -> Expr Src Void+makeHeadersTypeExpr keyKey valueKey =+ App List+ ( Record $ Core.makeRecordField <$>+ Dhall.Map.fromList+ [ (keyKey, Text)+ , (valueKey, Text)+ ]+ )++headersTypeExpr :: Expr Src Void+headersTypeExpr = makeHeadersTypeExpr "mapKey" "mapValue"++leagacyHeadersTypeExpr :: Expr Src Void+leagacyHeadersTypeExpr = makeHeadersTypeExpr "header" "value"++originHeadersTypeExpr :: Expr Src Void+originHeadersTypeExpr =+ App List+ ( Record $ Core.makeRecordField <$>+ Dhall.Map.fromList+ [ ("mapKey", Text)+ , ("mapValue", headersTypeExpr)+ ]+ )++typecheck :: Expr Src Void -> Expr Src Void -> IO (Expr Src Void)+typecheck expected expr = do+ let suffix_ = Dhall.Pretty.Internal.prettyToStrictText expected+ let annot = case expr of+ Note (Src begin end bytes) _ ->+ Note (Src begin end bytes') (Annot expr expected)+ where+ bytes' = bytes <> " : " <> suffix_+ _ ->+ Annot expr expected++ _ <- case (Dhall.TypeCheck.typeOf annot) of+ Left err -> throwM err+ Right _ -> return ()++ return (Core.normalize expr)++normalizeHeaders :: Expr Src Void -> IO (Expr Src Void)+normalizeHeaders headersExpr = do+ let handler₀ (e :: SomeException) = do+ {- Try to typecheck using the preferred @mapKey@/@mapValue@ fields+ and fall back to @header@/@value@ if that fails. However, if+ @header@/@value@ still fails then re-throw the original exception+ for @mapKey@ / @mapValue@. -}+ let handler₁ (_ :: SomeException) = throwM e+ handle handler₁ (typecheck leagacyHeadersTypeExpr headersExpr)++ handle handler₀ (typecheck headersTypeExpr headersExpr)++normalizeOriginHeaders :: Expr Src Void -> IO (Expr Src Void)+normalizeOriginHeaders = typecheck originHeadersTypeExpr
@@ -1,172 +1,209 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}+ {-# OPTIONS_GHC -Wall #-} module Dhall.Import.Types where -import Control.Exception (Exception)+import Control.Exception (Exception) import Control.Monad.Trans.State.Strict (StateT)+import Data.ByteString (ByteString)+import Data.CaseInsensitive (CI) import Data.Dynamic-import Data.List.NonEmpty (NonEmpty)-import Data.Map (Map)-import Data.Semigroup ((<>))-import Dhall.Binary (StandardVersion(..))-import Dhall.Context (Context)+import Data.HashMap.Strict (HashMap)+import Data.List.NonEmpty (NonEmpty)+import Data.Void (Void)+import Dhall.Context (Context) import Dhall.Core- ( Directory (..)- , Expr- , File (..)- , FilePrefix (..)- , Import (..)- , ImportHashed (..)- , ImportMode (..)- , ImportType (..)- , ReifiedNormalizer(..)- , pretty- )-import Dhall.Parser (Src)-import Dhall.TypeCheck (X)-import Lens.Family (LensLike')-import System.FilePath (isRelative, splitDirectories)-import Text.Dot (Dot, NodeId, userNode, userNodeId)+ ( Expr+ , Import (..)+ , ReifiedNormalizer (..)+ , URL+ )+import Dhall.Map (Map)+import Dhall.Parser (Src)+import Lens.Micro (Lens', lens)+import Prettyprinter (Pretty (..)) -import qualified Dhall.Binary-import qualified Dhall.Context-import qualified Data.Map as Map+#ifdef WITH_HTTP+import qualified Dhall.Import.Manager+#endif+ import qualified Data.Text+import qualified Dhall.Context+import qualified Dhall.Map as Map+import qualified Dhall.Substitution -data Resolved = Resolved- { resolvedExpression :: Expr Src Import- -- ^ Expression with its immediate imports resolved- , newImport :: Import- -- ^ New import to use in place of the original import for chaining- -- downstream imports+-- | A fully \"chained\" import, i.e. if it contains a relative path that path+-- is relative to the current directory. If it is a remote import with headers+-- those are well-typed (either of type `List { header : Text, value Text}` or+-- `List { mapKey : Text, mapValue Text})` and in normal form. These+-- invariants are preserved by the API exposed by @Dhall.Import@.+newtype Chained = Chained+ { chainedImport :: Import+ -- ^ The underlying import }+ deriving (Eq, Ord) +instance Pretty Chained where+ pretty (Chained import_) = pretty import_++-- | An import that has been fully interpeted+newtype ImportSemantics = ImportSemantics+ { importSemantics :: Expr Void Void+ -- ^ The fully resolved import, typechecked and beta-normal.+ }++-- | `parent` imports (i.e. depends on) `child`+data Depends = Depends { parent :: Chained, child :: Chained }++{-| This enables or disables the semantic cache for imports protected by+ integrity checks+-}+data SemanticCacheMode = IgnoreSemanticCache | UseSemanticCache deriving (Eq)++-- | Shared state for HTTP requests+type Manager =+#ifdef WITH_HTTP+ Dhall.Import.Manager.Manager+#else+ ()+#endif++-- | The default HTTP 'Manager'+defaultNewManager :: IO Manager+defaultNewManager =+#ifdef WITH_HTTP+ Dhall.Import.Manager.defaultNewManager+#else+ pure ()+#endif++-- | HTTP headers+type HTTPHeader = (CI ByteString, ByteString)++-- | A map of site origin -> HTTP headers+type OriginHeaders = HashMap Data.Text.Text [HTTPHeader]++{-| Used internally to track whether or not we've already warned the user about+ caching issues+-}+data CacheWarning = CacheNotWarned | CacheWarned+ -- | State threaded throughout the import process-data Status m = Status- { _stack :: NonEmpty Import+data Status = Status+ { _stack :: NonEmpty Chained -- ^ Stack of `Import`s that we've imported along the way to get to the -- current point - , _dot :: Dot NodeId- -- ^ Graph of all the imports visited so far-- , _nextNodeId :: Int- -- ^ Next node id to be used for the dot graph generation+ , _graph :: [Depends]+ -- ^ Graph of all the imports visited so far, represented by a list of+ -- import dependencies. - , _cache :: Map Import (NodeId, Expr Src X)+ , _cache :: Map Chained ImportSemantics -- ^ Cache of imported expressions with their node id in order to avoid -- importing the same expression twice with different values - , _manager :: Maybe Dynamic- -- ^ Cache for the HTTP `Manager` so that we only acquire it once+ , _newManager :: IO Manager+ , _manager :: Maybe Manager+ -- ^ Used to cache the `Dhall.Import.Manager.Manager` when making multiple+ -- requests - , _standardVersion :: StandardVersion+ , _loadOriginHeaders :: StateT Status IO OriginHeaders+ -- ^ Load the origin headers from environment or configuration file.+ -- After loading once, further evaluations return the cached version. - , _normalizer :: Maybe (ReifiedNormalizer X)+ , _remote :: URL -> StateT Status IO Data.Text.Text+ -- ^ The remote resolver, fetches the content at the given URL. - , _startingContext :: Context (Expr Src X)+ , _remoteBytes :: URL -> StateT Status IO Data.ByteString.ByteString+ -- ^ Like `_remote`, except for `Dhall.Syntax.Expr.Bytes` - , _resolver :: Import -> StateT (Status m) m Resolved+ , _substitutions :: Dhall.Substitution.Substitutions Src Void - , _cacher :: Import -> Expr Src X -> StateT (Status m) m ()+ , _normalizer :: Maybe (ReifiedNormalizer Void)++ , _startingContext :: Context (Expr Src Void)++ , _semanticCacheMode :: SemanticCacheMode++ , _cacheWarning :: CacheWarning+ -- ^ Records whether or not we already warned the user about issues with+ -- cache directory } --- | Default starting `Status` that is polymorphic in the base `Monad`+-- | Initial `Status`, parameterised over the HTTP 'Manager',+-- the origin headers and the remote resolver,+-- importing relative to the given root import. emptyStatusWith- :: (Import -> StateT (Status m) m Resolved)- -> (Import -> Expr Src X -> StateT (Status m) m ())- -> FilePath- -> Status m-emptyStatusWith _resolver _cacher rootDirectory = Status {..}+ :: IO Manager+ -> StateT Status IO OriginHeaders+ -> (URL -> StateT Status IO Data.Text.Text)+ -> (URL -> StateT Status IO Data.ByteString.ByteString)+ -> Import+ -> Status+emptyStatusWith _newManager _loadOriginHeaders _remote _remoteBytes rootImport = Status {..} where- _stack = pure rootImport-- _dot = importNode (userNodeId 0) rootImport+ _stack = pure (Chained rootImport) - _nextNodeId = 1+ _graph = [] _cache = Map.empty _manager = Nothing - _standardVersion = Dhall.Binary.defaultStandardVersion+ _substitutions = Dhall.Substitution.empty _normalizer = Nothing _startingContext = Dhall.Context.empty - prefix = if isRelative rootDirectory- then Here- else Absolute- pathComponents =- fmap Data.Text.pack (reverse (splitDirectories rootDirectory))-- dirAsFile = File (Directory pathComponents) "."-- -- Fake import to set the directory we're relative to.- rootImport = Import- { importHashed = ImportHashed- { hash = Nothing- , importType = Local prefix dirAsFile- }- , importMode = Code- }--importNode :: NodeId -> Import -> Dot NodeId-importNode nodeId i = do- userNode- nodeId- [ ("label", Data.Text.unpack $ pretty i)- , ("shape", "box")- , ("style", "rounded")- ]- pure nodeId+ _semanticCacheMode = UseSemanticCache -stack :: Functor f => LensLike' f (Status m) (NonEmpty Import)-stack k s = fmap (\x -> s { _stack = x }) (k (_stack s))+ _cacheWarning = CacheNotWarned -dot :: Functor f => LensLike' f (Status m) (Dot NodeId)-dot k s = fmap (\x -> s { _dot = x }) (k (_dot s))+-- | Lens from a `Status` to its `_stack` field+stack :: Lens' Status (NonEmpty Chained)+stack = lens _stack (\s x -> s { _stack = x }) -nextNodeId :: Functor f => LensLike' f (Status m) Int-nextNodeId k s = fmap (\x -> s { _nextNodeId = x }) (k (_nextNodeId s))+-- | Lens from a `Status` to its `_graph` field+graph :: Lens' Status [Depends]+graph = lens _graph (\s x -> s { _graph = x }) -cache :: Functor f => LensLike' f (Status m) (Map Import (NodeId, Expr Src X))-cache k s = fmap (\x -> s { _cache = x }) (k (_cache s))+-- | Lens from a `Status` to its `_cache` field+cache :: Lens' Status (Map Chained ImportSemantics)+cache = lens _cache (\s x -> s { _cache = x }) -manager :: Functor f => LensLike' f (Status m) (Maybe Dynamic)-manager k s = fmap (\x -> s { _manager = x }) (k (_manager s))+-- | Lens from a `Status` to its `_remote` field+remote :: Lens' Status (URL -> StateT Status IO Data.Text.Text)+remote = lens _remote (\s x -> s { _remote = x }) -standardVersion :: Functor f => LensLike' f (Status m) StandardVersion-standardVersion k s =- fmap (\x -> s { _standardVersion = x }) (k (_standardVersion s))+-- | Lens from a `Status` to its `_remote` field+remoteBytes :: Lens' Status (URL -> StateT Status IO Data.ByteString.ByteString)+remoteBytes = lens _remoteBytes (\s x -> s { _remoteBytes = x }) -normalizer :: Functor f => LensLike' f (Status m) (Maybe (ReifiedNormalizer X))-normalizer k s = fmap (\x -> s {_normalizer = x}) (k (_normalizer s))+-- | Lens from a `Status` to its `_substitutions` field+substitutions :: Lens' Status (Dhall.Substitution.Substitutions Src Void)+substitutions = lens _substitutions (\s x -> s { _substitutions = x }) -startingContext :: Functor f => LensLike' f (Status m) (Context (Expr Src X))-startingContext k s =- fmap (\x -> s { _startingContext = x }) (k (_startingContext s))+-- | Lens from a `Status` to its `_normalizer` field+normalizer :: Lens' Status (Maybe (ReifiedNormalizer Void))+normalizer = lens _normalizer (\s x -> s {_normalizer = x}) -resolver- :: Functor f- => LensLike' f (Status m) (Import -> StateT (Status m) m Resolved)-resolver k s = fmap (\x -> s { _resolver = x }) (k (_resolver s))+-- | Lens from a `Status` to its `_startingContext` field+startingContext :: Lens' Status (Context (Expr Src Void))+startingContext = lens _startingContext (\s x -> s { _startingContext = x }) -cacher- :: Functor f- => LensLike' f (Status m) (Import -> Expr Src X -> StateT (Status m) m ())-cacher k s = fmap (\x -> s { _cacher = x }) (k (_cacher s))+-- | Lens from a `Status` to its `_cacheWarning` field+cacheWarning :: Lens' Status CacheWarning+cacheWarning = lens _cacheWarning (\s x -> s { _cacheWarning = x }) {-| This exception indicates that there was an internal error in Dhall's import-related logic- the `expected` type then the `extract` function must succeed. If not, then- this exception is thrown - This exception indicates that an invalid `Type` was provided to the `input`- function+ This exception indicates that an invalid `Dhall.Syntax.Type` was provided to+ the `Dhall.input` function -} data InternalError = InternalError deriving (Typeable) @@ -193,11 +230,12 @@ instance Exception InternalError --- | Wrapper around `HttpException`s with a prettier `Show` instance.+-- | Wrapper around `Network.HTTP.Client.HttpException`s with a prettier `Show`+-- instance -- -- In order to keep the library API constant even when the @with-http@ Cabal -- flag is disabled the pretty error message is pre-rendered and the real--- 'HttpExcepion' is stored in a 'Dynamic'+-- 'Network.HTTP.Client.HttpException' is stored in a 'Dynamic' data PrettyHttpException = PrettyHttpException String Dynamic deriving (Typeable)
@@ -1,61 +1,210 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}+ -- | This module contains the implementation of the @dhall lint@ command module Dhall.Lint ( -- * Lint lint- , removeLetInLet , removeUnusedBindings- , optionalLitToSomeNone+ , fixAssert+ , fixParentPath+ , addPreludeExtensions+ , removeLetInLet+ , useToMap ) where -import Control.Monad (mplus)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Semigroup ((<>))-import Dhall.Core (Binding(..), Expr(..), Import, Var(..), subExpressions)+import Control.Applicative ((<|>)) -import qualified Dhall.Core-import qualified Dhall.Optics+import Dhall.Syntax+ ( Binding (..)+ , Chunks (..)+ , Directory (..)+ , Expr (..)+ , File (..)+ , FilePrefix (..)+ , Import (..)+ , ImportHashed (..)+ , ImportType (..)+ , URL (..)+ , Var (..)+ , subExpressions+ ) +import qualified Data.Foldable as Foldable+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Text as Text+import qualified Dhall.Core as Core+import qualified Dhall.Map+import qualified Lens.Micro as Lens+ {-| Automatically improve a Dhall expression Currently this: - * removes unused @let@ bindings with 'removeLetInLet'.- * consolidates nested @let@ bindings to use a multiple-@let@ binding with 'removeUnusedBindings'.- * switches legacy @List@-like @Optional@ literals to use @Some@ / @None@ instead with 'optionalLitToSomeNone'+ * removes unused @let@ bindings with 'removeUnusedBindings'.+ * fixes @let a = x ≡ y@ to be @let a = assert : x ≡ y@+ * consolidates nested @let@ bindings to use a multiple-@let@ binding with 'removeLetInLet'+ * fixes paths of the form @.\/..\/foo@ to @..\/foo@ -}-lint :: Expr s Import -> Expr t Import-lint =- Dhall.Optics.rewriteOf- subExpressions- ( \e ->- removeLetInLet e- `mplus` removeUnusedBindings e- `mplus` optionalLitToSomeNone e- )- . Dhall.Core.denote--removeLetInLet :: Eq a => Expr s a -> Maybe (Expr s a)-removeLetInLet (Let a (Let b c)) = Just (Let (a <> b) c)-removeLetInLet _ = Nothing+lint :: Eq s => Expr s Import -> Expr s Import+lint = Lens.rewriteOf subExpressions rewrite+ where+ rewrite e =+ fixAssert e+ <|> removeUnusedBindings e+ <|> fixParentPath e+ <|> removeLetInLet e+ <|> addPreludeExtensions e +-- | Remove unused `Let` bindings. removeUnusedBindings :: Eq a => Expr s a -> Maybe (Expr s a)-removeUnusedBindings (Let (Binding a _ _ :| []) d)- | not (V a 0 `Dhall.Core.freeIn` d) =- Just d- | otherwise =- Nothing-removeUnusedBindings (Let (Binding a _ _ :| (l : ls)) d)- | not (V a 0 `Dhall.Core.freeIn` e) =- Just e- | otherwise =- Nothing- where- e = Let (l :| ls) d+-- Don't remove assertions!+removeUnusedBindings (Let (Binding _ _ _ _ _ e) _)+ | isOrContainsAssert e = Nothing+removeUnusedBindings (Let (Binding _ a _ _ _ _) d)+ | not (V a 0 `Core.freeIn` d) =+ Just (Core.shift (-1) (V a 0) d) removeUnusedBindings _ = Nothing +-- | Fix `Let` bindings that the user probably meant to be @assert@s+fixAssert :: Expr s a -> Maybe (Expr s a)+fixAssert (Let (Binding { value = v@(Core.shallowDenote -> Equivalent {}), ..}) body) =+ Just (Let (Binding { value = Assert v, .. }) body)+fixAssert (Let binding body@(Core.shallowDenote -> Equivalent {})) =+ Just (Let binding (Assert body))+fixAssert _ =+ Nothing -optionalLitToSomeNone :: Expr s a -> Maybe (Expr s a)-optionalLitToSomeNone (OptionalLit _ (Just b)) = Just (Some b)-optionalLitToSomeNone (OptionalLit a Nothing) = Just (App None a)-optionalLitToSomeNone _ = Nothing+-- | This transforms @.\/..\/foo@ into @..\/foo@+fixParentPath :: Expr s Import -> Maybe (Expr s Import)+fixParentPath (Embed oldImport) = do+ let Import{..} = oldImport++ let ImportHashed{..} = importHashed++ case importType of+ Local Here File{ directory = Directory { components }, .. }+ | Just nonEmpty <- NonEmpty.nonEmpty components+ , NonEmpty.last nonEmpty == ".." -> do+ let newDirectory =+ Directory { components = NonEmpty.init nonEmpty }++ let newImportType =+ Local Parent File{ directory = newDirectory, .. }++ let newImportHashed =+ ImportHashed { importType = newImportType, .. }++ let newImport = Import { importHashed = newImportHashed, .. }++ Just (Embed newImport)+ _ ->+ Nothing+fixParentPath _ = Nothing++{-| This transforms @https://prelude.dhall-lang.org/…/foo@ to+ @https://prelude.dhall-lang.org/…/foo.dhall@+-}+addPreludeExtensions :: Expr s Import -> Maybe (Expr s Import)+addPreludeExtensions (Embed oldImport) = do+ let Import{ importHashed = oldImportHashed, .. } = oldImport++ let ImportHashed{ importType = oldImportType, .. } = oldImportHashed++ case oldImportType of+ Remote URL{ path = oldPath, ..}+ | authority == "prelude.dhall-lang.org" ->+ case oldPath of+ File{ file = oldFile, .. }+ | not (Text.isSuffixOf ".dhall" oldFile) -> do+ let newFile = oldFile <> ".dhall"++ let newPath = File{ file = newFile, .. }++ let newImportType = Remote URL{ path = newPath, .. }++ let newImportHashed =+ ImportHashed{ importType = newImportType, .. }++ let newImport =+ Import{ importHashed = newImportHashed, .. }++ return (Embed newImport)+ _ ->+ Nothing+ _ -> do+ Nothing+addPreludeExtensions _ = Nothing++isOrContainsAssert :: Expr s a -> Bool+isOrContainsAssert (Assert _) = True+isOrContainsAssert e = Lens.anyOf subExpressions isOrContainsAssert e++-- | The difference between+--+-- > let x = 1 let y = 2 in x + y+--+-- and+--+-- > let x = 1 in let y = 2 in x + y+--+-- is that in the second expression, the inner 'Let' is wrapped by a 'Note'.+--+-- We remove such a 'Note' in order to consolidate nested let-blocks into a+-- single one.+removeLetInLet :: Expr s a -> Maybe (Expr s a)+removeLetInLet (Let binding (Note _ l@Let{})) = Just (Let binding l)+removeLetInLet _ = Nothing++-- | This replaces a record of key-value pairs with the equivalent use of+-- @toMap@+--+-- This is currently not used by @dhall lint@ because this would sort @Map@+-- keys, which is not necessarily a behavior-preserving change, but is still+-- made available as a convenient rewrite rule. For example,+-- @{json,yaml}-to-dhall@ use this rewrite to simplify their output.+useToMap :: Expr s a -> Maybe (Expr s a)+useToMap+ (ListLit+ t@(Just+ (Core.shallowDenote -> App+ (Core.shallowDenote -> List)+ (Core.shallowDenote -> Record+ (Dhall.Map.sort ->+ [ ("mapKey", Core.shallowDenote . Core.recordFieldValue -> Text)+ , ("mapValue", _)+ ]+ )+ )+ )+ )+ []+ ) =+ Just (ToMap (RecordLit []) t)+useToMap (ListLit _ keyValues)+ | not (null keyValues)+ , Just keyValues' <- traverse convert keyValues =+ Just+ (ToMap+ (RecordLit (Dhall.Map.fromList (Foldable.toList keyValues')))+ Nothing+ )+ where+ convert keyValue =+ case Core.shallowDenote keyValue of+ RecordLit+ (Dhall.Map.sort ->+ [ ("mapKey" , Core.shallowDenote . Core.recordFieldValue -> TextLit (Chunks [] key))+ , ("mapValue", value)+ ]+ ) ->+ Just (key, value)+ _ ->+ Nothing+useToMap _ =+ Nothing
@@ -2,7 +2,8 @@ @dhall@ executable -} -{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -11,99 +12,192 @@ ( -- * Options Options(..) , Mode(..)+ , ResolveMode(..) , parseOptions , parserInfoOptions -- * Execution- , command+ , Dhall.Main.command , main ) where import Control.Applicative (optional, (<|>))-import Control.Exception (SomeException)-import Data.Monoid ((<>))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty)-import Data.Version (showVersion)-import Dhall.Binary (StandardVersion)-import Dhall.Core (Expr(..), Import)-import Dhall.Freeze (Intent(..), Scope(..))-import Dhall.Import (Imported(..))-import Dhall.Parser (Src)-import Dhall.Pretty (Ann, CharacterSet(..), annToAnsiStyle, layoutOpts)-import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)-import Lens.Family (set)+import Control.Exception (Handler (..), SomeException)+import Control.Monad (when)+import Data.Foldable (for_)+import Data.List.NonEmpty (NonEmpty (..), nonEmpty)+import Data.Maybe (fromMaybe)+import Data.Monoid (Endo (..))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Freeze (Intent (..), Scope (..))+import Dhall.Import+ ( Depends (..)+ , Imported (..)+ , SemanticCacheMode (..)+ , _semanticCacheMode+ )+import Dhall.Package (PackagingMode (..), writePackage)+import Dhall.Parser (Src)+import Dhall.Pretty+ ( Ann+ , CharacterSet (..)+ , annToAnsiStyle+ , detectCharacterSet+ )+import Dhall.Schemas (Schemas (..))+import Dhall.TypeCheck (Censored (..), DetailedTypeError (..), TypeError)+import Dhall.Version (dhallVersionString)+import Lens.Micro (set) import Options.Applicative (Parser, ParserInfo)-import System.Exit (exitFailure)-import System.IO (Handle)+import Prettyprinter (Doc, Pretty)+import System.Exit (ExitCode, exitFailure)+import System.IO (Handle)+import Text.Dot ((.->.)) +import Dhall.Core+ ( Expr (Annot)+ , Import (..)+ , ImportHashed (..)+ , ImportType (..)+ , URL (..)+ , pretty+ )+import Dhall.Util+ ( Censor (..)+ , CheckFailed (..)+ , Header (..)+ , Input (..)+ , Output (..)+ , OutputMode (..)+ , Transitivity (..)+ , handleMultipleChecksFailed+ )+ import qualified Codec.CBOR.JSON import qualified Codec.CBOR.Read import qualified Codec.CBOR.Write-import qualified Codec.Serialise import qualified Control.Exception-import qualified Control.Monad.Trans.State.Strict as State+import qualified Control.Monad.Trans.State.Strict as State import qualified Data.Aeson import qualified Data.Aeson.Encode.Pretty import qualified Data.ByteString.Lazy import qualified Data.ByteString.Lazy.Char8+import qualified Data.Map import qualified Data.Text import qualified Data.Text.IO-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty import qualified Dhall import qualified Dhall.Binary import qualified Dhall.Core import qualified Dhall.Diff+import qualified Dhall.DirectoryTree as DirectoryTree import qualified Dhall.Format import qualified Dhall.Freeze-import qualified Dhall.Hash import qualified Dhall.Import import qualified Dhall.Import.Types import qualified Dhall.Lint-import qualified Dhall.Parser+import qualified Dhall.Map+import qualified Dhall.Package import qualified Dhall.Pretty import qualified Dhall.Repl+import qualified Dhall.Schemas+import qualified Dhall.Tags import qualified Dhall.TypeCheck+import qualified Dhall.Util import qualified GHC.IO.Encoding import qualified Options.Applicative-import qualified Paths_dhall as Meta+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified System.AtomicWrite.Writer.LazyText as AtomicWrite.LazyText import qualified System.Console.ANSI+import qualified System.Exit as Exit+import qualified System.FilePath import qualified System.IO import qualified Text.Dot-import qualified Data.Map+import qualified Text.Pretty.Simple -- | Top-level program options data Options = Options- { mode :: Mode- , explain :: Bool- , plain :: Bool- , ascii :: Bool- , standardVersion :: StandardVersion+ { mode :: Mode+ , explain :: Bool+ , plain :: Bool+ , chosenCharacterSet :: Maybe CharacterSet+ , censor :: Censor } -- | The subcommands for the @dhall@ executable data Mode- = Default { file :: Maybe FilePath, annotate :: Bool, alpha :: Bool }+ = Default+ { file :: Input+ , output :: Output+ , annotate :: Bool+ , alpha :: Bool+ , semanticCacheMode :: SemanticCacheMode+ , version :: Bool+ } | Version- | Resolve { file :: Maybe FilePath, resolveMode :: Maybe ResolveMode }- | Type { file :: Maybe FilePath }- | Normalize { file :: Maybe FilePath, alpha :: Bool }+ | Resolve+ { file :: Input+ , resolveMode :: Maybe ResolveMode+ , semanticCacheMode :: SemanticCacheMode+ }+ | Type+ { file :: Input+ , quiet :: Bool+ , semanticCacheMode :: SemanticCacheMode+ }+ | Normalize { file :: Input , alpha :: Bool } | Repl- | Format { formatMode :: Dhall.Format.FormatMode }- | Freeze { inplace :: Maybe FilePath, all_ :: Bool, cache :: Bool }- | Hash+ | Format { deprecatedInPlace :: Bool, transitivity :: Transitivity, outputMode :: OutputMode, inputs :: NonEmpty Input }+ | Freeze { deprecatedInPlace :: Bool, transitivity :: Transitivity, all_ :: Bool, cache :: Bool, outputMode :: OutputMode, inputs :: NonEmpty Input }+ | Hash { file :: Input, cache :: Bool } | Diff { expr1 :: Text, expr2 :: Text }- | Lint { inplace :: Maybe FilePath }- | Encode { file :: Maybe FilePath, json :: Bool }- | Decode { file :: Maybe FilePath, json :: Bool }+ | Lint { deprecatedInPlace :: Bool, transitivity :: Transitivity, outputMode :: OutputMode, inputs :: NonEmpty Input }+ | Tags+ { input :: Input+ , output :: Output+ , suffixes :: Maybe [Text]+ , followSymlinks :: Bool+ }+ | Encode { file :: Input, json :: Bool }+ | Decode { file :: Input, json :: Bool, quiet :: Bool }+ | Text { file :: Input, output :: Output }+ | DirectoryTree { allowSeparators :: Bool, file :: Input, path :: FilePath }+ | Schemas { file :: Input, outputMode :: OutputMode, schemas :: Text }+ | SyntaxTree { file :: Input, noted :: Bool }+ | Package+ { packageOptions :: Endo Dhall.Package.Options+ , packageFiles :: NonEmpty FilePath+ } +-- | This specifies how to resolve transitive dependencies data ResolveMode = Dot+ -- ^ Generate a DOT file for @graphviz@ | ListTransitiveDependencies+ -- ^ List all transitive dependencies as text, one per line | ListImmediateDependencies+ -- ^ List immediate dependencies as text, one per line +-- | Groups of subcommands+data Group+ = Manipulate+ | Generate+ | Interpret+ | Convert+ | Miscellaneous+ | Debugging +groupDescription :: Group -> String+groupDescription group = case group of+ Manipulate -> "Manipulate Dhall code"+ Generate -> "Generate other formats from Dhall"+ Interpret -> "Interpret Dhall"+ Convert -> "Convert Dhall to and from its binary representation"+ Miscellaneous -> "Miscellaneous"+ Debugging -> "Debugging this interpreter"+ -- | `Parser` for the `Options` type parseOptions :: Parser Options parseOptions =@@ -111,8 +205,8 @@ <$> parseMode <*> switch "explain" "Explain error messages in more detail" <*> switch "plain" "Disable syntax highlighting"- <*> switch "ascii" "Format code using only ASCII syntax"- <*> Dhall.Binary.parseStandardVersion+ <*> parseCharacterSet+ <*> parseCensor where switch name description = Options.Applicative.switch@@ -120,11 +214,30 @@ <> Options.Applicative.help description ) -subcommand :: String -> String -> Parser a -> Parser a-subcommand name description parser =+ parseCensor = fmap f (switch "censor" "Hide source code in error messages")+ where+ f True = Censor+ f False = NoCensor++ parseCharacterSet =+ Options.Applicative.flag'+ (Just Unicode)+ ( Options.Applicative.long "unicode"+ <> Options.Applicative.help "Format code using only Unicode syntax"+ )+ <|> Options.Applicative.flag'+ (Just ASCII)+ ( Options.Applicative.long "ascii"+ <> Options.Applicative.help "Format code using only ASCII syntax"+ )+ <|> pure Nothing++subcommand :: Group -> String -> String -> Parser a -> Parser a+subcommand group name description parser = Options.Applicative.hsubparser ( Options.Applicative.command name parserInfo <> Options.Applicative.metavar name+ <> Options.Applicative.commandGroup (groupDescription group) ) where parserInfo =@@ -136,67 +249,154 @@ parseMode :: Parser Mode parseMode = subcommand- "version"- "Display version"- (pure Version)+ Manipulate+ "format"+ "Standard code formatter for the Dhall language"+ (Format <$> deprecatedInPlace <*> parseTransitiveSwitch <*> parseCheck "formatted" <*> parseFiles) <|> subcommand+ Manipulate+ "freeze"+ "Add integrity checks to remote import statements of an expression"+ (Freeze <$> deprecatedInPlace <*> parseTransitiveSwitch <*> parseAllFlag <*> parseCacheFlag <*> parseCheck "frozen" <*> parseFiles)+ <|> subcommand+ Manipulate+ "lint"+ "Improve Dhall code by using newer language features and removing dead code"+ (Lint <$> deprecatedInPlace <*> parseTransitiveSwitch <*> parseCheck "linted" <*> parseFiles)+ <|> subcommand+ Manipulate+ "rewrite-with-schemas"+ "Simplify Dhall code using a schemas record"+ (Dhall.Main.Schemas <$> parseInplaceNonTransitive <*> parseCheck "rewritten" <*> parseSchemasRecord)+ <|> subcommand+ Generate+ "text"+ "Render a Dhall expression that evaluates to a Text literal"+ (Text <$> parseFile <*> parseOutput)+ <|> subcommand+ Generate+ "to-directory-tree"+ "Convert nested records of Text literals into a directory tree"+ (DirectoryTree <$> parseDirectoryTreeAllowSeparators <*> parseFile <*> parseDirectoryTreeOutput)+ <|> subcommand+ Interpret "resolve" "Resolve an expression's imports"- (Resolve <$> optional parseFile <*> parseResolveMode)+ (Resolve <$> parseFile <*> parseResolveMode <*> parseSemanticCacheMode) <|> subcommand+ Interpret "type" "Infer an expression's type"- (Type <$> optional parseFile)+ (Type <$> parseFile <*> parseQuiet <*> parseSemanticCacheMode) <|> subcommand+ Interpret "normalize" "Normalize an expression"- (Normalize <$> optional parseFile <*> parseAlpha)+ (Normalize <$> parseFile <*> parseAlpha) <|> subcommand+ Convert+ "encode"+ "Encode a Dhall expression to binary"+ (Encode <$> parseFile <*> parseJSONFlag)+ <|> subcommand+ Convert+ "decode"+ "Decode a Dhall expression from binary"+ (Decode <$> parseFile <*> parseJSONFlag <*> parseQuiet)+ <|> subcommand+ Miscellaneous "repl" "Interpret expressions in a REPL" (pure Repl) <|> subcommand+ Miscellaneous "diff" "Render the difference between the normal form of two expressions" (Diff <$> argument "expr1" <*> argument "expr2") <|> subcommand+ Miscellaneous "hash" "Compute semantic hashes for Dhall expressions"- (pure Hash)- <|> subcommand- "lint"- "Improve Dhall code"- (Lint <$> optional parseInplace)+ (Hash <$> parseFile <*> parseCache) <|> subcommand- "format"- "Formatter for the Dhall language"- (Format <$> parseFormatMode)+ Miscellaneous+ "package"+ "Create a package.dhall referencing the provided paths"+ (Package <$> parsePackageOptions <*> parsePackageFiles) <|> subcommand- "freeze"- "Add integrity checks to remote import statements of an expression"- (Freeze <$> optional parseInplace <*> parseAllFlag <*> parseCacheFlag)+ Miscellaneous+ "tags"+ "Generate etags file"+ (Tags <$> parseInput <*> parseTagsOutput <*> parseSuffixes <*> parseFollowSymlinks) <|> subcommand- "encode"- "Encode a Dhall expression to binary"- (Encode <$> optional parseFile <*> parseJSONFlag)+ Miscellaneous+ "version"+ "Display version"+ (pure Version) <|> subcommand- "decode"- "Decode a Dhall expression from binary"- (Decode <$> optional parseFile <*> parseJSONFlag)- <|> (Default <$> optional parseFile <*> parseAnnotate <*> parseAlpha)+ Debugging+ "haskell-syntax-tree"+ "Output the parsed syntax tree (for debugging)"+ (SyntaxTree <$> parseFile <*> parseNoted)+ <|> ( Default+ <$> parseFile+ <*> parseOutput+ <*> parseAnnotate+ <*> parseAlpha+ <*> parseSemanticCacheMode+ <*> parseVersion+ ) where+ deprecatedInPlace =+ Options.Applicative.switch+ ( Options.Applicative.long "inplace"+ <> Options.Applicative.internal -- completely hidden from help+ )+ argument = fmap Data.Text.pack . Options.Applicative.strArgument . Options.Applicative.metavar - parseFile =- Options.Applicative.strOption- ( Options.Applicative.long "file"- <> Options.Applicative.help "Read expression from a file instead of standard input"- <> Options.Applicative.metavar "FILE"- )+ parseFile = fmap f (optional p)+ where+ f Nothing = StandardInput+ f (Just file) = InputFile file + p = Options.Applicative.strOption+ ( Options.Applicative.long "file"+ <> Options.Applicative.help "Read expression from a file instead of standard input"+ <> Options.Applicative.metavar "FILE"+ <> Options.Applicative.action "file"+ )++ parseFiles = fmap f (Options.Applicative.many p)+ where+ -- Parse explicit stdin in the input filepaths+ parseStdin inputs+ | InputFile "-" `elem` inputs = StandardInput : filter (/= InputFile "-") inputs+ | otherwise = inputs++ f = fromMaybe (pure StandardInput) . nonEmpty . parseStdin . fmap InputFile++ p = Options.Applicative.strArgument+ ( Options.Applicative.help "Read expression from files instead of standard input"+ <> Options.Applicative.metavar "FILES"+ <> Options.Applicative.action "file"+ )++ parseOutput = fmap f (optional p)+ where+ f Nothing = StandardOutput+ f (Just file) = OutputFile file++ p = Options.Applicative.strOption+ ( Options.Applicative.long "output"+ <> Options.Applicative.help "Write result to a file instead of standard output"+ <> Options.Applicative.metavar "FILE"+ <> Options.Applicative.action "file"+ )+ parseAlpha = Options.Applicative.switch ( Options.Applicative.long "alpha"@@ -209,6 +409,21 @@ <> Options.Applicative.help "Add a type annotation to the output" ) + parseSemanticCacheMode =+ Options.Applicative.flag+ UseSemanticCache+ IgnoreSemanticCache+ ( Options.Applicative.long "no-cache"+ <> Options.Applicative.help+ "Handle protected imports as if the cache was empty"+ )++ parseVersion =+ Options.Applicative.switch+ ( Options.Applicative.long "version"+ <> Options.Applicative.help "Display version"+ )+ parseResolveMode = Options.Applicative.flag' (Just Dot) ( Options.Applicative.long "dot"@@ -225,17 +440,76 @@ Options.Applicative.flag' (Just ListTransitiveDependencies) ( Options.Applicative.long "transitive-dependencies" <> Options.Applicative.help- "List transitive import dependencies"+ "List transitive import dependencies in post-order" ) <|> pure Nothing + parseQuiet =+ Options.Applicative.switch+ ( Options.Applicative.long "quiet"+ <> Options.Applicative.help "Don't print the result"+ )+ parseInplace = Options.Applicative.strOption- ( Options.Applicative.long "inplace"- <> Options.Applicative.help "Modify the specified file in-place"- <> Options.Applicative.metavar "FILE"+ ( Options.Applicative.long "inplace"+ <> Options.Applicative.help "Modify the specified file in-place"+ <> Options.Applicative.metavar "FILE"+ <> Options.Applicative.action "file"+ )++ parseTransitiveSwitch = Options.Applicative.flag NonTransitive Transitive+ ( Options.Applicative.long "transitive"+ <> Options.Applicative.help "Modify the input and its transitive relative imports in-place" ) + parseInplaceNonTransitive =+ fmap InputFile parseInplace+ <|> pure StandardInput++ parseInput = fmap f (optional p)+ where+ f Nothing = StandardInput+ f (Just path) = InputFile path++ p = Options.Applicative.strOption+ ( Options.Applicative.long "path"+ <> Options.Applicative.help "Index all files in path recursively. Will get list of files from STDIN if omitted."+ <> Options.Applicative.metavar "PATH"+ <> Options.Applicative.action "file"+ <> Options.Applicative.action "directory"+ )++ parseTagsOutput = fmap f (optional p)+ where+ f Nothing = OutputFile "tags"+ f (Just file) = OutputFile file++ p = Options.Applicative.strOption+ ( Options.Applicative.long "output"+ <> Options.Applicative.help "The name of the file that the tags are written to. Defaults to \"tags\""+ <> Options.Applicative.metavar "FILENAME"+ <> Options.Applicative.action "file"+ )++ parseSuffixes = fmap f (optional p)+ where+ f Nothing = Just [".dhall"]+ f (Just "") = Nothing+ f (Just line) = Just (Data.Text.splitOn " " line)++ p = Options.Applicative.strOption+ ( Options.Applicative.long "suffixes"+ <> Options.Applicative.help "Index only files with suffixes. \"\" to index all files."+ <> Options.Applicative.metavar "SUFFIXES"+ )++ parseFollowSymlinks =+ Options.Applicative.switch+ ( Options.Applicative.long "follow-symlinks"+ <> Options.Applicative.help "Follow symlinks when recursing directories"+ )+ parseJSONFlag = Options.Applicative.switch ( Options.Applicative.long "json"@@ -245,7 +519,7 @@ parseAllFlag = Options.Applicative.switch ( Options.Applicative.long "all"- <> Options.Applicative.help "Add integrity checks to all imports (not just remote imports)"+ <> Options.Applicative.help "Add integrity checks to all imports (not just remote imports) except for missing imports" ) parseCacheFlag =@@ -254,27 +528,77 @@ <> Options.Applicative.help "Add fallback unprotected imports when using integrity checks purely for caching purposes" ) - parseCheck =+ parseCheck processed = fmap adapt switch+ where+ adapt True = Check+ adapt False = Write++ switch =+ Options.Applicative.switch+ ( Options.Applicative.long "check"+ <> Options.Applicative.help ("Only check if the input is " <> processed)+ )++ parseSchemasRecord =+ Options.Applicative.strOption+ ( Options.Applicative.long "schemas"+ <> Options.Applicative.help "A record of schemas"+ <> Options.Applicative.metavar "EXPR"+ )++ parseDirectoryTreeAllowSeparators = Options.Applicative.switch- ( Options.Applicative.long "check"- <> Options.Applicative.help "Only check if the input is formatted"- )+ ( Options.Applicative.long "allow-path-separators"+ <> Options.Applicative.help "Whether to allow path separators in file names"+ ) - parseFormatMode = adapt <$> parseCheck <*> optional parseInplace- where- adapt True path = Dhall.Format.Check {..}- adapt False inplace = Dhall.Format.Modify {..}+ parseDirectoryTreeOutput =+ Options.Applicative.strOption+ ( Options.Applicative.long "output"+ <> Options.Applicative.help "The destination path to create"+ <> Options.Applicative.metavar "PATH"+ <> Options.Applicative.action "directory"+ ) -getExpression :: Maybe FilePath -> IO (Expr Src Import)-getExpression maybeFile = do- inText <- do- case maybeFile of- Just "-" -> Data.Text.IO.getContents- Just file -> Data.Text.IO.readFile file- Nothing -> Data.Text.IO.getContents+ parseNoted =+ Options.Applicative.switch+ ( Options.Applicative.long "noted"+ <> Options.Applicative.help "Print `Note` constructors"+ ) - Dhall.Core.throws (Dhall.Parser.exprFromText "(stdin)" inText)+ parseCache =+ Options.Applicative.switch+ ( Options.Applicative.long "cache"+ <> Options.Applicative.help "Cache the hashed expression"+ ) + parsePackageOptions :: Parser (Endo Dhall.Package.Options)+ parsePackageOptions = do+ packageMode <- (optional . Options.Applicative.flag' RecursiveSubpackages)+ ( Options.Applicative.short 'r'+ <> Options.Applicative.long "recursive"+ <> Options.Applicative.help "Create packages for all subdirectories first."+ )++ packageFileName <- (optional . Options.Applicative.strOption)+ ( Options.Applicative.long "name"+ <> Options.Applicative.help "The filename of the package"+ <> Options.Applicative.metavar "NAME"+ <> Options.Applicative.action "file"+ )++ pure $+ maybe mempty (Endo . set Dhall.Package.packagingMode) packageMode <>+ maybe mempty (Endo . set Dhall.Package.packageFileName) packageFileName++ parsePackageFiles = (:|) <$> p <*> Options.Applicative.many p+ where+ p = Options.Applicative.strArgument+ ( Options.Applicative.help "Paths that may either point to files or directories. If the latter is the case all *.dhall files in the directory will be included."+ <> Options.Applicative.metavar "PATH"+ <> Options.Applicative.action "file"+ )+ -- | `ParserInfo` for the `Options` type parserInfoOptions :: ParserInfo Options parserInfoOptions =@@ -284,40 +608,69 @@ <> Options.Applicative.fullDesc ) +noHeaders :: Import -> Import+noHeaders+ (Import { importHashed = ImportHashed { importType = Remote URL{ .. }, ..}, .. }) =+ Import { importHashed = ImportHashed { importType = Remote URL{ headers = Nothing, .. }, .. }, .. }+noHeaders i =+ i+ -- | Run the command specified by the `Options` type command :: Options -> IO () command (Options {..}) = do- let characterSet = case ascii of- True -> ASCII- False -> Unicode- GHC.IO.Encoding.setLocaleEncoding System.IO.utf8 - let toStatus maybeFile =- set Dhall.Import.standardVersion standardVersion- (Dhall.Import.emptyStatus file)- where- file = case maybeFile of- Just "-" -> "."- Just f -> f- Nothing -> "."+ let rootDirectory = \case+ InputFile f -> System.FilePath.takeDirectory f+ StandardInput -> "." - let handle =- Control.Exception.handle handler2- . Control.Exception.handle handler1- . Control.Exception.handle handler0+ let toStatus = Dhall.Import.emptyStatus . rootDirectory++ let getExpression = Dhall.Util.getExpression censor++ -- The characterSet detection used here only works on the source+ -- expression, before any transformation is applied. This helper is there+ -- make sure the detection is done on the correct expr.+ let getExpressionAndCharacterSet file = do+ expr <- getExpression file++ let characterSet = fromMaybe (detectCharacterSet expr) chosenCharacterSet++ return (expr, characterSet)++ let handle io =+ Control.Exception.catches io+ [ Handler handleTypeError+ , Handler handleImported+ , Handler handleExitCode+ ] where- handler0 e = do- let _ = e :: TypeError Src X+ handleAll e = do+ let string = show (e :: SomeException)++ if not (null string)+ then System.IO.hPutStrLn System.IO.stderr string+ else return ()++ System.Exit.exitFailure++ handleTypeError e = Control.Exception.handle handleAll $ do+ let _ = e :: TypeError Src Void System.IO.hPutStrLn System.IO.stderr "" if explain- then Control.Exception.throwIO (DetailedTypeError e)+ then+ case censor of+ Censor -> Control.Exception.throwIO (CensoredDetailed (DetailedTypeError e))+ NoCensor -> Control.Exception.throwIO (DetailedTypeError e)+ else do Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"- Control.Exception.throwIO e+ case censor of+ Censor -> Control.Exception.throwIO (Censored e)+ NoCensor -> Control.Exception.throwIO e - handler1 (Imported ps e) = do- let _ = e :: TypeError Src X+ handleImported (Imported ps e) = Control.Exception.handle handleAll $ do+ let _ = e :: TypeError Src Void System.IO.hPutStrLn System.IO.stderr "" if explain then Control.Exception.throwIO (Imported ps (DetailedTypeError e))@@ -325,18 +678,12 @@ Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m" Control.Exception.throwIO (Imported ps e) - handler2 e = do- let string = show (e :: SomeException)-- if not (null string)- then System.IO.hPutStrLn System.IO.stderr string- else return ()-- System.Exit.exitFailure+ handleExitCode e =+ Control.Exception.throwIO (e :: ExitCode) let renderDoc :: Handle -> Doc Ann -> IO () renderDoc h doc = do- let stream = Pretty.layoutSmart layoutOpts doc+ let stream = Dhall.Pretty.layout doc supportsANSI <- System.Console.ANSI.hSupportsANSI h let ansiStream =@@ -347,28 +694,34 @@ Pretty.renderIO h ansiStream Data.Text.IO.hPutStrLn h "" - let render :: Pretty a => Handle -> Expr s a -> IO ()- render h expression = do+ let render :: Pretty a => Handle -> CharacterSet -> Expr Src a -> IO ()+ render h characterSet expression = do let doc = Dhall.Pretty.prettyCharacterSet characterSet expression renderDoc h doc - handle $ case mode of- Version -> do- let line₀ = "Haskell package version: "- <> Data.Text.pack (showVersion Meta.version)+ let writeDocToFile :: FilePath -> Doc ann -> IO ()+ writeDocToFile file doc = do+ let stream = Dhall.Pretty.layout (doc <> "\n") - let line₁ = "Standard version: "- <> Dhall.Binary.renderStandardVersion Dhall.Binary.defaultStandardVersion+ AtomicWrite.LazyText.atomicWriteFile file (Pretty.Text.renderLazy stream) - Data.Text.IO.putStrLn line₀- Data.Text.IO.putStrLn line₁+ handle $ case mode of+ Version ->+ putStrLn dhallVersionString Default {..} -> do- expression <- getExpression file+ if version+ then do+ putStrLn dhallVersionString+ Exit.exitSuccess+ else return () - resolvedExpression <- State.evalStateT (Dhall.Import.loadWith expression) (toStatus file)+ (expression, characterSet) <- getExpressionAndCharacterSet file + resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) semanticCacheMode expression+ inferredType <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression) let normalizedExpression = Dhall.Core.normalize resolvedExpression@@ -383,47 +736,75 @@ then Annot alphaNormalizedExpression inferredType else alphaNormalizedExpression - render System.IO.stdout annotatedExpression+ case output of+ StandardOutput -> render System.IO.stdout characterSet annotatedExpression + OutputFile file_ ->+ writeDocToFile+ file_+ (Dhall.Pretty.prettyCharacterSet characterSet annotatedExpression)+ Resolve { resolveMode = Just Dot, ..} -> do expression <- getExpression file - (Dhall.Import.Types.Status { _dot}) <-- State.execStateT (Dhall.Import.loadWith expression) (toStatus file)+ (Dhall.Import.Types.Status { _graph, _stack }) <-+ State.execStateT (Dhall.Import.loadWith expression) (toStatus file) { _semanticCacheMode = semanticCacheMode } - putStr . ("strict " <>) . Text.Dot.showDot $- Text.Dot.attribute ("rankdir", "LR") >>- _dot+ let (rootImport :| _) = _stack+ imports = rootImport : map parent _graph ++ map child _graph+ importIds = Data.Map.fromList (zip imports [Text.Dot.userNodeId i | i <- [0..]]) + let dotNode (i, nodeId) =+ Text.Dot.userNode+ nodeId+ [ ("label", Data.Text.unpack $ pretty (convert i))+ , ("shape", "box")+ , ("style", "rounded")+ ]+ where+ convert = noHeaders . Dhall.Import.chainedImport++ let dotEdge (Depends parent child) =+ case (Data.Map.lookup parent importIds, Data.Map.lookup child importIds) of+ (Just from, Just to) -> from .->. to+ _ -> pure ()++ let dot = do Text.Dot.attribute ("rankdir", "LR")+ mapM_ dotNode (Data.Map.assocs importIds)+ mapM_ dotEdge _graph++ putStr . ("strict " <>) . Text.Dot.showDot $ dot+ Resolve { resolveMode = Just ListImmediateDependencies, ..} -> do expression <- getExpression file - mapM_ (print- . Pretty.pretty- . Dhall.Core.importHashed) expression+ mapM_ (print . Pretty.pretty . noHeaders) expression Resolve { resolveMode = Just ListTransitiveDependencies, ..} -> do expression <- getExpression file (Dhall.Import.Types.Status { _cache }) <-- State.execStateT (Dhall.Import.loadWith expression) (toStatus file)+ State.execStateT (Dhall.Import.loadWith expression) (toStatus file) { _semanticCacheMode = semanticCacheMode } mapM_ print- . fmap ( Pretty.pretty- . Dhall.Core.importType- . Dhall.Core.importHashed )- . Data.Map.keys+ . fmap ( Pretty.pretty+ . noHeaders+ . Dhall.Import.chainedImport+ )+ . reverse+ . Dhall.Map.keys $ _cache Resolve { resolveMode = Nothing, ..} -> do- expression <- getExpression file+ (expression, characterSet) <- getExpressionAndCharacterSet file - (resolvedExpression, _) <-- State.runStateT (Dhall.Import.loadWith expression) (toStatus file)- render System.IO.stdout resolvedExpression+ resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) semanticCacheMode expression + render System.IO.stdout characterSet resolvedExpression+ Normalize {..} -> do- expression <- getExpression file+ (expression, characterSet) <- getExpressionAndCharacterSet file resolvedExpression <- Dhall.Import.assertNoImports expression @@ -436,19 +817,24 @@ then Dhall.Core.alphaNormalize normalizedExpression else normalizedExpression - render System.IO.stdout alphaNormalizedExpression+ render System.IO.stdout characterSet alphaNormalizedExpression Type {..} -> do- expression <- getExpression file+ (expression, characterSet) <- getExpressionAndCharacterSet file - resolvedExpression <- Dhall.Import.assertNoImports expression+ resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) semanticCacheMode expression inferredType <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression) - render System.IO.stdout (Dhall.Core.normalize inferredType)+ if quiet+ then return ()+ else render System.IO.stdout characterSet inferredType - Repl -> do- Dhall.Repl.repl characterSet explain standardVersion+ Repl ->+ Dhall.Repl.repl+ (fromMaybe Unicode chosenCharacterSet) -- Default to Unicode if no characterSet specified+ explain Diff {..} -> do expression1 <- Dhall.inputExpr expr1@@ -457,54 +843,116 @@ let diff = Dhall.Diff.diffNormalized expression1 expression2 - renderDoc System.IO.stdout diff+ renderDoc System.IO.stdout (Dhall.Diff.doc diff) + if Dhall.Diff.same diff+ then return ()+ else Exit.exitFailure+ Format {..} -> do- Dhall.Format.format (Dhall.Format.Format {..})+ when deprecatedInPlace $+ System.IO.hPutStrLn System.IO.stderr "Warning: the flag \"--inplace\" is deprecated" + Dhall.Format.format Dhall.Format.Format{..}+ Freeze {..} -> do+ when deprecatedInPlace $+ System.IO.hPutStrLn System.IO.stderr "Warning: the flag \"--inplace\" is deprecated"+ let scope = if all_ then AllImports else OnlyRemoteImports let intent = if cache then Cache else Secure - Dhall.Freeze.freeze inplace scope intent characterSet standardVersion+ Dhall.Freeze.freeze outputMode transitivity inputs scope intent chosenCharacterSet censor - Hash -> do- Dhall.Hash.hash standardVersion+ Hash {..} -> do+ expression <- getExpression file - Lint {..} -> do- case inplace of- Just file -> do- text <- Data.Text.IO.readFile file+ resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression - (header, expression) <- Dhall.Core.throws (Dhall.Parser.exprAndHeaderFromText file text)+ _ <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression) - let lintedExpression = Dhall.Lint.lint expression+ let normalizedExpression =+ Dhall.Core.alphaNormalize (Dhall.Core.normalize resolvedExpression) - let doc = Pretty.pretty header- <> Dhall.Pretty.prettyCharacterSet characterSet lintedExpression+ if cache+ then Dhall.Import.writeExpressionToSemanticCache normalizedExpression+ else return () - System.IO.withFile file System.IO.WriteMode (\h -> do- renderDoc h doc )+ Data.Text.IO.putStrLn (Dhall.Import.hashExpressionToCode normalizedExpression) - Nothing -> do- text <- Data.Text.IO.getContents+ Lint { transitivity = transitivity0, ..} -> do+ when deprecatedInPlace $+ System.IO.hPutStrLn System.IO.stderr "Warning: the flag \"--inplace\" is deprecated" - (header, expression) <- Dhall.Core.throws (Dhall.Parser.exprAndHeaderFromText "(stdin)" text)+ handleMultipleChecksFailed "lint" "linted" go inputs+ where+ go input = do+ let directory = case input of+ StandardInput -> "."+ InputFile file -> System.FilePath.takeDirectory file - let lintedExpression = Dhall.Lint.lint expression+ let status = Dhall.Import.emptyStatus directory - let doc = Pretty.pretty header- <> Dhall.Pretty.prettyCharacterSet characterSet lintedExpression+ (inputName, originalText, transitivity) <- case input of+ InputFile file -> do+ text <- Data.Text.IO.readFile file - renderDoc System.IO.stdout doc+ return (file, text, transitivity0)+ StandardInput -> do+ text <- Data.Text.IO.getContents + return ("(input)", text, NonTransitive)++ (Header header, parsedExpression) <-+ Dhall.Util.getExpressionAndHeaderFromStdinText censor inputName originalText++ let characterSet = fromMaybe (detectCharacterSet parsedExpression) chosenCharacterSet++ case transitivity of+ Transitive ->+ for_ parsedExpression $ \import_ -> do+ maybeFilepath <- Dhall.Import.dependencyToFile status import_++ for_ maybeFilepath $ \filepath ->+ go (InputFile filepath)++ NonTransitive ->+ return ()++ let lintedExpression = Dhall.Lint.lint parsedExpression++ let doc = Pretty.pretty header+ <> Dhall.Pretty.prettyCharacterSet characterSet lintedExpression++ let stream = Dhall.Pretty.layout doc++ let modifiedText = Pretty.Text.renderStrict stream <> "\n"++ case outputMode of+ Write -> do+ case input of+ InputFile file ->+ if originalText == modifiedText+ then return ()+ else writeDocToFile file doc++ StandardInput ->+ renderDoc System.IO.stdout doc++ return (Right ())++ Check ->+ return $+ if originalText == modifiedText+ then Right ()+ else Left CheckFailed{..}+ Encode {..} -> do expression <- getExpression file - let term = Dhall.Binary.encode expression-- let bytes = Codec.Serialise.serialise term+ let bytes = Dhall.Binary.encodeExpression (Dhall.Core.denote expression) if json then do@@ -516,16 +964,16 @@ Data.ByteString.Lazy.Char8.putStrLn jsonBytes - else do+ else Data.ByteString.Lazy.putStr bytes Decode {..} -> do- bytes <- do+ bytes <- case file of- Just f -> Data.ByteString.Lazy.readFile f- Nothing -> Data.ByteString.Lazy.getContents+ InputFile f -> Data.ByteString.Lazy.readFile f+ StandardInput -> Data.ByteString.Lazy.getContents - term <- do+ expression <- if json then do value <- case Data.Aeson.eitherDecode' bytes of@@ -534,19 +982,92 @@ let encoding = Codec.CBOR.JSON.encodeValue value - let cborBytes = Codec.CBOR.Write.toLazyByteString encoding- Dhall.Core.throws (Codec.Serialise.deserialiseOrFail cborBytes)- else do- Dhall.Core.throws (Codec.Serialise.deserialiseOrFail bytes)+ let cborgBytes = Codec.CBOR.Write.toLazyByteString encoding - expression <- Dhall.Core.throws (Dhall.Binary.decodeExpression term)+ Dhall.Core.throws (Dhall.Binary.decodeExpression cborgBytes)+ else+ Dhall.Core.throws (Dhall.Binary.decodeExpression bytes) - let doc = Dhall.Pretty.prettyCharacterSet characterSet expression - renderDoc System.IO.stdout doc+ if quiet+ then return ()+ else do+ let doc =+ Dhall.Pretty.prettyCharacterSet+ (fromMaybe Unicode chosenCharacterSet) -- default to Unicode+ (Dhall.Core.renote expression :: Expr Src Import) + renderDoc System.IO.stdout doc++ Text {..} -> do+ expression <- getExpression file++ resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression++ _ <- Dhall.Core.throws (Dhall.TypeCheck.typeOf (Annot resolvedExpression Dhall.Core.Text))++ let normalizedExpression = Dhall.Core.normalize resolvedExpression++ case normalizedExpression of+ Dhall.Core.TextLit (Dhall.Core.Chunks [] text) ->+ let write = case output of+ StandardOutput -> Data.Text.IO.putStr+ OutputFile file_ -> Data.Text.IO.writeFile file_+ in write text+ _ -> do+ let invalidDecoderExpected :: Expr Void Void+ invalidDecoderExpected = Dhall.Core.Text++ let invalidDecoderExpression :: Expr Void Void+ invalidDecoderExpression = normalizedExpression++ Control.Exception.throwIO (Dhall.InvalidDecoder {..})++ Tags {..} -> do+ tags <- Dhall.Tags.generate input suffixes followSymlinks++ case output of+ OutputFile file ->+ System.IO.withFile file System.IO.WriteMode (`Data.Text.IO.hPutStr` tags)++ StandardOutput -> Data.Text.IO.putStrLn tags++ DirectoryTree {..} -> do+ expression <- getExpression file++ resolvedExpression <-+ Dhall.Import.loadRelativeTo (rootDirectory file) UseSemanticCache expression++ _ <- Dhall.Core.throws (Dhall.TypeCheck.typeOf resolvedExpression)++ let normalizedExpression = Dhall.Core.normalize resolvedExpression++ DirectoryTree.toDirectoryTree allowSeparators path normalizedExpression++ Dhall.Main.Schemas{..} ->+ Dhall.Schemas.schemasCommand Dhall.Schemas.Schemas{ input = file, ..}++ SyntaxTree {..} -> do+ expression <- getExpression file++ if noted then+ Text.Pretty.Simple.pPrintNoColor expression+ else+ let denoted :: Expr Void Import+ denoted = Dhall.Core.denote expression+ in Text.Pretty.Simple.pPrintNoColor denoted++ Package {..} -> do+ let options = appEndo+ (maybe mempty (Endo . set Dhall.Package.characterSet) chosenCharacterSet+ <> packageOptions+ ) Dhall.Package.defaultOptions+ writePackage options packageFiles+ -- | Entry point for the @dhall@ executable main :: IO () main = do options <- Options.Applicative.execParser parserInfoOptions- command options++ Dhall.Main.command options
@@ -1,8 +1,11 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-} -- | `Map` type used to represent records and unions @@ -11,9 +14,16 @@ Map -- * Construction+ , empty , singleton , fromList+ , fromListWithKey+ , fromMap + -- * Constructing unordered 'Map's+ , unorderedSingleton+ , unorderedFromList+ -- * Sorting , sort , isSorted@@ -25,16 +35,21 @@ -- * Deletion/Update , delete , filter+ , partition+ , restrictKeys+ , withoutKeys , mapMaybe -- * Query , lookup , member , uncons+ , size -- * Combine , union , unionWith+ , outerJoin , intersection , intersectionWith , difference@@ -42,25 +57,33 @@ -- * Traversals , mapWithKey , traverseWithKey- , traverseWithKey_+ , unorderedTraverseWithKey , unorderedTraverseWithKey_ , foldMapWithKey -- * Conversions , toList+ , toAscList , toMap , keys+ , keysSet+ , elems ) where -import Control.Applicative ((<|>))-import Data.Data (Data)-import Data.Foldable (traverse_)-import Data.Semigroup-import Prelude hiding (filter, lookup)+import Control.Applicative ((<|>))+import Control.DeepSeq (NFData)+import Data.Data (Data)+import GHC.Generics (Generic)+import Instances.TH.Lift ()+import Language.Haskell.TH.Syntax (Lift)+import Prelude hiding (filter, lookup) -import qualified Data.Functor-import qualified Data.Map+import qualified Data.Foldable.WithIndex as Foldable.WithIndex+import qualified Data.Functor.WithIndex as Functor.WithIndex+import qualified Data.List+import qualified Data.Map.Strict import qualified Data.Set+import qualified Data.Traversable.WithIndex as Traversable.WithIndex import qualified GHC.Exts import qualified Prelude @@ -71,44 +94,62 @@ This is done primarily to avoid a dependency on @insert-ordered-containers@ and also to improve performance -}-data Map k v = Map (Data.Map.Map k v) [k]- deriving (Data)+data Map k v = Map (Data.Map.Strict.Map k v) (Keys k)+ deriving (Data, Generic, Lift, NFData) -instance (Eq k, Eq v) => Eq (Map k v) where- Map m1 ks == Map m2 ks' = m1 == m2 && ks == ks'+data Keys a+ = Sorted+ | Original [a]+ deriving (Data, Generic, Lift, NFData)++instance (Ord k, Eq v) => Eq (Map k v) where+ m1 == m2 =+ Data.Map.Strict.size (toMap m1) == Data.Map.Strict.size (toMap m2)+ && toList m1 == toList m2 {-# INLINABLE (==) #-} +{-|+>>> fromList [("A",1),("B",2)] < fromList [("B",1),("A",0)]+True+-} instance (Ord k, Ord v) => Ord (Map k v) where- compare (Map mL ksL) (Map mR ksR) = compare mL mR <> compare ksL ksR+ compare m1 m2 = compare (toList m1) (toList m2)+ {-# INLINABLE compare #-} instance Functor (Map k) where fmap f (Map m ks) = Map (fmap f m) ks {-# INLINABLE fmap #-} -instance Foldable (Map k) where- foldr f z (Map m _) = foldr f z m+instance Ord k => Foldable (Map k) where+ foldr f z (Map m Sorted) = foldr f z m+ foldr f z m = foldr f z (elems m) {-# INLINABLE foldr #-} - foldMap f (Map m _) = foldMap f m- {-# INLINABLE foldMap #-}+ length m = size m+ {-# INLINABLE length #-} -instance Traversable (Map k) where- traverse f (Map m ks) = (\m' -> Map m' ks) <$> traverse f m+ null (Map m _) = null m+ {-# INLINABLE null #-}++instance Ord k => Traversable (Map k) where+ traverse f m = traverseWithKey (\_ v -> f v) m {-# INLINABLE traverse #-} -instance Ord k => Data.Semigroup.Semigroup (Map k v) where+{-|+prop> \x y z -> x <> (y <> z) == (x <> y) <> (z :: Map Int Int)+-}+instance Ord k => Semigroup (Map k v) where (<>) = union {-# INLINABLE (<>) #-} +{-|+prop> \x -> x <> mempty == (x :: Map Int Int)+prop> \x -> mempty <> x == (x :: Map Int Int)+-} instance Ord k => Monoid (Map k v) where- mempty = Map Data.Map.empty []+ mempty = Map Data.Map.Strict.empty (Original []) {-# INLINABLE mempty #-} -#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)- {-# INLINABLE mappend #-}-#endif- instance (Show k, Show v, Ord k) => Show (Map k v) where showsPrec d m = showParen (d > 10) (showString "fromList " . showsPrec 11 kvs)@@ -122,6 +163,22 @@ toList = Dhall.Map.toList +instance Ord k => Foldable.WithIndex.FoldableWithIndex k (Map k) where+ ifoldMap = foldMapWithKey+ {-# INLINABLE ifoldMap #-}++instance Functor.WithIndex.FunctorWithIndex k (Map k) where+ imap = mapWithKey+ {-# INLINABLE imap #-}++instance Ord k => Traversable.WithIndex.TraversableWithIndex k (Map k) where+ itraverse = traverseWithKey+ {-# INLINABLE itraverse #-}++-- | Create an empty `Map`+empty :: Ord k => Map k v+empty = mempty+ {-| Create a `Map` from a single key-value pair >>> singleton "A" 1@@ -130,30 +187,52 @@ singleton :: k -> v -> Map k v singleton k v = Map m ks where- m = Data.Map.singleton k v+ m = Data.Map.Strict.singleton k v - ks = pure k+ ks = Original [k] {-# INLINABLE singleton #-} {-| Create a `Map` from a list of key-value pairs -> fromList empty = mempty->-> fromList (x <|> y) = fromList x <> fromList y- >>> fromList [("B",1),("A",2)] -- The map preserves order fromList [("B",1),("A",2)] >>> fromList [("A",1),("A",2)] -- For duplicates, later values take precedence fromList [("A",2)]++Note that this handling of duplicates means that 'fromList' is /not/ a monoid+homomorphism:++>>> fromList [(1, True)] <> fromList [(1, False)]+fromList [(1,True)]+>>> fromList ([(1, True)] <> [(1, False)])+fromList [(1,False)]+ -} fromList :: Ord k => [(k, v)] -> Map k v fromList kvs = Map m ks where- m = Data.Map.fromList kvs+ m = Data.Map.Strict.fromList kvs - ks = nubOrd (map fst kvs)+ ks = Original (nubOrd (map fst kvs)) {-# INLINABLE fromList #-} +{-| Create a `Map` from a list of key-value pairs with a combining function.++>>> fromListWithKey (\k v1 v2 -> k ++ v1 ++ v2) [("B","v1"),("A","v2"),("B","v3")]+fromList [("B","Bv3v1"),("A","v2")]+-}+fromListWithKey :: Ord k => (k -> v -> v -> v) -> [(k, v)] -> Map k v+fromListWithKey f kvs = Map m ks+ where+ m = Data.Map.Strict.fromListWithKey f kvs++ ks = Original (nubOrd (map fst kvs))+{-# INLINABLE fromListWithKey #-}++-- | Create a `Map` from a @"Data.Map.Strict".`Data.Map.Strict.Map`@+fromMap :: Data.Map.Strict.Map k v -> Map k v+fromMap m = Map m Sorted+ {-| Remove duplicates from a list >>> nubOrd [1,2,3]@@ -170,6 +249,36 @@ | otherwise = k : go (Data.Set.insert k set) ks {-# INLINABLE nubOrd #-} +{-| Create a `Map` from a single key-value pair.++ Any further operations on this map will not retain the order of the keys.++>>> unorderedSingleton "A" 1+fromList [("A",1)]+-}+unorderedSingleton :: k -> v -> Map k v+unorderedSingleton k v = Map m Sorted+ where+ m = Data.Map.Strict.singleton k v+{-# INLINABLE unorderedSingleton #-}++{-| Create a `Map` from a list of key-value pairs++ Any further operations on this map will not retain the order of the keys.++>>> unorderedFromList []+fromList []+>>> unorderedFromList [("B",1),("A",2)] -- The map /doesn't/ preserve order+fromList [("A",2),("B",1)]+>>> unorderedFromList [("A",1),("A",2)] -- For duplicates, later values take precedence+fromList [("A",2)]+-}+unorderedFromList :: Ord k => [(k, v)] -> Map k v+unorderedFromList kvs = Map m Sorted+ where+ m = Data.Map.Strict.fromList kvs+{-# INLINABLE unorderedFromList #-}+ {-| Sort the keys of a `Map`, forgetting the original ordering > sort (sort x) = sort x@@ -177,10 +286,8 @@ >>> sort (fromList [("B",1),("A",2)]) fromList [("A",2),("B",1)] -}-sort :: Ord k => Map k v -> Map k v-sort (Map m _) = Map m ks- where- ks = Data.Map.keys m+sort :: Map k v -> Map k v+sort (Map m _) = Map m Sorted {-# INLINABLE sort #-} {-| Check if the keys of a `Map` are already sorted@@ -193,7 +300,8 @@ True -} isSorted :: Eq k => Map k v -> Bool-isSorted (Map m k) = Data.Map.keys m == k+isSorted (Map _ Sorted) = True+isSorted (Map m (Original ks)) = Data.Map.Strict.keys m == ks -- Or shortcut to False here? {-# INLINABLE isSorted #-} {-| Insert a key-value pair into a `Map`, overriding any previous value stored@@ -207,12 +315,13 @@ fromList [("C",1),("A",3)] -} insert :: Ord k => k -> v -> Map k v -> Map k v-insert k v (Map m ks) = Map m' ks'+insert k v (Map m Sorted) = Map (Data.Map.Strict.insert k v m) Sorted+insert k v (Map m (Original ks)) = Map m' (Original ks') where- m' = Data.Map.insert k v m+ (mayOldV, m') = Data.Map.Strict.insertLookupWithKey (\_k new _old -> new) k v m - ks' | elem k ks = ks- | otherwise = k : ks+ ks' | Just _ <- mayOldV = ks+ | otherwise = k : ks {-# INLINABLE insert #-} {-| Insert a key-value pair into a `Map`, using the supplied function to combine@@ -224,12 +333,13 @@ fromList [("C",3),("A",3)] -} insertWith :: Ord k => (v -> v -> v) -> k -> v -> Map k v -> Map k v-insertWith f k v (Map m ks) = Map m' ks'+insertWith f k v (Map m Sorted) = Map (Data.Map.Strict.insertWith f k v m) Sorted+insertWith f k v (Map m (Original ks)) = Map m' (Original ks') where- m' = Data.Map.insertWith f k v m+ (mayOldV, m') = Data.Map.Strict.insertLookupWithKey (\_k new old -> f new old) k v m - ks' | elem k ks = ks- | otherwise = k : ks+ ks' | Just _ <- mayOldV = ks+ | otherwise = k : ks {-# INLINABLE insertWith #-} {-| Delete a key from a `Map` if present, otherwise return the original `Map`@@ -242,9 +352,11 @@ delete :: Ord k => k -> Map k v -> Map k v delete k (Map m ks) = Map m' ks' where- m' = Data.Map.delete k m+ m' = Data.Map.Strict.delete k m - ks' = Prelude.filter (k /=) ks+ ks' = case ks of+ Sorted -> Sorted+ Original ks'' -> Original (Data.List.delete k ks'') {-# INLINABLE delete #-} {-| Keep all values that satisfy the given predicate@@ -257,13 +369,52 @@ filter :: Ord k => (a -> Bool) -> Map k a -> Map k a filter predicate (Map m ks) = Map m' ks' where- m' = Data.Map.filter predicate m-- set = Data.Map.keysSet m'+ m' = Data.Map.Strict.filter predicate m - ks' = Prelude.filter (\k -> Data.Set.member k set) ks+ ks' = filterKeys (\k -> Data.Map.Strict.member k m') ks {-# INLINABLE filter #-} +{-| Split the map into values that do and don't satisfy the predicate++>>> partition even (fromList [("C",3),("B",2),("A",1)])+(fromList [("B",2)],fromList [("C",3),("A",1)])+>>> partition odd (fromList [("C",3),("B",2),("A",1)])+(fromList [("C",3),("A",1)],fromList [("B",2)])+-}+partition :: Ord k => (a -> Bool) -> Map k a -> (Map k a, Map k a)+partition predicate (Map m ks) = (Map mpass kpass, Map mfail kfail)+ where+ (mpass, mfail) = Data.Map.Strict.partition predicate m++ (kpass, kfail) = partitionKeys (\k -> Data.Map.Strict.member k mpass) ks+{-# INLINABLE partition #-}++{-| Restrict a 'Map' to only those keys found in a @"Data.Set".'Data.Set.Set'@.++>>> restrictKeys (fromList [("A",1),("B",2)]) (Data.Set.fromList ["A"])+fromList [("A",1)]+-}+restrictKeys :: Ord k => Map k a -> Data.Set.Set k -> Map k a+restrictKeys (Map m ks) s = Map m' ks'+ where+ m' = Data.Map.Strict.restrictKeys m s++ ks' = filterKeys (\k -> Data.Set.member k s) ks+{-# INLINABLE restrictKeys #-}++{-| Remove all keys in a @"Data.Set".'Data.Set.Set'@ from a 'Map'++>>> withoutKeys (fromList [("A",1),("B",2)]) (Data.Set.fromList ["A"])+fromList [("B",2)]+-}+withoutKeys :: Ord k => Map k a -> Data.Set.Set k -> Map k a+withoutKeys (Map m ks) s = Map m' ks'+ where+ m' = Data.Map.Strict.withoutKeys m s++ ks' = filterKeys (\k -> Data.Set.notMember k s) ks+{-# INLINABLE withoutKeys #-}+ {-| Transform all values in a `Map` using the supplied function, deleting the key if the function returns `Nothing` @@ -273,11 +424,9 @@ mapMaybe :: Ord k => (a -> Maybe b) -> Map k a -> Map k b mapMaybe f (Map m ks) = Map m' ks' where- m' = Data.Map.mapMaybe f m-- set = Data.Map.keysSet m'+ m' = Data.Map.Strict.mapMaybe f m - ks' = Prelude.filter (\k -> Data.Set.member k set) ks+ ks' = filterKeys (\k -> Data.Map.Strict.member k m') ks {-# INLINABLE mapMaybe #-} {-| Retrieve a key from a `Map`@@ -292,7 +441,7 @@ Nothing -} lookup :: Ord k => k -> Map k v -> Maybe v-lookup k (Map m _) = Data.Map.lookup k m+lookup k (Map m _) = Data.Map.Strict.lookup k m {-# INLINABLE lookup #-} {-| Retrieve the first key, value of the 'Map', if present,@@ -308,8 +457,12 @@ Nothing -} uncons :: Ord k => Map k v -> Maybe (k, v, Map k v)-uncons (Map _ []) = Nothing-uncons (Map m (k:ks)) = Just (k, m Data.Map.! k, Map (Data.Map.delete k m) ks)+uncons (Map _ (Original [])) = Nothing+uncons (Map m (Original (k:ks))) =+ Just (k, m Data.Map.Strict.! k, Map (Data.Map.Strict.delete k m) (Original ks))+uncons (Map m Sorted)+ | Just ((k, v), m') <- Data.Map.Strict.minViewWithKey m = Just (k, v, Map m' Sorted)+ | otherwise = Nothing {-# INLINABLE uncons #-} {-| Check if a key belongs to a `Map`@@ -324,9 +477,17 @@ False -} member :: Ord k => k -> Map k v -> Bool-member k (Map m _) = Data.Map.member k m+member k (Map m _) = Data.Map.Strict.member k m {-# INLINABLE member #-} +{-|+>>> size (fromList [("A",1)])+1+-}+size :: Map k v -> Int+size (Map m _) = Data.Map.Strict.size m+{-# INLINABLE size #-}+ {-| Combine two `Map`s, preferring keys from the first `Map` > union = unionWith (\v _ -> v)@@ -339,11 +500,12 @@ union :: Ord k => Map k v -> Map k v -> Map k v union (Map mL ksL) (Map mR ksR) = Map m ks where- m = Data.Map.union mL mR-- setL = Data.Map.keysSet mL+ m = Data.Map.Strict.union mL mR - ks = ksL <|> Prelude.filter (\k -> Data.Set.notMember k setL) ksR+ ks = case (ksL, ksR) of+ (Original l, Original r) -> Original $+ l <|> Prelude.filter (\k -> Data.Map.Strict.notMember k mL) r+ _ -> Sorted {-# INLINABLE union #-} {-| Combine two `Map`s using a combining function for colliding keys@@ -356,13 +518,44 @@ unionWith :: Ord k => (v -> v -> v) -> Map k v -> Map k v -> Map k v unionWith combine (Map mL ksL) (Map mR ksR) = Map m ks where- m = Data.Map.unionWith combine mL mR-- setL = Data.Map.keysSet mL+ m = Data.Map.Strict.unionWith combine mL mR - ks = ksL <|> Prelude.filter (\k -> Data.Set.notMember k setL) ksR+ ks = case (ksL, ksR) of+ (Original l, Original r) -> Original $+ l <|> Prelude.filter (\k -> Data.Map.Strict.notMember k mL) r+ _ -> Sorted {-# INLINABLE unionWith #-} +{-| A generalised 'unionWith'.++>>> outerJoin Left Left (\k a b -> Right (k, a, b)) (fromList [("A",1),("B",2)]) (singleton "A" 3)+fromList [("A",Right ("A",1,3)),("B",Left 2)]++This function is much inspired by the "Data.Semialign.Semialign" class.+-}+outerJoin+ :: Ord k+ => (a -> c)+ -> (b -> c)+ -> (k -> a -> b -> c)+ -> Map k a+ -> Map k b+ -> Map k c+outerJoin fa fb fab (Map ma ksA) (Map mb ksB) = Map m ks+ where+ m = Data.Map.Strict.mergeWithKey+ (\k a b -> Just (fab k a b))+ (fmap fa)+ (fmap fb)+ ma+ mb++ ks = case (ksA, ksB) of+ (Original l, Original r) -> Original $+ l <|> Prelude.filter (\k -> Data.Map.Strict.notMember k ma) r+ _ -> Sorted+{-# INLINABLE outerJoin #-}+ {-| Combine two `Map` on their shared keys, keeping the value from the first `Map` @@ -374,12 +567,10 @@ intersection :: Ord k => Map k a -> Map k b -> Map k a intersection (Map mL ksL) (Map mR _) = Map m ks where- m = Data.Map.intersection mL mR+ m = Data.Map.Strict.intersection mL mR - setL = Data.Map.keysSet mL- setR = Data.Map.keysSet mR- set = Data.Set.intersection setL setR- ks = Prelude.filter (\k -> Data.Set.member k set) ksL+ -- Or forget order unless both maps are ordered?!+ ks = filterKeys (\k -> Data.Map.Strict.member k m) ksL {-# INLINABLE intersection #-} {-| Combine two `Map`s on their shared keys, using the supplied function to@@ -391,12 +582,10 @@ intersectionWith :: Ord k => (a -> b -> c) -> Map k a -> Map k b -> Map k c intersectionWith combine (Map mL ksL) (Map mR _) = Map m ks where- m = Data.Map.intersectionWith combine mL mR+ m = Data.Map.Strict.intersectionWith combine mL mR - setL = Data.Map.keysSet mL- setR = Data.Map.keysSet mR- set = Data.Set.intersection setL setR- ks = Prelude.filter (\k -> Data.Set.member k set) ksL+ -- Or forget order unless both maps are ordered?!+ ks = filterKeys (\k -> Data.Map.Strict.member k m) ksL {-# INLINABLE intersectionWith #-} {-| Compute the difference of two `Map`s by subtracting all keys from the@@ -408,11 +597,9 @@ difference :: Ord k => Map k a -> Map k b -> Map k a difference (Map mL ksL) (Map mR _) = Map m ks where- m = Data.Map.difference mL mR-- setR = Data.Map.keysSet mR+ m = Data.Map.Strict.difference mL mR - ks = Prelude.filter (\k -> Data.Set.notMember k setR) ksL+ ks = filterKeys (\k -> Data.Map.Strict.notMember k mR) ksL {-# INLINABLE difference #-} {-| Fold all of the key-value pairs in a `Map`, in their original order@@ -421,7 +608,8 @@ ("BA",[1,2]) -} foldMapWithKey :: (Monoid m, Ord k) => (k -> a -> m) -> Map k a -> m-foldMapWithKey f m = foldMap (uncurry f) (toList m)+foldMapWithKey f (Map m Sorted) = Data.Map.Strict.foldMapWithKey f m+foldMapWithKey f m = foldMap (uncurry f) (toList m) {-# INLINABLE foldMapWithKey #-} {-| Transform the values of a `Map` using their corresponding key@@ -440,7 +628,7 @@ mapWithKey :: (k -> a -> b) -> Map k a -> Map k b mapWithKey f (Map m ks) = Map m' ks where- m' = Data.Map.mapWithKey f m+ m' = Data.Map.Strict.mapWithKey f m {-# INLINABLE mapWithKey #-} {-| Traverse all of the key-value pairs in a `Map`, in their original order@@ -450,33 +638,33 @@ -} traverseWithKey :: Ord k => Applicative f => (k -> a -> f b) -> Map k a -> f (Map k b)-traverseWithKey f m =- fmap fromList (traverse f' (toList m))+traverseWithKey f (Map m Sorted) =+ fmap (\m' -> Map m' Sorted) (Data.Map.Strict.traverseWithKey f m)+traverseWithKey f m@(Map _ ks) =+ flip Map ks . Data.Map.Strict.fromList <$> traverse f' (toList m) where f' (k, a) = fmap ((,) k) (f k a) {-# INLINABLE traverseWithKey #-} -{-| Traverse all of the key-value pairs in a `Map`, in their original order- where the result of the computation can be forgotten.-->>> traverseWithKey_ (\k v -> print (k, v)) (fromList [("B",1),("A",2)])-("B",1)-("A",2)+{-| Same as `traverseWithKey`, except that the order of effects is not+ necessarily the same as the order of the keys -}-traverseWithKey_- :: Ord k => Applicative f => (k -> a -> f ()) -> Map k a -> f ()-traverseWithKey_ f m = Data.Functor.void (traverseWithKey f m)-{-# INLINABLE traverseWithKey_ #-}+unorderedTraverseWithKey+ :: Ord k => Applicative f => (k -> a -> f b) -> Map k a -> f (Map k b)+unorderedTraverseWithKey f (Map m ks) =+ fmap (\m' -> Map m' ks) (Data.Map.Strict.traverseWithKey f m)+{-# INLINABLE unorderedTraverseWithKey #-} -{-| Travese all of the key-value pairs in a 'Map', not preserving their+{-| Traverse all of the key-value pairs in a 'Map', not preserving their original order, where the result of the computation can be forgotten. - Note that this is an optimisation over 'traverseWithKey_' since we do- not care in what order we traverse the pairs.+ Note that this is a strict traversal, fully traversing the map even+ when the Applicative is lazy in the remaining elements. -} unorderedTraverseWithKey_ :: Ord k => Applicative f => (k -> a -> f ()) -> Map k a -> f ()-unorderedTraverseWithKey_ f = Data.Functor.void . traverse_ (uncurry f) . toList+unorderedTraverseWithKey_ f (Map m _) =+ Data.Map.Strict.foldlWithKey' (\acc k v -> acc *> f k v) (pure ()) m {-# INLINABLE unorderedTraverseWithKey_ #-} {-| Convert a `Map` to a list of key-value pairs in the original order of keys@@ -485,15 +673,22 @@ [("B",1),("A",2)] -} toList :: Ord k => Map k v -> [(k, v)]-toList (Map m ks) = fmap (\k -> (k, m Data.Map.! k)) ks+toList (Map m Sorted) = Data.Map.Strict.toList m+toList (Map m (Original ks)) = fmap (\k -> (k, m Data.Map.Strict.! k)) ks {-# INLINABLE toList #-} -{-| Convert a @"Dhall.Map".`Map`@ to a @"Data.Map".`Data.Map.Map`@+{-| Convert a `Map` to a list of key-value pairs in ascending order of keys+-}+toAscList :: Map k v -> [(k, v)]+toAscList (Map m _) = Data.Map.Strict.toAscList m+{-# INLINABLE toAscList #-} +{-| Convert a @"Dhall.Map".`Map`@ to a @"Data.Map.Strict".`Data.Map.Strict.Map`@+ >>> toMap (fromList [("B",1),("A",2)]) -- Order is lost upon conversion fromList [("A",2),("B",1)] -}-toMap :: Map k v -> Data.Map.Map k v+toMap :: Map k v -> Data.Map.Strict.Map k v toMap (Map m _) = m {-# INLINABLE toMap #-} @@ -503,5 +698,45 @@ ["B","A"] -} keys :: Map k v -> [k]-keys (Map _ ks) = ks+keys (Map m Sorted) = Data.Map.Strict.keys m+keys (Map _ (Original ks)) = ks {-# INLINABLE keys #-}++{-| Return the values from a `Map` in their original order.++>>> elems (fromList [("B",1),("A",2)])+[1,2]+-}+elems :: Ord k => Map k v -> [v]+elems (Map m Sorted) = Data.Map.Strict.elems m+elems (Map m (Original ks)) = fmap (\k -> m Data.Map.Strict.! k) ks+{-# INLINABLE elems #-}++{-| Return the @"Data.Set".'Data.Set.Set'@ of the keys++>>> keysSet (fromList [("B",1),("A",2)])+fromList ["A","B"]+-}+keysSet :: Map k v -> Data.Set.Set k+keysSet (Map m _) = Data.Map.Strict.keysSet m+{-# INLINABLE keysSet #-}++filterKeys :: (a -> Bool) -> Keys a -> Keys a+filterKeys _ Sorted = Sorted+filterKeys f (Original ks) = Original (Prelude.filter f ks)+{-# INLINABLE filterKeys #-}++partitionKeys :: (a -> Bool) -> Keys a -> (Keys a, Keys a)+partitionKeys _ Sorted = (Sorted, Sorted)+partitionKeys f (Original ks) =+ let (kpass, kfail) = Data.List.partition f ks+ in (Original kpass, Original kfail)+{-# INLINABLE partitionKeys #-}++{- $setup+>>> import Test.QuickCheck (Arbitrary(..), oneof)+>>> :{+ instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v) where+ arbitrary = oneof [fromList <$> arbitrary, unorderedFromList <$> arbitrary]+:}+-}
@@ -0,0 +1,1712 @@+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-}++{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining+ how to use the language, the compiler, and this library+-}++module Dhall.Marshal.Decode+ ( -- * General+ Decoder (..)+ , FromDhall(..)+ , Interpret+ , auto++ -- * Building decoders+ -- ** Simple decoders+ , bool+ , unit+ , void+ -- ** Numbers+ , natural+ , word+ , word8+ , word16+ , word32+ , word64+ , integer+ , int+ , int8+ , int16+ , int32+ , int64+ , scientific+ , double+ -- ** Bytes+ , lazyBytes+ , strictBytes+ , shortBytes+ -- ** Textual+ , string+ , lazyText+ , strictText+ , shortText+ -- ** Time+ , timeOfDay+ , day+ , timeZone+ , localTime+ , zonedTime+ , utcTime+ , dayOfWeek+ -- ** Containers+ , maybe+ , pair+ , sequence+ , list+ , vector+ , setFromDistinctList+ , setIgnoringDuplicates+ , hashSetFromDistinctList+ , hashSetIgnoringDuplicates+ , Dhall.Marshal.Decode.map+ , hashMap+ , pairFromMapEntry+ -- ** Functions+ , function+ , functionWith+ -- ** Records+ , RecordDecoder(..)+ , record+ , field+ -- ** Unions+ , UnionDecoder(..)+ , union+ , constructor++ -- * Generic decoding+ , GenericFromDhall(..)+ , GenericFromDhallUnion(..)+ , genericAuto+ , genericAutoWith+ , genericAutoWithInputNormalizer++ -- * Decoding errors+ , DhallErrors(..)+ , showDhallErrors+ , InvalidDecoder(..)+ -- ** Extraction errors+ , ExtractErrors+ , ExtractError(..)+ , Extractor+ , typeError+ , extractError+ , MonadicExtractor+ , toMonadic+ , fromMonadic+ -- ** Typing errors+ , ExpectedTypeErrors+ , ExpectedTypeError(..)+ , Expector++ -- * Miscellaneous+ , InputNormalizer(..)+ , defaultInputNormalizer+ , InterpretOptions(..)+ , SingletonConstructors(..)+ , defaultInterpretOptions+ , Result++ -- * Re-exports+ , Natural+ , Seq+ , Text+ , Vector+ , Generic+ ) where+++import Control.Applicative (empty, liftA2)+import Control.Exception (Exception)+import Control.Monad (guard)+import Control.Monad.Trans.State.Strict+import Data.Coerce (coerce)+import Data.Either.Validation+ ( Validation (..)+ , eitherToValidation+ , validationToEither+ )+import Data.Functor.Contravariant+ ( Equivalence (..)+ , Op (..)+ , Predicate (..)+ )+import Data.Functor.Identity (Identity (..))+import Data.Hashable (Hashable)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Typeable (Proxy (..), Typeable)+import Dhall.Parser (Src (..))+import Dhall.Syntax+ ( Chunks (..)+ , DhallDouble (..)+ , Expr (..)+ , FieldSelection (..)+ , FunctionBinding (..)+ , Var (..)+ )+import GHC.Generics+import Prelude hiding (maybe, sequence)+import Prettyprinter (Pretty)++import qualified Control.Applicative+import qualified Data.ByteString+import qualified Data.ByteString.Lazy+import qualified Data.ByteString.Short+import qualified Data.Foldable+import qualified Data.Functor.Compose+import qualified Data.Functor.Product+import qualified Data.HashMap.Strict as HashMap+import qualified Data.HashSet+import qualified Data.List as List+import qualified Data.List.NonEmpty+import qualified Data.Map+import qualified Data.Maybe+import qualified Data.Scientific+import qualified Data.Sequence+import qualified Data.Set+import qualified Data.Text+import qualified Data.Text.Lazy+import qualified Data.Text.Short+import qualified Data.Time as Time+import qualified Data.Vector+import qualified Dhall.Core as Core+import qualified Dhall.Map+import qualified Dhall.Util++import Dhall.Marshal.Encode+import Dhall.Marshal.Internal++-- $setup+-- >>> import Dhall (input)++{-| A @(Decoder a)@ represents a way to marshal a value of type @\'a\'@ from Dhall+ into Haskell.++ You can produce `Decoder`s either explicitly:++> example :: Decoder (Vector Text)+> example = vector text++ ... or implicitly using `auto`:++> example :: Decoder (Vector Text)+> example = auto++ You can consume `Decoder`s using the `Dhall.input` function:++> input :: Decoder a -> Text -> IO a+-}+data Decoder a = Decoder+ { extract :: Expr Src Void -> Extractor Src Void a+ -- ^ Extracts Haskell value from the Dhall expression+ , expected :: Expector (Expr Src Void)+ -- ^ Dhall type of the Haskell value+ }+ deriving (Functor)++{-| Any value that implements `FromDhall` can be automatically decoded based on+ the inferred return type of `Dhall.input`.++>>> input auto "[1, 2, 3]" :: IO (Vector Natural)+[1,2,3]+>>> input auto "toMap { a = False, b = True }" :: IO (Map Text Bool)+fromList [("a",False),("b",True)]++ This class auto-generates a default implementation for types that+ implement `Generic`. This does not auto-generate an instance for recursive+ types.++ The default instance can be tweaked using 'genericAutoWith'/'genericAutoWithInputNormalizer'+ and custom 'InterpretOptions', or using+ [DerivingVia](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-DerivingVia)+ and 'Dhall.Deriving.Codec' from "Dhall.Deriving".+-}+class FromDhall a where+ autoWith :: InputNormalizer -> Decoder a+ default autoWith+ :: (Generic a, GenericFromDhall a (Rep a)) => InputNormalizer -> Decoder a+ autoWith _ = genericAuto++-- | A compatibility alias for `FromDhall`.+type Interpret = FromDhall+{-# DEPRECATED Interpret "Use FromDhall instead" #-}++{-| Use the default input normalizer for interpreting an input.++> auto = autoWith defaultInputNormalizer+-}+auto :: FromDhall a => Decoder a+auto = autoWith defaultInputNormalizer++++instance FromDhall Void where+ autoWith _ = void++instance FromDhall () where+ autoWith _ = unit++instance FromDhall Bool where+ autoWith _ = bool++instance FromDhall Natural where+ autoWith _ = natural++instance FromDhall Word where+ autoWith _ = word++instance FromDhall Word8 where+ autoWith _ = word8++instance FromDhall Word16 where+ autoWith _ = word16++instance FromDhall Word32 where+ autoWith _ = word32++instance FromDhall Word64 where+ autoWith _ = word64++instance FromDhall Integer where+ autoWith _ = integer++instance FromDhall Int where+ autoWith _ = int++instance FromDhall Int8 where+ autoWith _ = int8++instance FromDhall Int16 where+ autoWith _ = int16++instance FromDhall Int32 where+ autoWith _ = int32++instance FromDhall Int64 where+ autoWith _ = int64++instance FromDhall Scientific where+ autoWith _ = scientific++instance FromDhall Double where+ autoWith _ = double++instance FromDhall Data.ByteString.Short.ShortByteString where+ autoWith _ = shortBytes++instance FromDhall Data.ByteString.Lazy.ByteString where+ autoWith _ = lazyBytes++instance FromDhall Data.ByteString.ByteString where+ autoWith _ = strictBytes++instance {-# OVERLAPS #-} FromDhall [Char] where+ autoWith _ = string++instance FromDhall Data.Text.Short.ShortText where+ autoWith _ = shortText++instance FromDhall Data.Text.Lazy.Text where+ autoWith _ = lazyText++instance FromDhall Text where+ autoWith _ = strictText++instance FromDhall a => FromDhall (Identity a) where+ autoWith opts = Identity <$> autoWith opts++instance FromDhall a => FromDhall (Maybe a) where+ autoWith opts = maybe (autoWith opts)++instance FromDhall a => FromDhall (Seq a) where+ autoWith opts = sequence (autoWith opts)++instance FromDhall a => FromDhall [a] where+ autoWith opts = list (autoWith opts)++instance FromDhall a => FromDhall (Vector a) where+ autoWith opts = vector (autoWith opts)++instance FromDhall Time.TimeOfDay where+ autoWith _ = timeOfDay++instance FromDhall Time.Day where+ autoWith _ = day++instance FromDhall Time.TimeZone where+ autoWith _ = timeZone++instance FromDhall Time.LocalTime where+ autoWith _ = localTime++instance FromDhall Time.ZonedTime where+ autoWith _ = zonedTime++instance FromDhall Time.UTCTime where+ autoWith _ = utcTime++instance FromDhall Time.DayOfWeek where+ autoWith _ = dayOfWeek++{-| Note that this instance will throw errors in the presence of duplicates in+ the list. To ignore duplicates, use `setIgnoringDuplicates`.+-}+instance (FromDhall a, Ord a, Show a) => FromDhall (Data.Set.Set a) where+ autoWith opts = setFromDistinctList (autoWith opts)++{-| Note that this instance will throw errors in the presence of duplicates in+ the list. To ignore duplicates, use `hashSetIgnoringDuplicates`.+-}+instance (FromDhall a, Hashable a, Ord a, Show a) => FromDhall (Data.HashSet.HashSet a) where+ autoWith inputNormalizer = hashSetFromDistinctList (autoWith inputNormalizer)++instance (Ord k, FromDhall k, FromDhall v) => FromDhall (Map k v) where+ autoWith inputNormalizer = Dhall.Marshal.Decode.map (autoWith inputNormalizer) (autoWith inputNormalizer)++instance (Eq k, Hashable k, FromDhall k, FromDhall v) => FromDhall (HashMap k v) where+ autoWith inputNormalizer = Dhall.Marshal.Decode.hashMap (autoWith inputNormalizer) (autoWith inputNormalizer)++instance (ToDhall a, FromDhall b) => FromDhall (a -> b) where+ autoWith inputNormalizer =+ functionWith inputNormalizer (injectWith inputNormalizer) (autoWith inputNormalizer)++instance (FromDhall a, FromDhall b) => FromDhall (a, b)++instance FromDhall (f (Result f)) => FromDhall (Result f) where+ autoWith inputNormalizer = Decoder {..}+ where+ extract (App _ expr) =+ fmap Result (Dhall.Marshal.Decode.extract (autoWith inputNormalizer) expr)+ extract expr = typeError expected expr++ expected = pure "result"++deriving newtype instance (ToDhall x) => FromDhall (Predicate x)++deriving newtype instance (ToDhall x) => FromDhall (Equivalence x)++deriving newtype instance (FromDhall b, ToDhall x) => FromDhall (Op b x)++-- | You can use this instance to marshal recursive types from Dhall to Haskell.+--+-- Here is an example use of this instance:+--+-- > {-# LANGUAGE DeriveAnyClass #-}+-- > {-# LANGUAGE DeriveFoldable #-}+-- > {-# LANGUAGE DeriveFunctor #-}+-- > {-# LANGUAGE DeriveTraversable #-}+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE KindSignatures #-}+-- > {-# LANGUAGE QuasiQuotes #-}+-- > {-# LANGUAGE StandaloneDeriving #-}+-- > {-# LANGUAGE TypeFamilies #-}+-- > {-# LANGUAGE TemplateHaskell #-}+-- >+-- > import Data.Fix (Fix(..))+-- > import Data.Text (Text)+-- > import Dhall (FromDhall)+-- > import GHC.Generics (Generic)+-- > import Numeric.Natural (Natural)+-- >+-- > import qualified Data.Fix as Fix+-- > import qualified Data.Functor.Foldable as Foldable+-- > import qualified Data.Functor.Foldable.TH as TH+-- > import qualified Dhall+-- > import qualified NeatInterpolation+-- >+-- > data Expr+-- > = Lit Natural+-- > | Add Expr Expr+-- > | Mul Expr Expr+-- > deriving (Show)+-- >+-- > TH.makeBaseFunctor ''Expr+-- >+-- > deriving instance Generic (ExprF a)+-- > deriving instance FromDhall a => FromDhall (ExprF a)+-- >+-- > example :: Text+-- > example = [NeatInterpolation.text|+-- > \(Expr : Type)+-- > -> let ExprF =+-- > < LitF :+-- > Natural+-- > | AddF :+-- > { _1 : Expr, _2 : Expr }+-- > | MulF :+-- > { _1 : Expr, _2 : Expr }+-- > >+-- >+-- > in \(Fix : ExprF -> Expr)+-- > -> let Lit = \(x : Natural) -> Fix (ExprF.LitF x)+-- >+-- > let Add =+-- > \(x : Expr)+-- > -> \(y : Expr)+-- > -> Fix (ExprF.AddF { _1 = x, _2 = y })+-- >+-- > let Mul =+-- > \(x : Expr)+-- > -> \(y : Expr)+-- > -> Fix (ExprF.MulF { _1 = x, _2 = y })+-- >+-- > in Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))+-- > |]+-- >+-- > convert :: Fix ExprF -> Expr+-- > convert = Fix.foldFix Foldable.embed+-- >+-- > main :: IO ()+-- > main = do+-- > x <- Dhall.input Dhall.auto example :: IO (Fix ExprF)+-- >+-- > print (convert x :: Expr)+instance (Functor f, FromDhall (f (Result f))) => FromDhall (Fix f) where+ autoWith inputNormalizer = Decoder {..}+ where+ extract expr0 = extract0 expr0+ where+ die = typeError expected expr0++ extract0 (Lam _ (FunctionBinding { functionBindingVariable = x }) expr) =+ extract1 (rename x "result" expr)+ extract0 _ = die++ extract1 (Lam _ (FunctionBinding { functionBindingVariable = y }) expr) =+ extract2 (rename y "Make" expr)+ extract1 _ = die++ extract2 expr = fmap resultToFix (Dhall.Marshal.Decode.extract (autoWith inputNormalizer) expr)++ rename a b expr+ | a /= b = Core.subst (V a 0) (Var (V b 0)) (Core.shift 1 (V b 0) expr)+ | otherwise = expr++ expected = (\x -> Pi mempty "result" (Const Core.Type) (Pi mempty "Make" (Pi mempty "_" x "result") "result"))+ <$> Dhall.Marshal.Decode.expected (autoWith inputNormalizer :: Decoder (f (Result f)))++resultToFix :: Functor f => Result f -> Fix f+resultToFix (Result x) = Fix (fmap resultToFix x)++++{-| This is the underlying class that powers the `FromDhall` class's support+ for automatically deriving a generic implementation.+-}+class GenericFromDhall t f where+ genericAutoWithNormalizer :: Proxy t -> InputNormalizer -> InterpretOptions -> State Int (Decoder (f a))++instance GenericFromDhall t f => GenericFromDhall t (M1 D d f) where+ genericAutoWithNormalizer p inputNormalizer options = do+ res <- genericAutoWithNormalizer p inputNormalizer options+ pure (fmap M1 res)++instance GenericFromDhall t V1 where+ genericAutoWithNormalizer _ _ _ = pure Decoder {..}+ where+ extract expr = typeError expected expr++ expected = pure $ Union mempty++instance GenericFromDhallUnion t (f :+: g) => GenericFromDhall t (f :+: g) where+ genericAutoWithNormalizer p inputNormalizer options =+ pure (union (genericUnionAutoWithNormalizer p inputNormalizer options))++instance GenericFromDhall t f => GenericFromDhall t (M1 C c f) where+ genericAutoWithNormalizer p inputNormalizer options = do+ res <- genericAutoWithNormalizer p inputNormalizer options+ pure (fmap M1 res)++instance GenericFromDhall t U1 where+ genericAutoWithNormalizer _ _ _ = pure (Decoder {..})+ where+ extract _ = pure U1++ expected = pure expected'++ expected' = Record (Dhall.Map.fromList [])++instance (GenericFromDhall t (f :*: g), GenericFromDhall t (h :*: i)) => GenericFromDhall t ((f :*: g) :*: (h :*: i)) where+ genericAutoWithNormalizer p inputNormalizer options = do+ Decoder extractL expectedL <- genericAutoWithNormalizer p inputNormalizer options+ Decoder extractR expectedR <- genericAutoWithNormalizer p inputNormalizer options++ let ktsL = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" <$> expectedL+ let ktsR = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" <$> expectedR++ let expected = Record <$> (Dhall.Map.union <$> ktsL <*> ktsR)++ let extract expression =+ liftA2 (:*:) (extractL expression) (extractR expression)++ return (Decoder {..})++instance (GenericFromDhall t (f :*: g), Selector s, FromDhall a) => GenericFromDhall t ((f :*: g) :*: M1 S s (K1 i a)) where+ genericAutoWithNormalizer p inputNormalizer options@InterpretOptions{..} = do+ let nR :: M1 S s (K1 i a) r+ nR = undefined++ nameR <- fmap fieldModifier (getSelName nR)++ Decoder extractL expectedL <- genericAutoWithNormalizer p inputNormalizer options++ let Decoder extractR expectedR = autoWith inputNormalizer++ let ktsL = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" <$> expectedL++ let expected = Record <$> (Dhall.Map.insert nameR . Core.makeRecordField <$> expectedR <*> ktsL)++ let extract expression = do+ let die = typeError expected expression++ case expression of+ RecordLit kvs ->+ case Core.recordFieldValue <$> Dhall.Map.lookup nameR kvs of+ Just expressionR ->+ liftA2 (:*:)+ (extractL expression)+ (fmap (M1 . K1) (extractR expressionR))+ _ -> die+ _ -> die++ return (Decoder {..})++instance (Selector s, FromDhall a, GenericFromDhall t (f :*: g)) => GenericFromDhall t (M1 S s (K1 i a) :*: (f :*: g)) where+ genericAutoWithNormalizer p inputNormalizer options@InterpretOptions{..} = do+ let nL :: M1 S s (K1 i a) r+ nL = undefined++ nameL <- fmap fieldModifier (getSelName nL)++ let Decoder extractL expectedL = autoWith inputNormalizer++ Decoder extractR expectedR <- genericAutoWithNormalizer p inputNormalizer options++ let ktsR = unsafeExpectRecord "genericAutoWithNormalizer (:*:)" <$> expectedR++ let expected = Record <$> (Dhall.Map.insert nameL . Core.makeRecordField <$> expectedL <*> ktsR)++ let extract expression = do+ let die = typeError expected expression++ case expression of+ RecordLit kvs ->+ case Core.recordFieldValue <$> Dhall.Map.lookup nameL kvs of+ Just expressionL ->+ liftA2 (:*:)+ (fmap (M1 . K1) (extractL expressionL))+ (extractR expression)+ _ -> die+ _ -> die++ return (Decoder {..})++instance {-# OVERLAPPING #-} GenericFromDhall a1 (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where+ genericAutoWithNormalizer _ _ _ = pure $ Decoder+ { extract = \_ -> Failure $ DhallErrors $ pure $ ExpectedTypeError RecursiveTypeError+ , expected = Failure $ DhallErrors $ pure RecursiveTypeError+ }++instance {-# OVERLAPPING #-} GenericFromDhall a2 (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where+ genericAutoWithNormalizer _ _ _ = pure $ Decoder+ { extract = \_ -> Failure $ DhallErrors $ pure $ ExpectedTypeError RecursiveTypeError+ , expected = Failure $ DhallErrors $ pure RecursiveTypeError+ }++instance {-# OVERLAPPABLE #-} (Selector s1, Selector s2, FromDhall a1, FromDhall a2) => GenericFromDhall t (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where+ genericAutoWithNormalizer _ inputNormalizer InterpretOptions{..} = do+ let nL :: M1 S s1 (K1 i1 a1) r+ nL = undefined++ let nR :: M1 S s2 (K1 i2 a2) r+ nR = undefined++ nameL <- fmap fieldModifier (getSelName nL)+ nameR <- fmap fieldModifier (getSelName nR)++ let Decoder extractL expectedL = autoWith inputNormalizer+ let Decoder extractR expectedR = autoWith inputNormalizer++ let expected = do+ l <- Core.makeRecordField <$> expectedL+ r <- Core.makeRecordField <$> expectedR+ pure $ Record+ (Dhall.Map.fromList+ [ (nameL, l)+ , (nameR, r)+ ]+ )++ let extract expression = do+ let die = typeError expected expression++ case expression of+ RecordLit kvs ->+ case liftA2 (,) (Dhall.Map.lookup nameL kvs) (Dhall.Map.lookup nameR kvs) of+ Just (expressionL, expressionR) ->+ liftA2 (:*:)+ (fmap (M1 . K1) (extractL $ Core.recordFieldValue expressionL))+ (fmap (M1 . K1) (extractR $ Core.recordFieldValue expressionR))+ Nothing -> die+ _ -> die++ return (Decoder {..})++instance {-# OVERLAPPING #-} GenericFromDhall a (M1 S s (K1 i a)) where+ genericAutoWithNormalizer _ _ _ = pure $ Decoder+ { extract = \_ -> Failure $ DhallErrors $ pure $ ExpectedTypeError RecursiveTypeError+ , expected = Failure $ DhallErrors $ pure RecursiveTypeError+ }++instance {-# OVERLAPPABLE #-} (Selector s, FromDhall a) => GenericFromDhall t (M1 S s (K1 i a)) where+ genericAutoWithNormalizer _ inputNormalizer InterpretOptions{..} = do+ let n :: M1 S s (K1 i a) r+ n = undefined++ name <- fmap fieldModifier (getSelName n)++ let Decoder { extract = extract', expected = expected'} = autoWith inputNormalizer++ let expected =+ case singletonConstructors of+ Bare ->+ expected'+ Smart | selName n == "" ->+ expected'+ _ ->+ Record . Dhall.Map.singleton name . Core.makeRecordField <$> expected'++ let extract0 expression = fmap (M1 . K1) (extract' expression)++ let extract1 expression = do+ let die = typeError expected expression++ case expression of+ RecordLit kvs ->+ case Core.recordFieldValue <$> Dhall.Map.lookup name kvs of+ Just subExpression ->+ fmap (M1 . K1) (extract' subExpression)+ Nothing ->+ die+ _ -> die++ let extract =+ case singletonConstructors of+ Bare -> extract0+ Smart | selName n == "" -> extract0+ _ -> extract1++ return (Decoder {..})++{-| `genericAuto` is the default implementation for `auto` if you derive+ `FromDhall`. The difference is that you can use `genericAuto` without+ having to explicitly provide a `FromDhall` instance for a type as long as+ the type derives `Generic`.+-}+genericAuto :: (Generic a, GenericFromDhall a (Rep a)) => Decoder a+genericAuto = genericAutoWith defaultInterpretOptions++{-| `genericAutoWith` is a configurable version of `genericAuto`.+-}+genericAutoWith :: (Generic a, GenericFromDhall a (Rep a)) => InterpretOptions -> Decoder a+genericAutoWith options = genericAutoWithInputNormalizer options defaultInputNormalizer++{-| `genericAutoWithInputNormalizer` is like `genericAutoWith`, but instead of+ using the `defaultInputNormalizer` it expects an custom `InputNormalizer`.+-}+genericAutoWithInputNormalizer :: (Generic a, GenericFromDhall a (Rep a)) => InterpretOptions -> InputNormalizer -> Decoder a+genericAutoWithInputNormalizer options inputNormalizer = withProxy (\p -> fmap to (evalState (genericAutoWithNormalizer p inputNormalizer options) 1))+ where+ withProxy :: (Proxy a -> Decoder a) -> Decoder a+ withProxy f = f Proxy++extractUnionConstructor+ :: Expr s a -> Maybe (Text, Expr s a, Dhall.Map.Map Text (Maybe (Expr s a)))+extractUnionConstructor (App (Field (Union kts) (Core.fieldSelectionLabel -> fld)) e) =+ return (fld, e, Dhall.Map.delete fld kts)+extractUnionConstructor (Field (Union kts) (Core.fieldSelectionLabel -> fld)) =+ return (fld, RecordLit mempty, Dhall.Map.delete fld kts)+extractUnionConstructor _ =+ empty++{-| This is the underlying class that powers the `FromDhall` class's support+ for automatically deriving a generic implementation for a union type.+-}+class GenericFromDhallUnion t f where+ genericUnionAutoWithNormalizer :: Proxy t -> InputNormalizer -> InterpretOptions -> UnionDecoder (f a)++instance (GenericFromDhallUnion t f1, GenericFromDhallUnion t f2) => GenericFromDhallUnion t (f1 :+: f2) where+ genericUnionAutoWithNormalizer p inputNormalizer options =+ (<>)+ (L1 <$> genericUnionAutoWithNormalizer p inputNormalizer options)+ (R1 <$> genericUnionAutoWithNormalizer p inputNormalizer options)++instance (Constructor c1, GenericFromDhall t f1) => GenericFromDhallUnion t (M1 C c1 f1) where+ genericUnionAutoWithNormalizer p inputNormalizer options@(InterpretOptions {..}) =+ constructor name (evalState (genericAutoWithNormalizer p inputNormalizer options) 1)+ where+ n :: M1 C c1 f1 a+ n = undefined++ name = constructorModifier (Data.Text.pack (conName n))++++{-| Decode a `Prelude.Bool`.++>>> input bool "True"+True+-}+bool :: Decoder Bool+bool = Decoder {..}+ where+ extract (BoolLit b) = pure b+ extract expr = typeError expected expr++ expected = pure Bool++{-| Decode a `Prelude.Natural`.++>>> input natural "42"+42+-}+natural :: Decoder Natural+natural = Decoder {..}+ where+ extract (NaturalLit n) = pure n+ extract expr = typeError expected expr++ expected = pure Natural++{-| Decode an `Prelude.Integer`.++>>> input integer "+42"+42+-}+integer :: Decoder Integer+integer = Decoder {..}+ where+ extract (IntegerLit n) = pure n+ extract expr = typeError expected expr++ expected = pure Integer++wordHelper :: forall a . (Bounded a, Integral a) => Text -> Decoder a+wordHelper name = Decoder {..}+ where+ extract (NaturalLit n)+ | toInteger n <= toInteger (maxBound @a) =+ pure (fromIntegral n)+ | otherwise =+ extractError ("Decoded " <> name <> " is out of bounds: " <> Data.Text.pack (show n))+ extract expr =+ typeError expected expr++ expected = pure Natural++{-| Decode a `Word` from a Dhall @Natural@.++>>> input word "42"+42+-}+word :: Decoder Word+word = wordHelper "Word"++{-| Decode a `Word8` from a Dhall @Natural@.++>>> input word8 "42"+42+-}+word8 :: Decoder Word8+word8 = wordHelper "Word8"++{-| Decode a `Word16` from a Dhall @Natural@.++>>> input word16 "42"+42+-}+word16 :: Decoder Word16+word16 = wordHelper "Word16"++{-| Decode a `Word32` from a Dhall @Natural@.++>>> input word32 "42"+42+-}+word32 :: Decoder Word32+word32 = wordHelper "Word32"++{-| Decode a `Word64` from a Dhall @Natural@.++>>> input word64 "42"+42+-}+word64 :: Decoder Word64+word64 = wordHelper "Word64"++intHelper :: forall a . (Bounded a, Integral a) => Text -> Decoder a+intHelper name = Decoder {..}+ where+ extract (IntegerLit n)+ | toInteger (minBound @a) <= n && n <= toInteger (maxBound @a) =+ pure (fromIntegral n)+ | otherwise =+ extractError ("Decoded " <> name <> " is out of bounds: " <> Data.Text.pack (show n))+ extract expr =+ typeError expected expr++ expected = pure Integer++{-| Decode an `Int` from a Dhall @Integer@.++>>> input int "-42"+-42+-}+int :: Decoder Int+int = intHelper "Int"++{-| Decode an `Int8` from a Dhall @Integer@.++>>> input int8 "-42"+-42+-}+int8 :: Decoder Int8+int8 = intHelper "Int8"++{-| Decode an `Int16` from a Dhall @Integer@.++>>> input int16 "-42"+-42+-}+int16 :: Decoder Int16+int16 = intHelper "Int16"++{-| Decode an `Int32` from a Dhall @Integer@.++>>> input int32 "-42"+-42+-}+int32 :: Decoder Int32+int32 = intHelper "Int32"++{-| Decode an `Int64` from a Dhall @Integer@.++>>> input int64 "-42"+-42+-}+int64 :: Decoder Int64+int64 = intHelper "Int64"++{-| Decode a `Scientific`.++>>> input scientific "1e100"+1.0e100+-}+scientific :: Decoder Scientific+scientific = fmap Data.Scientific.fromFloatDigits double++{-| Decode a `Prelude.Double`.++>>> input double "42.0"+42.0+-}+double :: Decoder Double+double = Decoder {..}+ where+ extract (DoubleLit (DhallDouble n)) = pure n+ extract expr = typeError expected expr++ expected = pure Double++{-| Decode a `Data.ByteString.Short.ShortByteString`++>>> input shortBytes "0x\"00FF\""+"\NUL\255"+-}+shortBytes :: Decoder Data.ByteString.Short.ShortByteString+shortBytes = fmap Data.ByteString.Short.toShort strictBytes++{-| Decode a lazy `Data.ByteString.Lazy.ByteString`.++>>> input lazyBytes "0x\"00FF\""+"\NUL\255"+-}+lazyBytes :: Decoder Data.ByteString.Lazy.ByteString+lazyBytes = fmap Data.ByteString.Lazy.fromStrict strictBytes++{-| Decode a strict `Data.ByteString.ByteString`++>>> input strictBytes "0x\"00FF\""+"\NUL\255"+-}+strictBytes :: Decoder Data.ByteString.ByteString+strictBytes = Decoder {..}+ where+ extract (BytesLit b) = pure b+ extract expr = typeError expected expr++ expected = pure Bytes++{-| Decode `Data.Text.Short.ShortText`.++>>> input shortText "\"Test\""+"Test"+-}+shortText :: Decoder Data.Text.Short.ShortText+shortText = fmap Data.Text.Short.fromText strictText++{-| Decode lazy `Data.Text.Lazy.Text`.++>>> input lazyText "\"Test\""+"Test"+-}+lazyText :: Decoder Data.Text.Lazy.Text+lazyText = fmap Data.Text.Lazy.fromStrict strictText++{-| Decode strict `Data.Text.Text`.++>>> input strictText "\"Test\""+"Test"+-}+strictText :: Decoder Text+strictText = Decoder {..}+ where+ extract (TextLit (Chunks [] t)) = pure t+ extract expr = typeError expected expr++ expected = pure Text++{-| Decode `Time.TimeOfDay`++>>> input timeOfDay "00:00:00"+00:00:00+-}+timeOfDay :: Decoder Time.TimeOfDay+timeOfDay = Decoder {..}+ where+ extract (TimeLiteral t _) = pure t+ extract expr = typeError expected expr++ expected = pure Time++{-| Decode `Time.Day`++>>> input day "2000-01-01"+2000-01-01+-}+day :: Decoder Time.Day+day = Decoder {..}+ where+ extract (DateLiteral d) = pure d+ extract expr = typeError expected expr++ expected = pure Date++{-| Decode `Time.TimeZone`++>>> input timeZone "+00:00"++0000+-}+timeZone :: Decoder Time.TimeZone+timeZone = Decoder {..}+ where+ extract (TimeZoneLiteral z) = pure z+ extract expr = typeError expected expr++ expected = pure TimeZone++{-| Decode `Time.LocalTime`++>>> input localTime "2020-01-01T12:34:56"+2020-01-01 12:34:56+-}+localTime :: Decoder Time.LocalTime+localTime = record $+ Time.LocalTime+ <$> field "date" day+ <*> field "time" timeOfDay++{-| Decode `Time.ZonedTime`++>>> input zonedTime "2020-01-01T12:34:56+02:00"+2020-01-01 12:34:56 +0200+-}+zonedTime :: Decoder Time.ZonedTime+zonedTime = record $+ adapt+ <$> field "date" day+ <*> field "time" timeOfDay+ <*> field "timeZone" timeZone+ where+ adapt date time = Time.ZonedTime (Time.LocalTime date time)++{-| Decode `Time.UTCTime`++>>> input utcTime "2020-01-01T12:34:56+02:00"+2020-01-01 10:34:56 UTC+-}+utcTime :: Decoder Time.UTCTime+utcTime = Time.zonedTimeToUTC <$> zonedTime++{-| Decode `Time.DayOfWeek`++>>> input dayOfWeek "< Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday >.Monday"+Monday+-}+dayOfWeek :: Decoder Time.DayOfWeek+dayOfWeek = Decoder{..}+ where+ extract expr@(Field _ FieldSelection{ fieldSelectionLabel }) =+ case fieldSelectionLabel of+ "Sunday" -> pure Time.Sunday+ "Monday" -> pure Time.Monday+ "Tuesday" -> pure Time.Tuesday+ "Wednesday" -> pure Time.Wednesday+ "Thursday" -> pure Time.Thursday+ "Friday" -> pure Time.Friday+ "Saturday" -> pure Time.Saturday+ _ -> typeError expected expr+ extract expr =+ typeError expected expr++ expected =+ pure+ (Union+ (Dhall.Map.fromList+ [ ("Sunday", Nothing)+ , ("Monday", Nothing)+ , ("Tuesday", Nothing)+ , ("Wednesday", Nothing)+ , ("Thursday", Nothing)+ , ("Friday", Nothing)+ , ("Saturday", Nothing)+ ]+ )+ )++{-| Decode a `Maybe`.++>>> input (maybe natural) "Some 1"+Just 1+-}+maybe :: Decoder a -> Decoder (Maybe a)+maybe (Decoder extractIn expectedIn) = Decoder extractOut expectedOut+ where+ extractOut (Some e ) = fmap Just (extractIn e)+ extractOut (App None _) = pure Nothing+ extractOut expr = typeError expectedOut expr++ expectedOut = App Optional <$> expectedIn++{-| Decode a `Seq`.++>>> input (sequence natural) "[1, 2, 3]"+fromList [1,2,3]+-}+sequence :: Decoder a -> Decoder (Seq a)+sequence (Decoder extractIn expectedIn) = Decoder extractOut expectedOut+ where+ extractOut (ListLit _ es) = traverse extractIn es+ extractOut expr = typeError expectedOut expr++ expectedOut = App List <$> expectedIn++{-| Decode a list.++>>> input (list natural) "[1, 2, 3]"+[1,2,3]+-}+list :: Decoder a -> Decoder [a]+list = fmap Data.Foldable.toList . sequence++{-| Decode a `Vector`.++>>> input (vector natural) "[1, 2, 3]"+[1,2,3]+-}+vector :: Decoder a -> Decoder (Vector a)+vector = fmap Data.Vector.fromList . list++{-| Decode a Dhall function into a Haskell function.++>>> f <- input (function inject bool) "Natural/even" :: IO (Natural -> Bool)+>>> f 0+True+>>> f 1+False+-}+function+ :: Encoder a+ -> Decoder b+ -> Decoder (a -> b)+function = functionWith defaultInputNormalizer++{-| Decode a Dhall function into a Haskell function using the specified normalizer.++>>> f <- input (functionWith defaultInputNormalizer inject bool) "Natural/even" :: IO (Natural -> Bool)+>>> f 0+True+>>> f 1+False+-}+functionWith+ :: InputNormalizer+ -> Encoder a+ -> Decoder b+ -> Decoder (a -> b)+functionWith inputNormalizer (Encoder {..}) (Decoder extractIn expectedIn) =+ Decoder extractOut expectedOut+ where+ normalizer_ = Just (getInputNormalizer inputNormalizer)++ extractOut e = pure (\i -> case extractIn (Core.normalizeWith normalizer_ (App e (embed i))) of+ Success o -> o+ Failure _e -> error "FromDhall: You cannot decode a function if it does not have the correct type" )++ expectedOut = Pi mempty "_" declared <$> expectedIn++{-| Decode a `Data.Set.Set` from a `List`.++>>> input (setIgnoringDuplicates natural) "[1, 2, 3]"+fromList [1,2,3]++Duplicate elements are ignored.++>>> input (setIgnoringDuplicates natural) "[1, 1, 3]"+fromList [1,3]++-}+setIgnoringDuplicates :: (Ord a) => Decoder a -> Decoder (Data.Set.Set a)+setIgnoringDuplicates = fmap Data.Set.fromList . list++{-| Decode a `Data.HashSet.HashSet` from a `List`.++>>> input (hashSetIgnoringDuplicates natural) "[1, 2, 3]"+fromList [1,2,3]++Duplicate elements are ignored.++>>> input (hashSetIgnoringDuplicates natural) "[1, 1, 3]"+fromList [1,3]++-}+hashSetIgnoringDuplicates :: (Hashable a, Ord a)+ => Decoder a+ -> Decoder (Data.HashSet.HashSet a)+hashSetIgnoringDuplicates = fmap Data.HashSet.fromList . list++{-| Decode a `Data.Set.Set` from a `List` with distinct elements.++>>> input (setFromDistinctList natural) "[1, 2, 3]"+fromList [1,2,3]++An error is thrown if the list contains duplicates.++> >>> input (setFromDistinctList natural) "[1, 1, 3]"+> *** Exception: Error: Failed extraction+>+> The expression type-checked successfully but the transformation to the target+> type failed with the following error:+>+> One duplicate element in the list: 1+>++> >>> input (setFromDistinctList natural) "[1, 1, 3, 3]"+> *** Exception: Error: Failed extraction+>+> The expression type-checked successfully but the transformation to the target+> type failed with the following error:+>+> 2 duplicates were found in the list, including 1+>++-}+setFromDistinctList :: (Ord a, Show a) => Decoder a -> Decoder (Data.Set.Set a)+setFromDistinctList = setHelper Data.Set.size Data.Set.fromList++{-| Decode a `Data.HashSet.HashSet` from a `List` with distinct elements.++>>> input (hashSetFromDistinctList natural) "[1, 2, 3]"+fromList [1,2,3]++An error is thrown if the list contains duplicates.++> >>> input (hashSetFromDistinctList natural) "[1, 1, 3]"+> *** Exception: Error: Failed extraction+>+> The expression type-checked successfully but the transformation to the target+> type failed with the following error:+>+> One duplicate element in the list: 1+>++> >>> input (hashSetFromDistinctList natural) "[1, 1, 3, 3]"+> *** Exception: Error: Failed extraction+>+> The expression type-checked successfully but the transformation to the target+> type failed with the following error:+>+> 2 duplicates were found in the list, including 1+>++-}+hashSetFromDistinctList :: (Hashable a, Ord a, Show a)+ => Decoder a+ -> Decoder (Data.HashSet.HashSet a)+hashSetFromDistinctList = setHelper Data.HashSet.size Data.HashSet.fromList+++setHelper :: (Eq a, Foldable t, Show a)+ => (t a -> Int)+ -> ([a] -> t a)+ -> Decoder a+ -> Decoder (t a)+setHelper size toSet (Decoder extractIn expectedIn) = Decoder extractOut expectedOut+ where+ extractOut (ListLit _ es) = case traverse extractIn es of+ Success vSeq+ | sameSize -> Success vSet+ | otherwise -> extractError err+ where+ vList = Data.Foldable.toList vSeq+ vSet = toSet vList+ sameSize = size vSet == Data.Sequence.length vSeq+ duplicates = vList List.\\ Data.Foldable.toList vSet+ err | length duplicates == 1 =+ "One duplicate element in the list: "+ <> (Data.Text.pack $ show $ head duplicates)+ | otherwise = Data.Text.pack $ unwords+ [ show $ length duplicates+ , "duplicates were found in the list, including"+ , show $ head duplicates+ ]+ Failure f -> Failure f+ extractOut expr = typeError expectedOut expr++ expectedOut = App List <$> expectedIn++{-| Decode a `Map` from a @toMap@ expression or generally a @Prelude.Map.Type@.++>>> input (Dhall.map strictText bool) "toMap { a = True, b = False }"+fromList [("a",True),("b",False)]+>>> input (Dhall.map strictText bool) "[ { mapKey = \"foo\", mapValue = True } ]"+fromList [("foo",True)]++If there are duplicate @mapKey@s, later @mapValue@s take precedence:++>>> let expr = "[ { mapKey = 1, mapValue = True }, { mapKey = 1, mapValue = False } ]"+>>> input (Dhall.map natural bool) expr+fromList [(1,False)]++-}+map :: Ord k => Decoder k -> Decoder v -> Decoder (Map k v)+map k v = fmap Data.Map.fromList (list (pairFromMapEntry k v))++{-| Decode a `HashMap` from a @toMap@ expression or generally a @Prelude.Map.Type@.++>>> fmap (List.sort . HashMap.toList) (input (Dhall.hashMap strictText bool) "toMap { a = True, b = False }")+[("a",True),("b",False)]+>>> fmap (List.sort . HashMap.toList) (input (Dhall.hashMap strictText bool) "[ { mapKey = \"foo\", mapValue = True } ]")+[("foo",True)]++If there are duplicate @mapKey@s, later @mapValue@s take precedence:++>>> let expr = "[ { mapKey = 1, mapValue = True }, { mapKey = 1, mapValue = False } ]"+>>> input (Dhall.hashMap natural bool) expr+fromList [(1,False)]++-}+hashMap :: (Eq k, Hashable k) => Decoder k -> Decoder v -> Decoder (HashMap k v)+hashMap k v = fmap HashMap.fromList (list (pairFromMapEntry k v))++{-| Decode a tuple from a @Prelude.Map.Entry@ record.++>>> input (pairFromMapEntry strictText natural) "{ mapKey = \"foo\", mapValue = 3 }"+("foo",3)+-}+pairFromMapEntry :: Decoder k -> Decoder v -> Decoder (k, v)+pairFromMapEntry k v = Decoder extractOut expectedOut+ where+ extractOut (RecordLit kvs)+ | Just key <- Core.recordFieldValue <$> Dhall.Map.lookup "mapKey" kvs+ , Just value <- Core.recordFieldValue <$> Dhall.Map.lookup "mapValue" kvs+ = liftA2 (,) (extract k key) (extract v value)+ extractOut expr = typeError expectedOut expr++ expectedOut = do+ k' <- Core.makeRecordField <$> expected k+ v' <- Core.makeRecordField <$> expected v+ pure $ Record $ Dhall.Map.fromList+ [ ("mapKey", k')+ , ("mapValue", v')]++{-| Decode @()@ from an empty record.++>>> input unit "{=}" -- GHC doesn't print the result if it is ()++-}+unit :: Decoder ()+unit = Decoder {..}+ where+ extract (RecordLit fields)+ | Data.Foldable.null fields = pure ()+ extract expr = typeError expected expr++ expected = pure $ Record mempty++{-| Decode 'Void' from an empty union.++Since @<>@ is uninhabited, @'Dhall.input' 'void'@ will always fail.+-}+void :: Decoder Void+void = union mempty++{-| Decode a `String`++>>> input string "\"ABC\""+"ABC"++-}+string :: Decoder String+string = Data.Text.Lazy.unpack <$> lazyText++{-| Given a pair of `Decoder`s, decode a tuple-record into their pairing.++>>> input (pair natural bool) "{ _1 = 42, _2 = False }"+(42,False)+-}+pair :: Decoder a -> Decoder b -> Decoder (a, b)+pair l r = Decoder extractOut expectedOut+ where+ extractOut expr@(RecordLit fields) =+ (,) <$> Data.Maybe.maybe (typeError expectedOut expr) (extract l)+ (Core.recordFieldValue <$> Dhall.Map.lookup "_1" fields)+ <*> Data.Maybe.maybe (typeError expectedOut expr) (extract r)+ (Core.recordFieldValue <$> Dhall.Map.lookup "_2" fields)+ extractOut expr = typeError expectedOut expr++ expectedOut = do+ l' <- Core.makeRecordField <$> expected l+ r' <- Core.makeRecordField <$> expected r+ pure $ Record $ Dhall.Map.fromList+ [ ("_1", l')+ , ("_2", r')]++++{-| The 'RecordDecoder' applicative functor allows you to build a 'Decoder'+ from a Dhall record.++ For example, let's take the following Haskell data type:++>>> :{+data Project = Project+ { projectName :: Text+ , projectDescription :: Text+ , projectStars :: Natural+ }+:}++ And assume that we have the following Dhall record that we would like to+ parse as a @Project@:++> { name =+> "dhall-haskell"+> , description =+> "A configuration language guaranteed to terminate"+> , stars =+> 289+> }++ Our decoder has type 'Decoder' @Project@, but we can't build that out of any+ smaller decoders, as 'Decoder's cannot be combined (they are only 'Functor's).+ However, we can use a 'RecordDecoder' to build a 'Decoder' for @Project@:++>>> :{+project :: Decoder Project+project =+ record+ ( Project <$> field "name" strictText+ <*> field "description" strictText+ <*> field "stars" natural+ )+:}+-}+newtype RecordDecoder a =+ RecordDecoder+ ( Data.Functor.Product.Product+ ( Control.Applicative.Const+ (Dhall.Map.Map Text (Expector (Expr Src Void)))+ )+ ( Data.Functor.Compose.Compose ((->) (Expr Src Void)) (Extractor Src Void)+ )+ a+ )+ deriving (Functor, Applicative)++-- | Run a 'RecordDecoder' to build a 'Decoder'.+record :: RecordDecoder a -> Dhall.Marshal.Decode.Decoder a+record+ (RecordDecoder+ (Data.Functor.Product.Pair+ (Control.Applicative.Const fields)+ (Data.Functor.Compose.Compose extract)+ )+ ) = Decoder {..}+ where+ expected = Record <$> traverse (fmap Core.makeRecordField) fields++-- | Parse a single field of a record.+field :: Text -> Decoder a -> RecordDecoder a+field key (Decoder {..}) =+ RecordDecoder+ ( Data.Functor.Product.Pair+ ( Control.Applicative.Const+ (Dhall.Map.singleton key expected)+ )+ ( Data.Functor.Compose.Compose extractBody )+ )+ where+ extractBody expr@(RecordLit fields) = case Core.recordFieldValue <$> Dhall.Map.lookup key fields of+ Just v -> extract v+ _ -> typeError expected expr+ extractBody expr = typeError expected expr++++{-| The 'UnionDecoder' monoid allows you to build a 'Decoder' from a Dhall union.++ For example, let's take the following Haskell data type:++>>> :{+data Status = Queued Natural+ | Result Text+ | Errored Text+:}++ And assume that we have the following Dhall union that we would like to+ parse as a @Status@:++> < Result : Text+> | Queued : Natural+> | Errored : Text+> >.Result "Finish successfully"++ Our decoder has type 'Decoder' @Status@, but we can't build that out of any+ smaller decoders, as 'Decoder's cannot be combined (they are only 'Functor's).+ However, we can use a 'UnionDecoder' to build a 'Decoder' for @Status@:++>>> :{+status :: Decoder Status+status = union+ ( ( Queued <$> constructor "Queued" natural )+ <> ( Result <$> constructor "Result" strictText )+ <> ( Errored <$> constructor "Errored" strictText )+ )+:}++-}+newtype UnionDecoder a =+ UnionDecoder+ ( Data.Functor.Compose.Compose (Dhall.Map.Map Text) Decoder a )+ deriving (Functor)++instance Semigroup (UnionDecoder a) where+ (<>) = coerce ((<>) :: Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a) -> Dhall.Map.Map Text (Decoder a))++instance Monoid (UnionDecoder a) where+ mempty = coerce (mempty :: Dhall.Map.Map Text (Decoder a))++-- | Run a 'UnionDecoder' to build a 'Decoder'.+union :: UnionDecoder a -> Decoder a+union (UnionDecoder (Data.Functor.Compose.Compose mp)) = Decoder {..}+ where+ extract expr = case expected' of+ Failure e -> Failure $ fmap ExpectedTypeError e+ Success x -> extract' expr x++ extract' e0 mp' = Data.Maybe.maybe (typeError expected e0) (uncurry Dhall.Marshal.Decode.extract) $ do+ (fld, e1, rest) <- extractUnionConstructor e0++ t <- Dhall.Map.lookup fld mp++ guard $+ Core.Union rest `Core.judgmentallyEqual` Core.Union (Dhall.Map.delete fld mp')++ pure (t, e1)++ expected = Union <$> expected'++ expected' = traverse (fmap notEmptyRecord . Dhall.Marshal.Decode.expected) mp++-- | Parse a single constructor of a union.+constructor :: Text -> Decoder a -> UnionDecoder a+constructor key valueDecoder = UnionDecoder+ ( Data.Functor.Compose.Compose (Dhall.Map.singleton key valueDecoder) )++++{-| A newtype suitable for collecting one or more errors.+-}+newtype DhallErrors e = DhallErrors+ { getErrors :: NonEmpty e+ } deriving (Eq, Functor, Semigroup)++instance (Show (DhallErrors e), Typeable e) => Exception (DhallErrors e)++{-| Render a given prefix and some errors to a string.+-}+showDhallErrors :: Show e => String -> DhallErrors e -> String+showDhallErrors _ (DhallErrors (e :| [])) = show e+showDhallErrors ctx (DhallErrors es) = prefix <> (unlines . Data.List.NonEmpty.toList . fmap show $ es)+ where+ prefix =+ "Multiple errors were encountered" ++ ctx ++ ": \n\+ \ \n"++{-| One or more errors returned from extracting a Dhall expression to a+ Haskell expression.+-}+type ExtractErrors s a = DhallErrors (ExtractError s a)++instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractErrors s a) where+ show = showDhallErrors " during extraction"++{-| Extraction of a value can fail for two reasons, either a type mismatch (which should not happen,+ as expressions are type-checked against the expected type before being passed to @extract@), or+ a term-level error, described with a freeform text value.+-}+data ExtractError s a =+ TypeMismatch (InvalidDecoder s a)+ | ExpectedTypeError ExpectedTypeError+ | ExtractError Text+ deriving (Eq)++instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (ExtractError s a) where+ show (TypeMismatch e) = show e+ show (ExpectedTypeError e) = show e+ show (ExtractError es) = unlines+ [ _ERROR <> ": Failed extraction "+ , " "+ , "The expression type-checked successfully but the transformation to the target "+ , "type failed with the following error: "+ , " "+ , Data.Text.unpack es+ , " "+ ]++instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (ExtractError s a)++{-| Useful synonym for the `Validation` type used when marshalling Dhall+ expressions.+-}+type Extractor s a = Validation (ExtractErrors s a)++{-| Generate a type error during extraction by specifying the expected type+ and the actual type.+ The expected type is not yet determined.+-}+typeError :: Expector (Expr s a) -> Expr s a -> Extractor s a b+typeError expected actual = Failure $ case expected of+ Failure e -> fmap ExpectedTypeError e+ Success expected' -> DhallErrors $ pure $ TypeMismatch $ InvalidDecoder expected' actual++-- | Turn a `Data.Text.Text` message into an extraction failure.+extractError :: Text -> Extractor s a b+extractError = Failure . DhallErrors . pure . ExtractError++{-| Useful synonym for the equivalent `Either` type used when marshalling Dhall+ code.+-}+type MonadicExtractor s a = Either (ExtractErrors s a)++-- | Switches from an @Applicative@ extraction result, able to accumulate errors,+-- to a @Monad@ extraction result, able to chain sequential operations.+toMonadic :: Extractor s a b -> MonadicExtractor s a b+toMonadic = validationToEither++-- | Switches from a @Monad@ extraction result, able to chain sequential errors,+-- to an @Applicative@ extraction result, able to accumulate errors.+fromMonadic :: MonadicExtractor s a b -> Extractor s a b+fromMonadic = eitherToValidation++{-| Every `Decoder` must obey the contract that if an expression's type matches+ the `expected` type then the `extract` function must not fail with a type+ error. However, decoding may still fail for other reasons (such as the+ decoder for `Data.Map.Set`s rejecting a Dhall @List@ with duplicate+ elements).++ This error type is used to indicate an internal error in the implementation+ of a `Decoder` where the expected type matched the Dhall expression, but the+ expression supplied to the extraction function did not match the expected+ type. If this happens that means that the `Decoder` itself needs to be+ fixed.+-}+data InvalidDecoder s a = InvalidDecoder+ { invalidDecoderExpected :: Expr s a+ , invalidDecoderExpression :: Expr s a+ }+ deriving (Eq, Typeable)++instance (Pretty s, Typeable s, Pretty a, Typeable a) => Exception (InvalidDecoder s a)++instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (InvalidDecoder s a) where+ show InvalidDecoder { .. } = unlines+ [ _ERROR <> ": Invalid Dhall.Decoder "+ , " "+ , "Every Decoder must provide an extract function that does not fail with a type "+ , "error if an expression matches the expected type. You provided a Decoder that "+ , "disobeys this contract "+ , " "+ , "The Decoder provided has the expected dhall type: "+ , " "+ , show (Dhall.Util.insert invalidDecoderExpected)+ , " "+ , "and it threw a type error during extraction from the well-typed expression: "+ , " "+ , show (Dhall.Util.insert invalidDecoderExpression)+ , " "+ ]++{-| Useful synonym for the `Validation` type used when marshalling Dhall+ expressions.+-}+type Expector = Validation ExpectedTypeErrors++{-| One or more errors returned when determining the Dhall type of a+ Haskell expression.+-}+type ExpectedTypeErrors = DhallErrors ExpectedTypeError++{-| Error type used when determining the Dhall type of a Haskell expression.+-}+data ExpectedTypeError = RecursiveTypeError+ deriving (Eq, Show)++instance Exception ExpectedTypeError++instance Show ExpectedTypeErrors where+ show = showDhallErrors " while determining the expected type"++_ERROR :: String+_ERROR = "\ESC[1;31mError\ESC[0m"
@@ -0,0 +1,1068 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining+ how to use the language, the compiler, and this library+-}++module Dhall.Marshal.Encode+ ( -- * General+ Encoder(..)+ , ToDhall(..)+ , Inject+ , inject++ -- * Building encoders++ -- ** Records+ , RecordEncoder(..)+ , recordEncoder+ , encodeField+ , encodeFieldWith+ -- ** Unions+ , UnionEncoder(..)+ , unionEncoder+ , encodeConstructor+ , encodeConstructorWith+ , (>|<)++ -- * Generic encoding+ , GenericToDhall(..)+ , genericToDhall+ , genericToDhallWith+ , genericToDhallWithInputNormalizer+ , InterpretOptions(..)+ , SingletonConstructors(..)+ , defaultInterpretOptions++ -- * Miscellaneous+ , InputNormalizer(..)+ , defaultInputNormalizer+ , Result+ , (>$<)+ , (>*<)++ -- * Re-exports+ , Natural+ , Seq+ , Text+ , Vector+ , Generic+ ) where++import Control.Monad.Trans.State.Strict+import Data.Functor.Contravariant (Contravariant (..), Op (..), (>$<))+import Data.Functor.Contravariant.Divisible (Divisible (..), divided)+import Dhall.Parser (Src (..))+import Dhall.Syntax+ ( Chunks (..)+ , DhallDouble (..)+ , Expr (..)+ )+import GHC.Generics+import Prelude hiding (maybe, sequence)++import qualified Control.Applicative+import qualified Data.ByteString+import qualified Data.ByteString.Lazy+import qualified Data.ByteString.Short+import qualified Data.Functor.Product+import qualified Data.HashMap.Strict as HashMap+import qualified Data.HashSet+import qualified Data.Map+import qualified Data.Scientific+import qualified Data.Sequence+import qualified Data.Set+import qualified Data.Text+import qualified Data.Text.Lazy+import qualified Data.Text.Short+import qualified Data.Time as Time+import qualified Data.Vector+import qualified Data.Void+import qualified Dhall.Core as Core+import qualified Dhall.Map++import Dhall.Marshal.Internal++-- $setup+-- >>> :set -XRecordWildCards+-- >>> import Dhall.Pretty.Internal (prettyExpr)++{-| An @(Encoder a)@ represents a way to marshal a value of type @\'a\'@ from+ Haskell into Dhall.+-}+data Encoder a = Encoder+ { embed :: a -> Expr Src Void+ -- ^ Embeds a Haskell value as a Dhall expression+ , declared :: Expr Src Void+ -- ^ Dhall type of the Haskell value+ }++instance Contravariant Encoder where+ contramap f (Encoder embed declared) = Encoder embed' declared+ where+ embed' x = embed (f x)++{-| This class is used by `Dhall.Marshal.Decode.FromDhall` instance for functions:++> instance (ToDhall a, FromDhall b) => FromDhall (a -> b)++ You can convert Dhall functions with "simple" inputs (i.e. instances of this+ class) into Haskell functions. This works by:++ * Marshaling the input to the Haskell function into a Dhall expression (i.e.+ @x :: Expr Src Void@)+ * Applying the Dhall function (i.e. @f :: Expr Src Void@) to the Dhall input+ (i.e. @App f x@)+ * Normalizing the syntax tree (i.e. @normalize (App f x)@)+ * Marshaling the resulting Dhall expression back into a Haskell value++ This class auto-generates a default implementation for types that+ implement `Generic`. This does not auto-generate an instance for recursive+ types.++ The default instance can be tweaked using 'genericToDhallWith'/'genericToDhallWithInputNormalizer'+ and custom 'InterpretOptions', or using+ [DerivingVia](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-DerivingVia)+ and 'Dhall.Deriving.Codec' from "Dhall.Deriving".+-}+class ToDhall a where+ injectWith :: InputNormalizer -> Encoder a+ default injectWith+ :: (Generic a, GenericToDhall (Rep a)) => InputNormalizer -> Encoder a+ injectWith _ = genericToDhall++-- | A compatibility alias for `ToDhall`+type Inject = ToDhall+{-# DEPRECATED Inject "Use ToDhall instead" #-}++{-| Use the default input normalizer for injecting a value.++> inject = injectWith defaultInputNormalizer+-}+inject :: ToDhall a => Encoder a+inject = injectWith defaultInputNormalizer++++instance ToDhall Void where+ injectWith _ = Encoder {..}+ where+ embed = Data.Void.absurd++ declared = Union mempty++instance ToDhall Bool where+ injectWith _ = Encoder {..}+ where+ embed = BoolLit++ declared = Bool++instance ToDhall Data.ByteString.Short.ShortByteString where+ injectWith options =+ contramap Data.ByteString.Short.fromShort (injectWith options)++instance ToDhall Data.ByteString.Lazy.ByteString where+ injectWith options =+ contramap Data.ByteString.Lazy.toStrict (injectWith options)++instance ToDhall Data.ByteString.ByteString where+ injectWith _ = Encoder {..}+ where+ embed bytes = BytesLit bytes++ declared = Bytes++instance ToDhall Data.Text.Short.ShortText where+ injectWith _ = Encoder {..}+ where+ embed text =+ TextLit (Chunks [] (Data.Text.Short.toText text))++ declared = Text++instance ToDhall Data.Text.Lazy.Text where+ injectWith _ = Encoder {..}+ where+ embed text =+ TextLit (Chunks [] (Data.Text.Lazy.toStrict text))++ declared = Text++instance ToDhall Text where+ injectWith _ = Encoder {..}+ where+ embed text = TextLit (Chunks [] text)++ declared = Text++instance {-# OVERLAPS #-} ToDhall String where+ injectWith inputNormalizer =+ contramap Data.Text.pack (injectWith inputNormalizer :: Encoder Text)++instance ToDhall Natural where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit++ declared = Natural++instance ToDhall Integer where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit++ declared = Integer++instance ToDhall Int where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit . toInteger++ declared = Integer++instance ToDhall Int8 where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit . toInteger++ declared = Integer++instance ToDhall Int16 where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit . toInteger++ declared = Integer++instance ToDhall Int32 where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit . toInteger++ declared = Integer++instance ToDhall Int64 where+ injectWith _ = Encoder {..}+ where+ embed = IntegerLit . toInteger++ declared = Integer++{-| Encode a 'Word' to a Dhall @Natural@.++>>> embed inject (12 :: Word)+NaturalLit 12+-}+instance ToDhall Word where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit . fromIntegral++ declared = Natural++{-| Encode a 'Word8' to a Dhall @Natural@.++>>> embed inject (12 :: Word8)+NaturalLit 12+-}+instance ToDhall Word8 where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit . fromIntegral++ declared = Natural++{-| Encode a 'Word16' to a Dhall @Natural@.++>>> embed inject (12 :: Word16)+NaturalLit 12+-}+instance ToDhall Word16 where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit . fromIntegral++ declared = Natural++{-| Encode a 'Word32' to a Dhall @Natural@.++>>> embed inject (12 :: Word32)+NaturalLit 12+-}+instance ToDhall Word32 where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit . fromIntegral++ declared = Natural++{-| Encode a 'Word64' to a Dhall @Natural@.++>>> embed inject (12 :: Word64)+NaturalLit 12+-}+instance ToDhall Word64 where+ injectWith _ = Encoder {..}+ where+ embed = NaturalLit . fromIntegral++ declared = Natural++instance ToDhall Double where+ injectWith _ = Encoder {..}+ where+ embed = DoubleLit . DhallDouble++ declared = Double++instance ToDhall Scientific where+ injectWith inputNormalizer =+ contramap Data.Scientific.toRealFloat (injectWith inputNormalizer :: Encoder Double)++instance ToDhall () where+ injectWith _ = Encoder {..}+ where+ embed = const (RecordLit mempty)++ declared = Record mempty++instance ToDhall a => ToDhall (Maybe a) where+ injectWith inputNormalizer = Encoder embedOut declaredOut+ where+ embedOut (Just x ) = Some (embedIn x)+ embedOut Nothing = App None declaredIn++ Encoder embedIn declaredIn = injectWith inputNormalizer++ declaredOut = App Optional declaredIn++instance ToDhall a => ToDhall (Seq a) where+ injectWith inputNormalizer = Encoder embedOut declaredOut+ where+ embedOut xs = ListLit listType (fmap embedIn xs)+ where+ listType+ | null xs = Just (App List declaredIn)+ | otherwise = Nothing++ declaredOut = App List declaredIn++ Encoder embedIn declaredIn = injectWith inputNormalizer++instance ToDhall a => ToDhall [a] where+ injectWith = fmap (contramap Data.Sequence.fromList) injectWith++instance ToDhall a => ToDhall (Vector a) where+ injectWith = fmap (contramap Data.Vector.toList) injectWith++instance ToDhall Time.TimeOfDay where+ injectWith _ = Encoder {..}+ where+ embed timeOfDay = TimeLiteral timeOfDay 12++ declared = Time++instance ToDhall Time.Day where+ injectWith _ = Encoder {..}+ where+ embed = DateLiteral++ declared = Date++instance ToDhall Time.TimeZone where+ injectWith _ = Encoder {..}+ where+ embed = TimeZoneLiteral++ declared = TimeZone++instance ToDhall Time.LocalTime where+ injectWith _ = recordEncoder $+ adapt+ >$< encodeField "date"+ >*< encodeField "time"+ where+ adapt (Time.LocalTime date time) = (date, time)++instance ToDhall Time.ZonedTime where+ injectWith _ = recordEncoder $+ adapt+ >$< encodeField "date"+ >*< encodeField "time"+ >*< encodeField "timeZone"+ where+ adapt (Time.ZonedTime (Time.LocalTime date time) timeZone) = (date, (time, timeZone))++instance ToDhall Time.UTCTime where+ injectWith = contramap (Time.utcToZonedTime Time.utc) . injectWith++instance ToDhall Time.DayOfWeek where+ injectWith _ = Encoder{..}+ where+ embed Time.Sunday =+ Field declared (Core.makeFieldSelection "Sunday")+ embed Time.Monday =+ Field declared (Core.makeFieldSelection "Monday" )+ embed Time.Tuesday =+ Field declared (Core.makeFieldSelection "Tuesday")+ embed Time.Wednesday =+ Field declared (Core.makeFieldSelection "Wednesday")+ embed Time.Thursday =+ Field declared (Core.makeFieldSelection "Thursday")+ embed Time.Friday =+ Field declared (Core.makeFieldSelection "Friday")+ embed Time.Saturday =+ Field declared (Core.makeFieldSelection "Saturday")++ declared =+ Union+ (Dhall.Map.fromList+ [ ("Sunday", Nothing)+ , ("Monday", Nothing)+ , ("Tuesday", Nothing)+ , ("Wednesday", Nothing)+ , ("Thursday", Nothing)+ , ("Friday", Nothing)+ , ("Saturday", Nothing)+ ]+ )++{-| Note that the output list will be sorted.++>>> let x = Data.Set.fromList ["mom", "hi" :: Text]+>>> prettyExpr $ embed inject x+[ "hi", "mom" ]++-}+instance ToDhall a => ToDhall (Data.Set.Set a) where+ injectWith = fmap (contramap Data.Set.toAscList) injectWith++-- | Note that the output list may not be sorted+instance ToDhall a => ToDhall (Data.HashSet.HashSet a) where+ injectWith = fmap (contramap Data.HashSet.toList) injectWith++instance (ToDhall a, ToDhall b) => ToDhall (a, b)++{-| Embed a `Data.Map` as a @Prelude.Map.Type@.++>>> prettyExpr $ embed inject (Data.Map.fromList [(1 :: Natural, True)])+[ { mapKey = 1, mapValue = True } ]++>>> prettyExpr $ embed inject (Data.Map.fromList [] :: Data.Map.Map Natural Bool)+[] : List { mapKey : Natural, mapValue : Bool }++-}+instance (ToDhall k, ToDhall v) => ToDhall (Data.Map.Map k v) where+ injectWith inputNormalizer = Encoder embedOut declaredOut+ where+ embedOut m = ListLit listType (mapEntries m)+ where+ listType+ | Data.Map.null m = Just declaredOut+ | otherwise = Nothing++ declaredOut = App List (Record $ Dhall.Map.fromList+ [ ("mapKey", Core.makeRecordField declaredK)+ , ("mapValue", Core.makeRecordField declaredV)+ ])++ mapEntries = Data.Sequence.fromList . fmap recordPair . Data.Map.toList+ recordPair (k, v) = RecordLit $ Dhall.Map.fromList+ [ ("mapKey", Core.makeRecordField $ embedK k)+ , ("mapValue", Core.makeRecordField $ embedV v)+ ]++ Encoder embedK declaredK = injectWith inputNormalizer+ Encoder embedV declaredV = injectWith inputNormalizer++{-| Embed a `Data.HashMap` as a @Prelude.Map.Type@.++>>> prettyExpr $ embed inject (HashMap.fromList [(1 :: Natural, True)])+[ { mapKey = 1, mapValue = True } ]++>>> prettyExpr $ embed inject (HashMap.fromList [] :: HashMap Natural Bool)+[] : List { mapKey : Natural, mapValue : Bool }++-}+instance (ToDhall k, ToDhall v) => ToDhall (HashMap k v) where+ injectWith inputNormalizer = Encoder embedOut declaredOut+ where+ embedOut m = ListLit listType (mapEntries m)+ where+ listType+ | HashMap.null m = Just declaredOut+ | otherwise = Nothing++ declaredOut = App List (Record $ Dhall.Map.fromList+ [ ("mapKey", Core.makeRecordField declaredK)+ , ("mapValue", Core.makeRecordField declaredV)+ ])++ mapEntries = Data.Sequence.fromList . fmap recordPair . HashMap.toList+ recordPair (k, v) = RecordLit $ Dhall.Map.fromList+ [ ("mapKey", Core.makeRecordField $ embedK k)+ , ("mapValue", Core.makeRecordField $ embedV v)+ ]++ Encoder embedK declaredK = injectWith inputNormalizer+ Encoder embedV declaredV = injectWith inputNormalizer++instance ToDhall (f (Result f)) => ToDhall (Result f) where+ injectWith inputNormalizer = Encoder {..}+ where+ embed = App "Make" . Dhall.Marshal.Encode.embed (injectWith inputNormalizer) . _unResult+ declared = "result"++instance forall f. (Functor f, ToDhall (f (Result f))) => ToDhall (Fix f) where+ injectWith inputNormalizer = Encoder {..}+ where+ embed fixf =+ Lam Nothing (Core.makeFunctionBinding "result" (Const Core.Type)) $+ Lam Nothing (Core.makeFunctionBinding "Make" makeType) $+ embed' . fixToResult $ fixf++ declared = Pi Nothing "result" (Const Core.Type) $ Pi Nothing "_" makeType "result"++ makeType = Pi Nothing "_" declared' "result"+ Encoder embed' _ = injectWith @(Dhall.Marshal.Internal.Result f) inputNormalizer+ Encoder _ declared' = injectWith @(f (Dhall.Marshal.Internal.Result f)) inputNormalizer++fixToResult :: Functor f => Fix f -> Result f+fixToResult (Fix x) = Result (fmap fixToResult x)++++{-| This is the underlying class that powers the `Dhall.Marshal.Decode.FromDhall` class's support+ for automatically deriving a generic implementation.+-}+class GenericToDhall f where+ genericToDhallWithNormalizer :: InputNormalizer -> InterpretOptions -> State Int (Encoder (f a))++instance GenericToDhall f => GenericToDhall (M1 D d f) where+ genericToDhallWithNormalizer inputNormalizer options = do+ res <- genericToDhallWithNormalizer inputNormalizer options+ pure (contramap unM1 res)++instance GenericToDhall f => GenericToDhall (M1 C c f) where+ genericToDhallWithNormalizer inputNormalizer options = do+ res <- genericToDhallWithNormalizer inputNormalizer options+ pure (contramap unM1 res)++instance (Selector s, ToDhall a) => GenericToDhall (M1 S s (K1 i a)) where+ genericToDhallWithNormalizer inputNormalizer InterpretOptions{..} = do+ let Encoder { embed = embed', declared = declared' } =+ injectWith inputNormalizer++ let n :: M1 S s (K1 i a) r+ n = undefined++ name <- fieldModifier <$> getSelName n++ let embed0 (M1 (K1 x)) = embed' x++ let embed1 (M1 (K1 x)) =+ RecordLit (Dhall.Map.singleton name (Core.makeRecordField $ embed' x))++ let embed =+ case singletonConstructors of+ Bare -> embed0+ Smart | selName n == "" -> embed0+ _ -> embed1++ let declared =+ case singletonConstructors of+ Bare ->+ declared'+ Smart | selName n == "" ->+ declared'+ _ ->+ Record (Dhall.Map.singleton name $ Core.makeRecordField declared')++ return (Encoder {..})++instance (Constructor c1, Constructor c2, GenericToDhall f1, GenericToDhall f2) => GenericToDhall (M1 C c1 f1 :+: M1 C c2 f2) where+ genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})+ where+ embed (L1 (M1 l)) =+ case notEmptyRecordLit (embedL l) of+ Nothing ->+ Field declared $ Core.makeFieldSelection keyL+ Just valL ->+ App (Field declared $ Core.makeFieldSelection keyL) valL++ embed (R1 (M1 r)) =+ case notEmptyRecordLit (embedR r) of+ Nothing ->+ Field declared $ Core.makeFieldSelection keyR+ Just valR ->+ App (Field declared $ Core.makeFieldSelection keyR) valR++ declared =+ Union+ (Dhall.Map.fromList+ [ (keyL, notEmptyRecord declaredL)+ , (keyR, notEmptyRecord declaredR)+ ]+ )++ nL :: M1 i c1 f1 a+ nL = undefined++ nR :: M1 i c2 f2 a+ nR = undefined++ keyL = constructorModifier (Data.Text.pack (conName nL))+ keyR = constructorModifier (Data.Text.pack (conName nR))++ Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1+ Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1++instance (Constructor c, GenericToDhall (f :+: g), GenericToDhall h) => GenericToDhall ((f :+: g) :+: M1 C c h) where+ genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})+ where+ embed (L1 l) =+ case maybeValL of+ Nothing -> Field declared $ Core.makeFieldSelection keyL+ Just valL -> App (Field declared $ Core.makeFieldSelection keyL) valL+ where+ (keyL, maybeValL) =+ unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedL l)+ embed (R1 (M1 r)) =+ case notEmptyRecordLit (embedR r) of+ Nothing -> Field declared $ Core.makeFieldSelection keyR+ Just valR -> App (Field declared $ Core.makeFieldSelection keyR) valR++ nR :: M1 i c h a+ nR = undefined++ keyR = constructorModifier (Data.Text.pack (conName nR))++ declared = Union (Dhall.Map.insert keyR (notEmptyRecord declaredR) ktsL)++ Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1+ Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1++ ktsL = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredL++instance (Constructor c, GenericToDhall f, GenericToDhall (g :+: h)) => GenericToDhall (M1 C c f :+: (g :+: h)) where+ genericToDhallWithNormalizer inputNormalizer options@(InterpretOptions {..}) = pure (Encoder {..})+ where+ embed (L1 (M1 l)) =+ case notEmptyRecordLit (embedL l) of+ Nothing -> Field declared $ Core.makeFieldSelection keyL+ Just valL -> App (Field declared $ Core.makeFieldSelection keyL) valL+ embed (R1 r) =+ case maybeValR of+ Nothing -> Field declared $ Core.makeFieldSelection keyR+ Just valR -> App (Field declared $ Core.makeFieldSelection keyR) valR+ where+ (keyR, maybeValR) =+ unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedR r)++ nL :: M1 i c f a+ nL = undefined++ keyL = constructorModifier (Data.Text.pack (conName nL))++ declared = Union (Dhall.Map.insert keyL (notEmptyRecord declaredL) ktsR)++ Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1+ Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1++ ktsR = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredR++instance (GenericToDhall (f :+: g), GenericToDhall (h :+: i)) => GenericToDhall ((f :+: g) :+: (h :+: i)) where+ genericToDhallWithNormalizer inputNormalizer options = pure (Encoder {..})+ where+ embed (L1 l) =+ case maybeValL of+ Nothing -> Field declared $ Core.makeFieldSelection keyL+ Just valL -> App (Field declared $ Core.makeFieldSelection keyL) valL+ where+ (keyL, maybeValL) =+ unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedL l)+ embed (R1 r) =+ case maybeValR of+ Nothing -> Field declared $ Core.makeFieldSelection keyR+ Just valR -> App (Field declared $ Core.makeFieldSelection keyR) valR+ where+ (keyR, maybeValR) =+ unsafeExpectUnionLit "genericToDhallWithNormalizer (:+:)" (embedR r)++ declared = Union (Dhall.Map.union ktsL ktsR)++ Encoder embedL declaredL = evalState (genericToDhallWithNormalizer inputNormalizer options) 1+ Encoder embedR declaredR = evalState (genericToDhallWithNormalizer inputNormalizer options) 1++ ktsL = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredL+ ktsR = unsafeExpectUnion "genericToDhallWithNormalizer (:+:)" declaredR++instance (GenericToDhall (f :*: g), GenericToDhall (h :*: i)) => GenericToDhall ((f :*: g) :*: (h :*: i)) where+ genericToDhallWithNormalizer inputNormalizer options = do+ Encoder embedL declaredL <- genericToDhallWithNormalizer inputNormalizer options+ Encoder embedR declaredR <- genericToDhallWithNormalizer inputNormalizer options++ let embed (l :*: r) =+ RecordLit (Dhall.Map.union mapL mapR)+ where+ mapL =+ unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedL l)++ mapR =+ unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedR r)++ let declared = Record (Dhall.Map.union mapL mapR)+ where+ mapL = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredL+ mapR = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredR++ pure (Encoder {..})++instance (GenericToDhall (f :*: g), Selector s, ToDhall a) => GenericToDhall ((f :*: g) :*: M1 S s (K1 i a)) where+ genericToDhallWithNormalizer inputNormalizer options@InterpretOptions{..} = do+ let nR :: M1 S s (K1 i a) r+ nR = undefined++ nameR <- fmap fieldModifier (getSelName nR)++ Encoder embedL declaredL <- genericToDhallWithNormalizer inputNormalizer options++ let Encoder embedR declaredR = injectWith inputNormalizer++ let embed (l :*: M1 (K1 r)) =+ RecordLit (Dhall.Map.insert nameR (Core.makeRecordField $ embedR r) mapL)+ where+ mapL =+ unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedL l)++ let declared = Record (Dhall.Map.insert nameR (Core.makeRecordField declaredR) mapL)+ where+ mapL = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredL++ return (Encoder {..})++instance (Selector s, ToDhall a, GenericToDhall (f :*: g)) => GenericToDhall (M1 S s (K1 i a) :*: (f :*: g)) where+ genericToDhallWithNormalizer inputNormalizer options@InterpretOptions{..} = do+ let nL :: M1 S s (K1 i a) r+ nL = undefined++ nameL <- fmap fieldModifier (getSelName nL)++ let Encoder embedL declaredL = injectWith inputNormalizer++ Encoder embedR declaredR <- genericToDhallWithNormalizer inputNormalizer options++ let embed (M1 (K1 l) :*: r) =+ RecordLit (Dhall.Map.insert nameL (Core.makeRecordField $ embedL l) mapR)+ where+ mapR =+ unsafeExpectRecordLit "genericToDhallWithNormalizer (:*:)" (embedR r)++ let declared = Record (Dhall.Map.insert nameL (Core.makeRecordField declaredL) mapR)+ where+ mapR = unsafeExpectRecord "genericToDhallWithNormalizer (:*:)" declaredR++ return (Encoder {..})++instance (Selector s1, Selector s2, ToDhall a1, ToDhall a2) => GenericToDhall (M1 S s1 (K1 i1 a1) :*: M1 S s2 (K1 i2 a2)) where+ genericToDhallWithNormalizer inputNormalizer InterpretOptions{..} = do+ let nL :: M1 S s1 (K1 i1 a1) r+ nL = undefined++ let nR :: M1 S s2 (K1 i2 a2) r+ nR = undefined++ nameL <- fmap fieldModifier (getSelName nL)+ nameR <- fmap fieldModifier (getSelName nR)++ let Encoder embedL declaredL = injectWith inputNormalizer+ let Encoder embedR declaredR = injectWith inputNormalizer++ let embed (M1 (K1 l) :*: M1 (K1 r)) =+ RecordLit $+ Dhall.Map.fromList+ [ (nameL, Core.makeRecordField $ embedL l)+ , (nameR, Core.makeRecordField $ embedR r) ]+++ let declared =+ Record $ Dhall.Map.fromList+ [ (nameL, Core.makeRecordField declaredL)+ , (nameR, Core.makeRecordField declaredR) ]+++ return (Encoder {..})++instance GenericToDhall U1 where+ genericToDhallWithNormalizer _ _ = pure (Encoder {..})+ where+ embed _ = RecordLit mempty++ declared = Record mempty++{-| Use the default options for injecting a value, whose structure is+determined generically.++This can be used when you want to use 'ToDhall' on types that you don't+want to define orphan instances for.+-}+genericToDhall+ :: (Generic a, GenericToDhall (Rep a)) => Encoder a+genericToDhall+ = genericToDhallWith defaultInterpretOptions++{-| Use custom options for injecting a value, whose structure is+determined generically.++This can be used when you want to use 'ToDhall' on types that you don't+want to define orphan instances for.+-}+genericToDhallWith+ :: (Generic a, GenericToDhall (Rep a)) => InterpretOptions -> Encoder a+genericToDhallWith options = genericToDhallWithInputNormalizer options defaultInputNormalizer++{-| `genericToDhallWithInputNormalizer` is like `genericToDhallWith`, but+ instead of using the `defaultInputNormalizer` it expects an custom+ `InputNormalizer`.+-}+genericToDhallWithInputNormalizer+ :: (Generic a, GenericToDhall (Rep a)) => InterpretOptions -> InputNormalizer -> Encoder a+genericToDhallWithInputNormalizer options inputNormalizer+ = contramap GHC.Generics.from (evalState (genericToDhallWithNormalizer inputNormalizer options) 1)++++{-| The 'RecordEncoder' divisible (contravariant) functor allows you to build+ an 'Encoder' for a Dhall record.++ For example, let's take the following Haskell data type:++>>> :{+data Project = Project+ { projectName :: Text+ , projectDescription :: Text+ , projectStars :: Natural+ }+:}++ And assume that we have the following Dhall record that we would like to+ parse as a @Project@:++> { name =+> "dhall-haskell"+> , description =+> "A configuration language guaranteed to terminate"+> , stars =+> 289+> }++ Our encoder has type 'Encoder' @Project@, but we can't build that out of any+ smaller encoders, as 'Encoder's cannot be combined (they are only 'Contravariant's).+ However, we can use an 'RecordEncoder' to build an 'Encoder' for @Project@:++>>> :{+injectProject :: Encoder Project+injectProject =+ recordEncoder+ ( adapt >$< encodeFieldWith "name" inject+ >*< encodeFieldWith "description" inject+ >*< encodeFieldWith "stars" inject+ )+ where+ adapt (Project{..}) = (projectName, (projectDescription, projectStars))+:}++ Or, since we are simply using the `ToDhall` instance to inject each field, we could write++>>> :{+injectProject :: Encoder Project+injectProject =+ recordEncoder+ ( adapt >$< encodeField "name"+ >*< encodeField "description"+ >*< encodeField "stars"+ )+ where+ adapt (Project{..}) = (projectName, (projectDescription, projectStars))+:}++-}+newtype RecordEncoder a+ = RecordEncoder (Dhall.Map.Map Text (Encoder a))++instance Contravariant RecordEncoder where+ contramap f (RecordEncoder encodeTypeRecord) = RecordEncoder $ contramap f <$> encodeTypeRecord++instance Divisible RecordEncoder where+ divide f (RecordEncoder bEncoderRecord) (RecordEncoder cEncoderRecord) =+ RecordEncoder+ $ Dhall.Map.union+ ((contramap $ fst . f) <$> bEncoderRecord)+ ((contramap $ snd . f) <$> cEncoderRecord)+ conquer = RecordEncoder mempty++-- | Convert a `RecordEncoder` into the equivalent `Encoder`.+recordEncoder :: RecordEncoder a -> Encoder a+recordEncoder (RecordEncoder encodeTypeRecord) = Encoder makeRecordLit recordType+ where+ recordType = Record $ (Core.makeRecordField . declared) <$> encodeTypeRecord+ makeRecordLit x = RecordLit $ (Core.makeRecordField . ($ x) . embed) <$> encodeTypeRecord++{-| Specify how to encode one field of a record using the default `ToDhall`+ instance for that type.+-}+encodeField :: ToDhall a => Text -> RecordEncoder a+encodeField name = encodeFieldWith name inject++{-| Specify how to encode one field of a record by supplying an explicit+ `Encoder` for that field.+-}+encodeFieldWith :: Text -> Encoder a -> RecordEncoder a+encodeFieldWith name encodeType = RecordEncoder $ Dhall.Map.singleton name encodeType++++{-| 'UnionEncoder' allows you to build an 'Encoder' for a Dhall record.++ For example, let's take the following Haskell data type:++>>> :{+data Status = Queued Natural+ | Result Text+ | Errored Text+:}++ And assume that we have the following Dhall union that we would like to+ parse as a @Status@:++> < Result : Text+> | Queued : Natural+> | Errored : Text+> >.Result "Finish successfully"++ Our encoder has type 'Encoder' @Status@, but we can't build that out of any+ smaller encoders, as 'Encoder's cannot be combined.+ However, we can use an 'UnionEncoder' to build an 'Encoder' for @Status@:++>>> :{+injectStatus :: Encoder Status+injectStatus = adapt >$< unionEncoder+ ( encodeConstructorWith "Queued" inject+ >|< encodeConstructorWith "Result" inject+ >|< encodeConstructorWith "Errored" inject+ )+ where+ adapt (Queued n) = Left n+ adapt (Result t) = Right (Left t)+ adapt (Errored e) = Right (Right e)+:}++ Or, since we are simply using the `ToDhall` instance to inject each branch, we could write++>>> :{+injectStatus :: Encoder Status+injectStatus = adapt >$< unionEncoder+ ( encodeConstructor "Queued"+ >|< encodeConstructor "Result"+ >|< encodeConstructor "Errored"+ )+ where+ adapt (Queued n) = Left n+ adapt (Result t) = Right (Left t)+ adapt (Errored e) = Right (Right e)+:}++-}+newtype UnionEncoder a =+ UnionEncoder+ ( Data.Functor.Product.Product+ ( Control.Applicative.Const+ ( Dhall.Map.Map+ Text+ ( Expr Src Void )+ )+ )+ ( Op (Text, Expr Src Void) )+ a+ )+ deriving (Contravariant)++-- | Convert a `UnionEncoder` into the equivalent `Encoder`.+unionEncoder :: UnionEncoder a -> Encoder a+unionEncoder ( UnionEncoder ( Data.Functor.Product.Pair ( Control.Applicative.Const fields ) ( Op embedF ) ) ) =+ Encoder+ { embed = \x ->+ let (name, y) = embedF x+ in case notEmptyRecordLit y of+ Nothing -> Field (Union fields') $ Core.makeFieldSelection name+ Just val -> App (Field (Union fields') $ Core.makeFieldSelection name) val+ , declared =+ Union fields'+ }+ where+ fields' = fmap notEmptyRecord fields++{-| Specify how to encode an alternative by using the default `ToDhall` instance+ for that type.+-}+encodeConstructor+ :: ToDhall a+ => Text+ -> UnionEncoder a+encodeConstructor name = encodeConstructorWith name inject++{-| Specify how to encode an alternative by providing an explicit `Encoder`+ for that alternative.+-}+encodeConstructorWith+ :: Text+ -> Encoder a+ -> UnionEncoder a+encodeConstructorWith name encodeType = UnionEncoder $+ Data.Functor.Product.Pair+ ( Control.Applicative.Const+ ( Dhall.Map.singleton+ name+ ( declared encodeType )+ )+ )+ ( Op ( (name,) . embed encodeType )+ )++-- | Combines two 'UnionEncoder' values. See 'UnionEncoder' for usage+-- notes.+--+-- Ideally, this matches 'Data.Functor.Contravariant.Divisible.chosen';+-- however, this allows 'UnionEncoder' to not need a 'Divisible' instance+-- itself (since no instance is possible).+(>|<) :: UnionEncoder a -> UnionEncoder b -> UnionEncoder (Either a b)+UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const mx) (Op fx))+ >|< UnionEncoder (Data.Functor.Product.Pair (Control.Applicative.Const my) (Op fy)) =+ UnionEncoder+ ( Data.Functor.Product.Pair+ ( Control.Applicative.Const (mx <> my) )+ ( Op (either fx fy) )+ )++infixr 5 >|<++++-- | Infix 'divided'+(>*<) :: Divisible f => f a -> f b -> f (a, b)+(>*<) = divided++infixr 5 >*<
@@ -0,0 +1,193 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}++{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining+ how to use the language, the compiler, and this library+-}++module Dhall.Marshal.Internal+ ( InputNormalizer(..)+ , defaultInputNormalizer+ , InterpretOptions(..)+ , SingletonConstructors(..)+ , defaultInterpretOptions++ -- * Miscellaneous+ , Result(..)++ -- * Helpers for the generic deriving machinery+ , getSelName+ , notEmptyRecord+ , notEmptyRecordLit+ , unsafeExpectRecord+ , unsafeExpectRecordLit+ , unsafeExpectUnion+ , unsafeExpectUnionLit++ -- * Re-exports+ , Fix(..)+ , HashMap+ , Int8+ , Int16+ , Int32+ , Int64+ , Map+ , Natural+ , Scientific+ , Seq+ , Text+ , Vector+ , Void+ , Word8+ , Word16+ , Word32+ , Word64+ , Generic+ ) where++import Control.Monad.Trans.State.Strict+import Data.Fix (Fix (..))+import Data.HashMap.Strict (HashMap)+import Data.Int (Int16, Int32, Int64, Int8)+import Data.Map (Map)+import Data.Scientific (Scientific)+import Data.Sequence (Seq)+import Data.Text (Text)+import Data.Vector (Vector)+import Data.Void (Void)+import Data.Word (Word16, Word32, Word64, Word8)+import Dhall.Parser (Src (..))+import Dhall.Syntax (Expr (..), RecordField (..))+import GHC.Generics+import Numeric.Natural (Natural)+import Prelude hiding (maybe, sequence)++import qualified Data.Text+import qualified Dhall.Core as Core+import qualified Dhall.Map++{-| This type is exactly the same as `Data.Fix.Fix` except with a different+ `Dhall.Marshal.Decode.FromDhall` instance. This intermediate type+ simplifies the implementation of the inner loop for the+ `Dhall.Marshal.Decode.FromDhall` instance for `Fix`.+-}+newtype Result f = Result { _unResult :: f (Result f) }++{-| Use these options to tweak how Dhall derives a generic implementation of+ `Dhall.Marshal.Decode.FromDhall`.+-}+data InterpretOptions = InterpretOptions+ { fieldModifier :: Text -> Text+ -- ^ Function used to transform Haskell field names into their corresponding+ -- Dhall field names+ , constructorModifier :: Text -> Text+ -- ^ Function used to transform Haskell constructor names into their+ -- corresponding Dhall alternative names+ , singletonConstructors :: SingletonConstructors+ -- ^ Specify how to handle constructors with only one field. The default is+ -- `Smart`+ }++{-| This is only used by the `Dhall.Marshal.Decode.FromDhall` instance for+ functions in order to normalize the function input before marshaling the+ input into a Dhall expression.+-}+newtype InputNormalizer = InputNormalizer+ { getInputNormalizer :: Core.ReifiedNormalizer Void }++-- | Default normalization-related settings (no custom normalization)+defaultInputNormalizer :: InputNormalizer+defaultInputNormalizer = InputNormalizer+ { getInputNormalizer = Core.ReifiedNormalizer (const (pure Nothing)) }++{-| This type specifies how to model a Haskell constructor with 1 field in+ Dhall++ For example, consider the following Haskell datatype definition:++ > data Example = Foo { x :: Double } | Bar Double++ Depending on which option you pick, the corresponding Dhall type could be:++ > < Foo : Double | Bar : Double > -- Bare++ > < Foo : { x : Double } | Bar : { _1 : Double } > -- Wrapped++ > < Foo : { x : Double } | Bar : Double > -- Smart+-}+data SingletonConstructors+ = Bare+ -- ^ Never wrap the field in a record+ | Wrapped+ -- ^ Always wrap the field in a record+ | Smart+ -- ^ Only fields in a record if they are named++{-| Default interpret options for generics-based instances,+ which you can tweak or override, like this:++> genericAutoWith+> (defaultInterpretOptions { fieldModifier = Data.Text.Lazy.dropWhile (== '_') })+-}+defaultInterpretOptions :: InterpretOptions+defaultInterpretOptions = InterpretOptions+ { fieldModifier =+ id+ , constructorModifier =+ id+ , singletonConstructors =+ Smart+ }++unsafeExpectUnion+ :: Text -> Expr Src Void -> Dhall.Map.Map Text (Maybe (Expr Src Void))+unsafeExpectUnion _ (Union kts) =+ kts+unsafeExpectUnion name expression =+ Core.internalError+ (name <> ": Unexpected constructor: " <> Core.pretty expression)++unsafeExpectRecord+ :: Text -> Expr Src Void -> Dhall.Map.Map Text (RecordField Src Void)+unsafeExpectRecord _ (Record kts) =+ kts+unsafeExpectRecord name expression =+ Core.internalError+ (name <> ": Unexpected constructor: " <> Core.pretty expression)++unsafeExpectUnionLit+ :: Text+ -> Expr Src Void+ -> (Text, Maybe (Expr Src Void))+unsafeExpectUnionLit _ (Field (Union _) (Core.fieldSelectionLabel -> k)) =+ (k, Nothing)+unsafeExpectUnionLit _ (App (Field (Union _) (Core.fieldSelectionLabel -> k)) v) =+ (k, Just v)+unsafeExpectUnionLit name expression =+ Core.internalError+ (name <> ": Unexpected constructor: " <> Core.pretty expression)++unsafeExpectRecordLit+ :: Text -> Expr Src Void -> Dhall.Map.Map Text (RecordField Src Void)+unsafeExpectRecordLit _ (RecordLit kvs) =+ kvs+unsafeExpectRecordLit name expression =+ Core.internalError+ (name <> ": Unexpected constructor: " <> Core.pretty expression)++notEmptyRecordLit :: Expr s a -> Maybe (Expr s a)+notEmptyRecordLit e = case e of+ RecordLit m | null m -> Nothing+ _ -> Just e++notEmptyRecord :: Expr s a -> Maybe (Expr s a)+notEmptyRecord e = case e of+ Record m | null m -> Nothing+ _ -> Just e++getSelName :: Selector s => M1 i s f a -> State Int Text+getSelName n = case selName n of+ "" -> do i <- get+ put (i + 1)+ pure (Data.Text.pack ("_" ++ show i))+ nn -> pure (Data.Text.pack nn)
@@ -0,0 +1,1037 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-}++module Dhall.Normalize (+ alphaNormalize+ , normalize+ , normalizeWith+ , normalizeWithM+ , Normalizer+ , NormalizerM+ , ReifiedNormalizer (..)+ , judgmentallyEqual+ , subst+ , Syntax.shift+ , isNormalized+ , isNormalizedWith+ , freeIn+ ) where++import Control.Applicative (empty)+import Data.Foldable+import Data.Functor.Identity (Identity (..))+import Data.List.NonEmpty (NonEmpty (..))+import Data.Sequence (ViewL (..), ViewR (..))+import Data.Traversable+import Instances.TH.Lift ()+import Prelude hiding (succ)++import Dhall.Syntax+ ( Binding (Binding)+ , Chunks (..)+ , DhallDouble (..)+ , Expr (..)+ , FieldSelection (..)+ , FunctionBinding (..)+ , PreferAnnotation (..)+ , RecordField (..)+ , Var (..)+ , WithComponent (..)+ )++import qualified Data.Sequence+import qualified Data.Set+import qualified Data.Text as Text+import qualified Dhall.Eval as Eval+import qualified Dhall.Map+import qualified Dhall.Syntax as Syntax+import qualified Lens.Micro as Lens++{-| Returns `True` if two expressions are α-equivalent and β-equivalent and+ `False` otherwise++ `judgmentallyEqual` can fail with an `error` if you compare ill-typed+ expressions+-}+judgmentallyEqual :: Eq a => Expr s a -> Expr t a -> Bool+judgmentallyEqual = Eval.judgmentallyEqual+{-# INLINE judgmentallyEqual #-}++{-| Substitute all occurrences of a variable with an expression++> subst x C B ~ B[x := C]+-}+subst :: Var -> Expr s a -> Expr s a -> Expr s a+subst _ _ (Const a) = Const a+subst (V x n) e (Lam cs (FunctionBinding src0 y src1 src2 _A) b) =+ Lam cs (FunctionBinding src0 y src1 src2 _A') b'+ where+ _A' = subst (V x n ) e _A+ b' = subst (V x n') (Syntax.shift 1 (V y 0) e) b+ n' = if x == y then n + 1 else n+subst (V x n) e (Pi cs y _A _B) = Pi cs y _A' _B'+ where+ _A' = subst (V x n ) e _A+ _B' = subst (V x n') (Syntax.shift 1 (V y 0) e) _B+ n' = if x == y then n + 1 else n+subst v e (Var v') = if v == v' then e else Var v'+subst (V x n) e (Let (Binding src0 f src1 mt src2 r) b) =+ Let (Binding src0 f src1 mt' src2 r') b'+ where+ b' = subst (V x n') (Syntax.shift 1 (V f 0) e) b+ where+ n' = if x == f then n + 1 else n++ mt' = fmap (fmap (subst (V x n) e)) mt+ r' = subst (V x n) e r+subst x e expression = Lens.over Syntax.subExpressions (subst x e) expression++{-| This function is used to determine whether folds like @Natural/fold@ or+ @List/fold@ should be lazy or strict in their accumulator based on the type+ of the accumulator++ If this function returns `True`, then they will be strict in their+ accumulator since we can guarantee an upper bound on the amount of work to+ normalize the accumulator on each step of the loop. If this function+ returns `False` then they will be lazy in their accumulator and only+ normalize the final result at the end of the fold+-}+boundedType :: Expr s a -> Bool+boundedType Bool = True+boundedType Natural = True+boundedType Integer = True+boundedType Double = True+boundedType Text = True+boundedType (App List _) = False+boundedType (App Optional t) = boundedType t+boundedType (Record kvs) = all (boundedType . recordFieldValue) kvs+boundedType (Union kvs) = all (all boundedType) kvs+boundedType _ = False++{-| α-normalize an expression by renaming all bound variables to @\"_\"@ and+ using De Bruijn indices to distinguish them++>>> mfb = Syntax.makeFunctionBinding+>>> alphaNormalize (Lam mempty (mfb "a" (Const Type)) (Lam mempty (mfb "b" (Const Type)) (Lam mempty (mfb "x" "a") (Lam mempty (mfb "y" "b") "x"))))+Lam Nothing (FunctionBinding {functionBindingSrc0 = Nothing, functionBindingVariable = "_", functionBindingSrc1 = Nothing, functionBindingSrc2 = Nothing, functionBindingAnnotation = Const Type}) (Lam Nothing (FunctionBinding {functionBindingSrc0 = Nothing, functionBindingVariable = "_", functionBindingSrc1 = Nothing, functionBindingSrc2 = Nothing, functionBindingAnnotation = Const Type}) (Lam Nothing (FunctionBinding {functionBindingSrc0 = Nothing, functionBindingVariable = "_", functionBindingSrc1 = Nothing, functionBindingSrc2 = Nothing, functionBindingAnnotation = Var (V "_" 1)}) (Lam Nothing (FunctionBinding {functionBindingSrc0 = Nothing, functionBindingVariable = "_", functionBindingSrc1 = Nothing, functionBindingSrc2 = Nothing, functionBindingAnnotation = Var (V "_" 1)}) (Var (V "_" 1)))))++ α-normalization does not affect free variables:++>>> alphaNormalize "x"+Var (V "x" 0)++-}+alphaNormalize :: Expr s a -> Expr s a+alphaNormalize = Eval.alphaNormalize+{-# INLINE alphaNormalize #-}++{-| Reduce an expression to its normal form, performing beta reduction++ `normalize` does not type-check the expression. You may want to type-check+ expressions before normalizing them since normalization can convert an+ ill-typed expression into a well-typed expression.++ `normalize` can also fail with `error` if you normalize an ill-typed+ expression+-}+normalize :: Eq a => Expr s a -> Expr t a+normalize = Eval.normalize+{-# INLINE normalize #-}++{-| Reduce an expression to its normal form, performing beta reduction and applying+ any custom definitions.++ `normalizeWith` is designed to be used with function `Dhall.TypeCheck.typeWith`. The `Dhall.TypeCheck.typeWith`+ function allows typing of Dhall functions in a custom typing context whereas+ `normalizeWith` allows evaluating Dhall expressions in a custom context.++ To be more precise `normalizeWith` applies the given normalizer when it finds an+ application term that it cannot reduce by other means.++ Note that the context used in normalization will determine the properties of normalization.+ That is, if the functions in custom context are not total then the Dhall language, evaluated+ with those functions is not total either.++ `normalizeWith` can fail with an `error` if you normalize an ill-typed+ expression+-}+normalizeWith :: Eq a => Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a+normalizeWith (Just ctx) t = runIdentity (normalizeWithM (getReifiedNormalizer ctx) t)+normalizeWith _ t = Eval.normalize t+{-# INLINABLE normalizeWith #-}++{-| This function generalizes `normalizeWith` by allowing the custom normalizer+ to use an arbitrary `Monad`++ `normalizeWithM` can fail with an `error` if you normalize an ill-typed+ expression+-}+normalizeWithM+ :: (Monad m, Eq a) => NormalizerM m a -> Expr s a -> m (Expr t a)+normalizeWithM ctx e0 = loop (Syntax.denote e0)+ where+ loop e = ctx e >>= \case+ Just e' -> loop e'+ Nothing -> case e of+ Const k -> pure (Const k)+ Var v -> pure (Var v)+ Lam cs (FunctionBinding { functionBindingVariable = x, functionBindingAnnotation = _A }) b ->+ Lam cs <$> (Syntax.makeFunctionBinding x <$> _A') <*> b'+ where+ _A' = loop _A+ b' = loop b+ Pi cs x _A _B -> Pi cs x <$> _A' <*> _B'+ where+ _A' = loop _A+ _B' = loop _B+ App f a -> do+ f' <- loop f+ a' <- loop a+ case f' of+ Lam _ (FunctionBinding _ x _ _ _A) b₀ -> do++ let a₂ = Syntax.shift 1 (V x 0) a'+ let b₁ = subst (V x 0) a₂ b₀+ let b₂ = Syntax.shift (-1) (V x 0) b₁++ loop b₂+ _ ->+ case App f' a' of+ App (App (App (App NaturalFold (NaturalLit n0)) t) succ') zero -> do+ t' <- loop t+ if boundedType t' then strict else lazy+ where+ -- Use an `Integer` for the loop, due to the following+ -- issue:+ --+ -- https://github.com/ghcjs/ghcjs/issues/782+ strict = strictLoop (fromIntegral n0 :: Integer)+ lazy = loop ( lazyLoop (fromIntegral n0 :: Integer))++ strictLoop !n = do+ z <- loop zero+ strictLoopShortcut n z++ strictLoopShortcut 0 !previous = pure previous+ strictLoopShortcut !n !previous = do+ current <- loop (App succ' previous)+ if judgmentallyEqual previous current+ then pure previous+ else strictLoopShortcut (n - 1) current++ lazyLoop 0 = zero+ lazyLoop !n = App succ' (lazyLoop (n - 1))+ App NaturalBuild g -> loop (App (App (App g Natural) succ) zero)+ where+ succ = Lam mempty (Syntax.makeFunctionBinding "n" Natural) (NaturalPlus "n" (NaturalLit 1))++ zero = NaturalLit 0+ App NaturalIsZero (NaturalLit n) -> pure (BoolLit (n == 0))+ App NaturalEven (NaturalLit n) -> pure (BoolLit (even n))+ App NaturalOdd (NaturalLit n) -> pure (BoolLit (odd n))+ App NaturalToInteger (NaturalLit n) -> pure (IntegerLit (toInteger n))+ App NaturalShow (NaturalLit n) ->+ pure (TextLit (Chunks [] (Text.pack (show n))))+ App (App NaturalSubtract (NaturalLit x)) (NaturalLit y)+ -- Use an `Integer` for the subtraction, due to the+ -- following issue:+ --+ -- https://github.com/ghcjs/ghcjs/issues/782+ | y >= x ->+ pure (NaturalLit (fromIntegral (subtract (fromIntegral x :: Integer) (fromIntegral y :: Integer))))+ | otherwise ->+ pure (NaturalLit 0)+ App (App NaturalSubtract (NaturalLit 0)) y -> pure y+ App (App NaturalSubtract _) (NaturalLit 0) -> pure (NaturalLit 0)+ App (App NaturalSubtract x) y | Eval.judgmentallyEqual x y -> pure (NaturalLit 0)+ App IntegerClamp (IntegerLit n)+ | 0 <= n -> pure (NaturalLit (fromInteger n))+ | otherwise -> pure (NaturalLit 0)+ App IntegerNegate (IntegerLit n) ->+ pure (IntegerLit (negate n))+ App IntegerShow (IntegerLit n)+ | 0 <= n -> pure (TextLit (Chunks [] ("+" <> Text.pack (show n))))+ | otherwise -> pure (TextLit (Chunks [] (Text.pack (show n))))+ -- `(read . show)` is used instead of `fromInteger` because `read` uses+ -- the correct rounding rule.+ -- See https://gitlab.haskell.org/ghc/ghc/issues/17231.+ App IntegerToDouble (IntegerLit n) -> pure (DoubleLit ((DhallDouble . read . show) n))+ App DoubleShow (DoubleLit (DhallDouble n)) ->+ pure (TextLit (Chunks [] (Text.pack (show n))))+ App (App ListBuild _A₀) g -> loop (App (App (App g list) cons) nil)+ where+ _A₁ = Syntax.shift 1 "a" _A₀++ list = App List _A₀++ cons =+ Lam mempty (Syntax.makeFunctionBinding "a" _A₀)+ (Lam mempty+ (Syntax.makeFunctionBinding "as" (App List _A₁))+ (ListAppend (ListLit Nothing (pure "a")) "as")+ )++ nil = ListLit (Just (App List _A₀)) empty+ App (App (App (App (App ListFold _) (ListLit _ xs)) t) cons) nil -> do+ t' <- loop t+ if boundedType t' then strict else lazy+ where+ strict = foldr strictCons strictNil xs+ lazy = loop (foldr lazyCons lazyNil xs)++ strictNil = loop nil+ lazyNil = nil++ strictCons y ys =+ App (App cons y) <$> ys >>= loop+ lazyCons y ys = App (App cons y) ys+ App (App ListLength _) (ListLit _ ys) ->+ pure (NaturalLit (fromIntegral (Data.Sequence.length ys)))+ App (App ListHead t) (ListLit _ ys) -> loop o+ where+ o = case Data.Sequence.viewl ys of+ y :< _ -> Some y+ _ -> App None t+ App (App ListLast t) (ListLit _ ys) -> loop o+ where+ o = case Data.Sequence.viewr ys of+ _ :> y -> Some y+ _ -> App None t+ App (App ListIndexed _A₀) (ListLit _ as₀) -> loop (ListLit t as₁)+ where+ as₁ = Data.Sequence.mapWithIndex adapt as₀++ _A₂ = Record (Dhall.Map.fromList kts)+ where+ kts = [ ("index", Syntax.makeRecordField Natural)+ , ("value", Syntax.makeRecordField _A₀)+ ]++ t | null as₀ = Just (App List _A₂)+ | otherwise = Nothing++ adapt n a_ =+ RecordLit (Dhall.Map.fromList kvs)+ where+ kvs = [ ("index", Syntax.makeRecordField $ NaturalLit (fromIntegral n))+ , ("value", Syntax.makeRecordField a_)+ ]+ App (App ListReverse _) (ListLit t xs) ->+ loop (ListLit t (Data.Sequence.reverse xs))+ App TextShow (TextLit (Chunks [] oldText)) ->+ loop (TextLit (Chunks [] newText))+ where+ newText = Eval.textShow oldText+ App+ (App (App TextReplace (TextLit (Chunks [] ""))) _)+ haystack ->+ return haystack+ App (App+ (App TextReplace (TextLit (Chunks [] needleText)))+ (TextLit (Chunks [] replacementText))+ )+ (TextLit (Chunks xys z)) -> do+ let xys' = do+ (x, y) <- xys++ let x' = Text.replace needleText replacementText x+ return (x', y)++ let z' = Text.replace needleText replacementText z++ return (TextLit (Chunks xys' z'))+ App (App+ (App TextReplace (TextLit (Chunks [] needleText)))+ replacement+ )+ (TextLit (Chunks [] lastText)) -> do+ let (prefix, suffix) =+ Text.breakOn needleText lastText++ if Text.null suffix+ then return (TextLit (Chunks [] lastText))+ else do+ let remainder =+ Text.drop+ (Text.length needleText)+ suffix++ loop (TextAppend (TextLit (Chunks [(prefix, replacement)] "")) (App (App (App TextReplace (TextLit (Chunks [] needleText))) replacement) (TextLit (Chunks [] remainder))))+ App (App+ (App TextReplace (TextLit (Chunks [] needleText)))+ replacement+ )+ (TextLit+ (Chunks+ ((firstText, firstInterpolation) : chunks)+ lastText+ )+ ) -> do+ let (prefix, suffix) =+ Text.breakOn needleText firstText++ if Text.null suffix+ then do+ loop (TextAppend (TextLit (Chunks [(firstText, firstInterpolation)] "")) (App (App (App TextReplace (TextLit (Chunks [] needleText))) replacement) (TextLit (Chunks chunks lastText))))+ else do+ let remainder =+ Text.drop+ (Text.length needleText)+ suffix++ loop (TextAppend (TextLit (Chunks [(prefix, replacement)] "")) (App (App (App TextReplace (TextLit (Chunks [] needleText))) replacement) (TextLit (Chunks ((remainder, firstInterpolation) : chunks) lastText))))+ App DateShow (DateLiteral date) ->+ loop (TextLit (Chunks [] text))+ where+ text = Eval.dateShow date+ App TimeShow (TimeLiteral time precision) ->+ loop (TextLit (Chunks [] text))+ where+ text = Eval.timeShow time precision+ App TimeZoneShow (TimeZoneLiteral timezone) ->+ loop (TextLit (Chunks [] text))+ where+ text = Eval.timezoneShow timezone+ _ -> do+ res2 <- ctx (App f' a')+ case res2 of+ Nothing -> pure (App f' a')+ Just app' -> loop app'+ Let (Binding _ f _ _ _ r) b -> loop b''+ where+ r' = Syntax.shift 1 (V f 0) r+ b' = subst (V f 0) r' b+ b'' = Syntax.shift (-1) (V f 0) b'+ Annot x _ -> loop x+ Bool -> pure Bool+ BoolLit b -> pure (BoolLit b)+ BoolAnd x y -> decide <$> loop x <*> loop y+ where+ decide (BoolLit True ) r = r+ decide (BoolLit False) _ = BoolLit False+ decide l (BoolLit True ) = l+ decide _ (BoolLit False) = BoolLit False+ decide l r+ | Eval.judgmentallyEqual l r = l+ | otherwise = BoolAnd l r+ BoolOr x y -> decide <$> loop x <*> loop y+ where+ decide (BoolLit False) r = r+ decide (BoolLit True ) _ = BoolLit True+ decide l (BoolLit False) = l+ decide _ (BoolLit True ) = BoolLit True+ decide l r+ | Eval.judgmentallyEqual l r = l+ | otherwise = BoolOr l r+ BoolEQ x y -> decide <$> loop x <*> loop y+ where+ decide (BoolLit True ) r = r+ decide l (BoolLit True ) = l+ decide l r+ | Eval.judgmentallyEqual l r = BoolLit True+ | otherwise = BoolEQ l r+ BoolNE x y -> decide <$> loop x <*> loop y+ where+ decide (BoolLit False) r = r+ decide l (BoolLit False) = l+ decide l r+ | Eval.judgmentallyEqual l r = BoolLit False+ | otherwise = BoolNE l r+ BoolIf bool true false -> decide <$> loop bool <*> loop true <*> loop false+ where+ decide (BoolLit True ) l _ = l+ decide (BoolLit False) _ r = r+ decide b (BoolLit True) (BoolLit False) = b+ decide b l r+ | Eval.judgmentallyEqual l r = l+ | otherwise = BoolIf b l r+ Bytes -> pure Bytes+ BytesLit b -> pure (BytesLit b)+ Natural -> pure Natural+ NaturalLit n -> pure (NaturalLit n)+ NaturalFold -> pure NaturalFold+ NaturalBuild -> pure NaturalBuild+ NaturalIsZero -> pure NaturalIsZero+ NaturalEven -> pure NaturalEven+ NaturalOdd -> pure NaturalOdd+ NaturalToInteger -> pure NaturalToInteger+ NaturalShow -> pure NaturalShow+ NaturalSubtract -> pure NaturalSubtract+ NaturalPlus x y -> decide <$> loop x <*> loop y+ where+ decide (NaturalLit 0) r = r+ decide l (NaturalLit 0) = l+ decide (NaturalLit m) (NaturalLit n) = NaturalLit (m + n)+ decide l r = NaturalPlus l r+ NaturalTimes x y -> decide <$> loop x <*> loop y+ where+ decide (NaturalLit 1) r = r+ decide l (NaturalLit 1) = l+ decide (NaturalLit 0) _ = NaturalLit 0+ decide _ (NaturalLit 0) = NaturalLit 0+ decide (NaturalLit m) (NaturalLit n) = NaturalLit (m * n)+ decide l r = NaturalTimes l r+ Integer -> pure Integer+ IntegerLit n -> pure (IntegerLit n)+ IntegerClamp -> pure IntegerClamp+ IntegerNegate -> pure IntegerNegate+ IntegerShow -> pure IntegerShow+ IntegerToDouble -> pure IntegerToDouble+ Double -> pure Double+ DoubleLit n -> pure (DoubleLit n)+ DoubleShow -> pure DoubleShow+ Text -> pure Text+ TextLit (Chunks xys z) -> do+ chunks' <- mconcat <$> chunks+ case chunks' of+ Chunks [("", x)] "" -> pure x+ c -> pure (TextLit c)+ where+ chunks =+ ((++ [Chunks [] z]) . concat) <$> traverse process xys++ process (x, y) = do+ y' <- loop y+ case y' of+ TextLit c -> pure [Chunks [] x, c]+ _ -> pure [Chunks [(x, y')] mempty]+ TextAppend x y -> loop (TextLit (Chunks [("", x), ("", y)] ""))+ TextReplace -> pure TextReplace+ TextShow -> pure TextShow+ Date -> pure Date+ DateLiteral d -> pure (DateLiteral d)+ DateShow -> pure DateShow+ Time -> pure Time+ TimeLiteral t p -> pure (TimeLiteral t p)+ TimeShow -> pure TimeShow+ TimeZone -> pure TimeZone+ TimeZoneLiteral z -> pure (TimeZoneLiteral z)+ TimeZoneShow -> pure TimeZoneShow+ List -> pure List+ ListLit t es+ | Data.Sequence.null es -> ListLit <$> t' <*> pure Data.Sequence.empty+ | otherwise -> ListLit Nothing <$> es'+ where+ t' = traverse loop t+ es' = traverse loop es+ ListAppend x y -> decide <$> loop x <*> loop y+ where+ decide (ListLit _ m) r | Data.Sequence.null m = r+ decide l (ListLit _ n) | Data.Sequence.null n = l+ decide (ListLit t m) (ListLit _ n) = ListLit t (m <> n)+ decide l r = ListAppend l r+ ListBuild -> pure ListBuild+ ListFold -> pure ListFold+ ListLength -> pure ListLength+ ListHead -> pure ListHead+ ListLast -> pure ListLast+ ListIndexed -> pure ListIndexed+ ListReverse -> pure ListReverse+ Optional -> pure Optional+ Some a -> Some <$> a'+ where+ a' = loop a+ None -> pure None+ Record kts -> Record . Dhall.Map.sort <$> kts'+ where+ f (RecordField s0 expr s1 s2) = (\expr' -> RecordField s0 expr' s1 s2) <$> loop expr+ kts' = traverse f kts+ RecordLit kvs -> RecordLit . Dhall.Map.sort <$> kvs'+ where+ f (RecordField s0 expr s1 s2) = (\expr' -> RecordField s0 expr' s1 s2) <$> loop expr+ kvs' = traverse f kvs+ Union kts -> Union . Dhall.Map.sort <$> kts'+ where+ kts' = traverse (traverse loop) kts+ Combine cs mk x y -> decide <$> loop x <*> loop y+ where+ decide (RecordLit m) r | Data.Foldable.null m =+ r+ decide l (RecordLit n) | Data.Foldable.null n =+ l+ decide (RecordLit m) (RecordLit n) =+ RecordLit (Dhall.Map.unionWith f m n)+ where+ f (RecordField _ expr _ _) (RecordField _ expr' _ _) =+ Syntax.makeRecordField $ decide expr expr'+ decide l r =+ Combine cs mk l r+ CombineTypes cs x y -> decide <$> loop x <*> loop y+ where+ decide (Record m) r | Data.Foldable.null m =+ r+ decide l (Record n) | Data.Foldable.null n =+ l+ decide (Record m) (Record n) =+ Record (Dhall.Map.unionWith f m n)+ where+ f (RecordField _ expr _ _) (RecordField _ expr' _ _) =+ Syntax.makeRecordField $ decide expr expr'+ decide l r =+ CombineTypes cs l r+ Prefer cs _ x y -> decide <$> loop x <*> loop y+ where+ decide (RecordLit m) r | Data.Foldable.null m =+ r+ decide l (RecordLit n) | Data.Foldable.null n =+ l+ decide (RecordLit m) (RecordLit n) =+ RecordLit (Dhall.Map.union n m)+ decide l r | Eval.judgmentallyEqual l r =+ l+ decide l r =+ Prefer cs PreferFromSource l r+ RecordCompletion x y ->+ loop (Annot (Prefer mempty PreferFromCompletion (Field x def) y) (Field x typ))+ where+ def = Syntax.makeFieldSelection "default"+ typ = Syntax.makeFieldSelection "Type"+ Merge x y t -> do+ x' <- loop x+ y' <- loop y+ case x' of+ RecordLit kvsX ->+ case y' of+ Field (Union ktsY) (Syntax.fieldSelectionLabel -> kY) ->+ case Dhall.Map.lookup kY ktsY of+ Just Nothing ->+ case recordFieldValue <$> Dhall.Map.lookup kY kvsX of+ Just vX -> return vX+ Nothing -> Merge x' y' <$> t'+ _ ->+ Merge x' y' <$> t'+ App (Field (Union ktsY) (Syntax.fieldSelectionLabel -> kY)) vY ->+ case Dhall.Map.lookup kY ktsY of+ Just (Just _) ->+ case recordFieldValue <$> Dhall.Map.lookup kY kvsX of+ Just vX -> loop (App vX vY)+ Nothing -> Merge x' y' <$> t'+ _ ->+ Merge x' y' <$> t'+ Some a ->+ case recordFieldValue <$> Dhall.Map.lookup "Some" kvsX of+ Just vX -> loop (App vX a)+ Nothing -> Merge x' y' <$> t'+ App None _ ->+ case recordFieldValue <$> Dhall.Map.lookup "None" kvsX of+ Just vX -> return vX+ Nothing -> Merge x' y' <$> t'+ _ -> Merge x' y' <$> t'+ _ -> Merge x' y' <$> t'+ where+ t' = traverse loop t+ ToMap x t -> do+ x' <- loop x+ t' <- traverse loop t+ case x' of+ RecordLit kvsX -> do+ let entry (key, value) =+ RecordLit+ (Dhall.Map.fromList+ [ ("mapKey" , Syntax.makeRecordField $ TextLit (Chunks [] key))+ , ("mapValue", Syntax.makeRecordField value )+ ]+ )++ let keyValues = Data.Sequence.fromList (map entry (Dhall.Map.toList $ recordFieldValue <$> kvsX))++ let listType = case t' of+ Just _ | null keyValues ->+ t'+ _ ->+ Nothing++ return (ListLit listType keyValues)+ _ ->+ return (ToMap x' t')+ ShowConstructor x -> do+ x' <- loop x+ return $ case x' of+ Field (Union ktsY) (Syntax.fieldSelectionLabel -> kY) ->+ case Dhall.Map.lookup kY ktsY of+ Just Nothing -> TextLit (Chunks [] kY)+ _ -> ShowConstructor x'+ App (Field (Union ktsY) (Syntax.fieldSelectionLabel -> kY)) _ ->+ case Dhall.Map.lookup kY ktsY of+ Just (Just _) -> TextLit (Chunks [] kY)+ _ -> ShowConstructor x'+ Some _ ->+ TextLit (Chunks [] "Some")+ App None _ ->+ TextLit (Chunks [] "None")+ _ -> ShowConstructor x'+ Field r k@FieldSelection{fieldSelectionLabel = x} -> do+ let singletonRecordLit v = RecordLit (Dhall.Map.singleton x v)++ r' <- loop r+ case r' of+ RecordLit kvs ->+ case Dhall.Map.lookup x kvs of+ Just v -> pure $ recordFieldValue v+ Nothing -> Field <$> (RecordLit <$> traverse (Syntax.recordFieldExprs loop) kvs) <*> pure k+ Project r_ _ -> loop (Field r_ k)+ Prefer cs _ (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of+ Just v -> pure (Field (Prefer cs PreferFromSource (singletonRecordLit v) r_) k)+ Nothing -> loop (Field r_ k)+ Prefer _ _ l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of+ Just v -> pure $ recordFieldValue v+ Nothing -> loop (Field l k)+ Combine cs m (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of+ Just v -> pure (Field (Combine cs m (singletonRecordLit v) r_) k)+ Nothing -> loop (Field r_ k)+ Combine cs m l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of+ Just v -> pure (Field (Combine cs m l (singletonRecordLit v)) k)+ Nothing -> loop (Field l k)+ _ -> pure (Field r' k)+ Project x (Left fields)-> do+ x' <- loop x+ let fieldsSet = Data.Set.fromList fields+ case x' of+ RecordLit kvs ->+ pure (RecordLit (Dhall.Map.restrictKeys kvs fieldsSet))+ Project y _ ->+ loop (Project y (Left fields))+ Prefer cs _ l (RecordLit rKvs) -> do+ let rKs = Dhall.Map.keysSet rKvs+ let l' = Project l (Left (Data.Set.toList (Data.Set.difference fieldsSet rKs)))+ let r' = RecordLit (Dhall.Map.restrictKeys rKvs fieldsSet)+ loop (Prefer cs PreferFromSource l' r')+ _ | null fields -> pure (RecordLit mempty)+ | otherwise -> pure (Project x' (Left (Data.Set.toList (Data.Set.fromList fields))))+ Project r (Right e1) -> do+ e2 <- loop e1++ case e2 of+ Record kts ->+ loop (Project r (Left (Data.Set.toList (Dhall.Map.keysSet kts))))+ _ -> do+ r' <- loop r+ pure (Project r' (Right e2))+ Assert t -> do+ t' <- loop t++ pure (Assert t')+ Equivalent cs l r -> do+ l' <- loop l+ r' <- loop r++ pure (Equivalent cs l' r')+ With r ks v -> do+ r' <- loop r+ v' <- loop v++ case r' of+ RecordLit kvs ->+ case ks of+ WithLabel k :| [] ->+ return (RecordLit (Dhall.Map.insert k (Syntax.makeRecordField v') kvs))+ WithLabel k₀ :| k₁ : ks' -> do+ let e₁ =+ case Dhall.Map.lookup k₀ kvs of+ Nothing -> RecordLit mempty+ Just val -> Syntax.recordFieldValue val++ e₂ <- loop (With e₁ (k₁ :| ks') v')++ return (RecordLit (Dhall.Map.insert k₀ (Syntax.makeRecordField e₂) kvs))+ WithQuestion :| _ -> do+ return (With r' ks v')+ Some t ->+ case ks of+ WithQuestion :| [] -> do+ return (Some v')+ WithQuestion :| k : ks' -> do+ w <- loop (With t (k :| ks') v)+ return (Some w)+ WithLabel _ :| _ ->+ return (With r' ks v')+ App None _T ->+ case ks of+ WithQuestion :| _ ->+ return (App None _T)+ WithLabel _ :| _ ->+ return (With r' ks v')+ _ ->+ return (With r' ks v')+ Note _ e' -> loop e'+ ImportAlt l _r -> loop l+ Embed a -> pure (Embed a)++-- | Use this to wrap you embedded functions (see `normalizeWith`) to make them+-- polymorphic enough to be used.+type NormalizerM m a = forall s. Expr s a -> m (Maybe (Expr s a))++-- | An variation on `NormalizerM` for pure normalizers+type Normalizer a = NormalizerM Identity a++-- | A reified 'Normalizer', which can be stored in structures without+-- running into impredicative polymorphism.+newtype ReifiedNormalizer a = ReifiedNormalizer+ { getReifiedNormalizer :: Normalizer a }++-- | Check if an expression is in a normal form given a context of evaluation.+-- Unlike `isNormalized`, this will fully normalize and traverse through the expression.+--+-- It is much more efficient to use `isNormalized`.+--+-- `isNormalizedWith` can fail with an `error` if you check an ill-typed+-- expression+isNormalizedWith :: (Eq s, Eq a) => Normalizer a -> Expr s a -> Bool+isNormalizedWith ctx e = e == normalizeWith (Just (ReifiedNormalizer ctx)) e++-- | Quickly check if an expression is in normal form+--+-- Given a well-typed expression @e@, @'isNormalized' e@ is equivalent to+-- @e == 'normalize' e@.+--+-- Given an ill-typed expression, 'isNormalized' may fail with an error, or+-- evaluate to either False or True!+isNormalized :: Eq a => Expr s a -> Bool+isNormalized e0 = loop (Syntax.denote e0)+ where+ loop e = case e of+ Const _ -> True+ Var _ -> True+ Lam _ (FunctionBinding Nothing _ Nothing Nothing a) b -> loop a && loop b+ Lam _ _ _ -> False+ Pi _ _ a b -> loop a && loop b+ App f a -> loop f && loop a && case App f a of+ App (Lam _ _ _) _ -> False+ App (App (App (App NaturalFold (NaturalLit _)) _) _) _ -> False+ App NaturalBuild _ -> False+ App NaturalIsZero (NaturalLit _) -> False+ App NaturalEven (NaturalLit _) -> False+ App NaturalOdd (NaturalLit _) -> False+ App NaturalShow (NaturalLit _) -> False+ App DateShow (DateLiteral _) -> False+ App TimeShow (TimeLiteral _ _) -> False+ App TimeZoneShow (TimeZoneLiteral _) -> False+ App (App NaturalSubtract (NaturalLit _)) (NaturalLit _) -> False+ App (App NaturalSubtract (NaturalLit 0)) _ -> False+ App (App NaturalSubtract _) (NaturalLit 0) -> False+ App (App NaturalSubtract x) y -> not (Eval.judgmentallyEqual x y)+ App NaturalToInteger (NaturalLit _) -> False+ App IntegerNegate (IntegerLit _) -> False+ App IntegerClamp (IntegerLit _) -> False+ App IntegerShow (IntegerLit _) -> False+ App IntegerToDouble (IntegerLit _) -> False+ App DoubleShow (DoubleLit _) -> False+ App (App ListBuild _) _ -> False+ App (App (App (App (App (App ListFold _) (ListLit _ _)) _) _) _) _ -> False+ App (App ListLength _) (ListLit _ _) -> False+ App (App ListHead _) (ListLit _ _) -> False+ App (App ListLast _) (ListLit _ _) -> False+ App (App ListIndexed _) (ListLit _ _) -> False+ App (App ListReverse _) (ListLit _ _) -> False+ App TextShow (TextLit (Chunks [] _)) ->+ False+ App (App (App TextReplace (TextLit (Chunks [] ""))) _) _ ->+ False+ App (App (App TextReplace (TextLit (Chunks [] _))) _) (TextLit _) ->+ False+ _ -> True+ Let _ _ -> False+ Annot _ _ -> False+ Bool -> True+ BoolLit _ -> True+ BoolAnd x y -> loop x && loop y && decide x y+ where+ decide (BoolLit _) _ = False+ decide _ (BoolLit _) = False+ decide l r = not (Eval.judgmentallyEqual l r)+ BoolOr x y -> loop x && loop y && decide x y+ where+ decide (BoolLit _) _ = False+ decide _ (BoolLit _) = False+ decide l r = not (Eval.judgmentallyEqual l r)+ BoolEQ x y -> loop x && loop y && decide x y+ where+ decide (BoolLit True) _ = False+ decide _ (BoolLit True) = False+ decide l r = not (Eval.judgmentallyEqual l r)+ BoolNE x y -> loop x && loop y && decide x y+ where+ decide (BoolLit False) _ = False+ decide _ (BoolLit False ) = False+ decide l r = not (Eval.judgmentallyEqual l r)+ BoolIf x y z ->+ loop x && loop y && loop z && decide x y z+ where+ decide (BoolLit _) _ _ = False+ decide _ (BoolLit True) (BoolLit False) = False+ decide _ l r = not (Eval.judgmentallyEqual l r)+ Bytes -> True+ BytesLit _ -> True+ Natural -> True+ NaturalLit _ -> True+ NaturalFold -> True+ NaturalBuild -> True+ NaturalIsZero -> True+ NaturalEven -> True+ NaturalOdd -> True+ NaturalShow -> True+ NaturalSubtract -> True+ NaturalToInteger -> True+ NaturalPlus x y -> loop x && loop y && decide x y+ where+ decide (NaturalLit 0) _ = False+ decide _ (NaturalLit 0) = False+ decide (NaturalLit _) (NaturalLit _) = False+ decide _ _ = True+ NaturalTimes x y -> loop x && loop y && decide x y+ where+ decide (NaturalLit 0) _ = False+ decide _ (NaturalLit 0) = False+ decide (NaturalLit 1) _ = False+ decide _ (NaturalLit 1) = False+ decide (NaturalLit _) (NaturalLit _) = False+ decide _ _ = True+ Integer -> True+ IntegerLit _ -> True+ IntegerClamp -> True+ IntegerNegate -> True+ IntegerShow -> True+ IntegerToDouble -> True+ Double -> True+ DoubleLit _ -> True+ DoubleShow -> True+ Text -> True+ TextLit (Chunks [("", _)] "") -> False+ TextLit (Chunks xys _) -> all (all check) xys+ where+ check y = loop y && case y of+ TextLit _ -> False+ _ -> True+ TextAppend _ _ -> False+ TextReplace -> True+ TextShow -> True+ Date -> True+ DateLiteral _ -> True+ DateShow -> True+ Time -> True+ TimeLiteral _ _ -> True+ TimeShow -> True+ TimeZone -> True+ TimeZoneLiteral _ -> True+ TimeZoneShow -> True+ List -> True+ ListLit t es -> all loop t && all loop es+ ListAppend x y -> loop x && loop y && decide x y+ where+ decide (ListLit _ m) _ | Data.Sequence.null m = False+ decide _ (ListLit _ n) | Data.Sequence.null n = False+ decide (ListLit _ _) (ListLit _ _) = False+ decide _ _ = True+ ListBuild -> True+ ListFold -> True+ ListLength -> True+ ListHead -> True+ ListLast -> True+ ListIndexed -> True+ ListReverse -> True+ Optional -> True+ Some a -> loop a+ None -> True+ Record kts -> Dhall.Map.isSorted kts && all decide kts+ where+ decide (RecordField Nothing exp' Nothing Nothing) = loop exp'+ decide _ = False+ RecordLit kvs -> Dhall.Map.isSorted kvs && all decide kvs+ where+ decide (RecordField Nothing exp' Nothing Nothing) = loop exp'+ decide _ = False+ Union kts -> Dhall.Map.isSorted kts && all (all loop) kts+ Combine _ _ x y -> loop x && loop y && decide x y+ where+ decide (RecordLit m) _ | Data.Foldable.null m = False+ decide _ (RecordLit n) | Data.Foldable.null n = False+ decide (RecordLit _) (RecordLit _) = False+ decide _ _ = True+ CombineTypes _ x y -> loop x && loop y && decide x y+ where+ decide (Record m) _ | Data.Foldable.null m = False+ decide _ (Record n) | Data.Foldable.null n = False+ decide (Record _) (Record _) = False+ decide _ _ = True+ Prefer _ _ x y -> loop x && loop y && decide x y+ where+ decide (RecordLit m) _ | Data.Foldable.null m = False+ decide _ (RecordLit n) | Data.Foldable.null n = False+ decide (RecordLit _) (RecordLit _) = False+ decide l r = not (Eval.judgmentallyEqual l r)+ RecordCompletion _ _ -> False+ Merge x y t -> loop x && loop y && all loop t && case x of+ RecordLit _ -> case y of+ Field (Union _) _ -> False+ App (Field (Union _) _) _ -> False+ Some _ -> False+ App None _ -> False+ _ -> True+ _ -> True+ ToMap x t -> case x of+ RecordLit _ -> False+ _ -> loop x && all loop t+ ShowConstructor x -> loop x && case x of+ Field (Union kts) (Syntax.fieldSelectionLabel -> k) ->+ case Dhall.Map.lookup k kts of+ Just Nothing -> False+ _ -> True+ App (Field (Union kts) (Syntax.fieldSelectionLabel -> k)) _ ->+ case Dhall.Map.lookup k kts of+ Just (Just _) -> False+ _ -> True+ Some _ -> False+ App None _ -> False+ _ -> True+ Field r (FieldSelection Nothing k Nothing) -> case r of+ RecordLit _ -> False+ Project _ _ -> False+ Prefer _ _ (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r+ Prefer _ _ _ (RecordLit _) -> False+ Combine _ _ (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r+ Combine _ _ _ (RecordLit m) -> Dhall.Map.keys m == [k] && loop r+ _ -> loop r+ Field _ _ -> False+ Project r p -> loop r &&+ case p of+ Left s -> case r of+ RecordLit _ -> False+ Project _ _ -> False+ Prefer _ _ _ (RecordLit _) -> False+ _ -> not (null s) && Data.Set.toList (Data.Set.fromList s) == s+ Right e' -> case e' of+ Record _ -> False+ _ -> loop e'+ Assert t -> loop t+ Equivalent _ l r -> loop l && loop r+ With{} -> False+ Note _ e' -> loop e'+ ImportAlt _ _ -> False+ Embed _ -> True++{-| Detect if the given variable is free within the given expression++>>> "x" `freeIn` "x"+True+>>> "x" `freeIn` "y"+False+>>> "x" `freeIn` Lam mempty (Syntax.makeFunctionBinding "x" (Const Type)) "x"+False+-}+freeIn :: Eq a => Var -> Expr s a -> Bool+variable@(V var i) `freeIn` expression =+ subst variable (Var (V var (i + 1))) strippedExpression+ /= strippedExpression+ where+ denote' :: Expr t b -> Expr () b+ denote' = Syntax.denote++ strippedExpression = denote' expression+{-# INLINABLE freeIn #-}++{- $setup+>>> import Dhall.Syntax (Const(..))+-}
@@ -3,51 +3,83 @@ for convenience -} -module Dhall.Optics- ( -- * Utilities- rewriteOf+{-# LANGUAGE RankNTypes #-}++module Dhall.Optics {-# DEPRECATED "Use the definitions from Lens.Micro of the microlens package directly." #-}+ ( Optic+ , Optic'+ -- * Utilities+ , anyOf+ , rewriteOf , transformOf , rewriteMOf , transformMOf , mapMOf+ , cosmosOf+ , to+ , foldOf ) where -import Control.Applicative (WrappedMonad(..))-import Data.Profunctor.Unsafe ((#.))-import Lens.Family (ASetter, LensLike, over)+import Control.Applicative (Const (..), WrappedMonad (..))+import Data.Monoid (Any (..))+import Lens.Micro (ASetter, LensLike, Traversal, SimpleGetter)+import Lens.Micro.Internal ((#.)) +import qualified Lens.Micro++-- | Identical to @"Control.Lens.Getter".`Control.Lens.Getter.Getting`@+type Getting r s a = (a -> Const r a) -> s -> Const r s++-- | Identical to @"Control.Lens.Type".`Control.Lens.Type.Optic`@+type Optic p f s t a b = p a (f b) -> p s (f t)++-- | Identical to @"Control.Lens.Type".`Control.Lens.Type.Optic'`@+type Optic' p f s a = Optic p f s s a a++-- | Identical to @"Control.Lens".`Control.Lens.anyOf`@+anyOf :: Getting Any s a -> (a -> Bool) -> s -> Bool+anyOf = Lens.Micro.anyOf+{-# INLINE anyOf #-}+ -- | Identical to @"Control.Lens".`Control.Lens.rewriteOf`@ rewriteOf :: ASetter a b a b -> (b -> Maybe a) -> a -> b-rewriteOf l f = go- where- go = transformOf l (\x -> maybe x go (f x))+rewriteOf = Lens.Micro.rewriteOf {-# INLINE rewriteOf #-} -- | Identical to @"Control.Lens".`Control.Lens.transformOf`@ transformOf :: ASetter a b a b -> (b -> b) -> a -> b-transformOf l f = go- where- go = f . over l go+transformOf = Lens.Micro.transformOf {-# INLINE transformOf #-} -- | Identical to @"Control.Lens".`Control.Lens.rewriteMOf`@ rewriteMOf :: Monad m => LensLike (WrappedMonad m) a b a b -> (b -> m (Maybe a)) -> a -> m b-rewriteMOf l f = go- where- go = transformMOf l (\x -> f x >>= maybe (return x) go)+rewriteMOf = Lens.Micro.rewriteMOf {-# INLINE rewriteMOf #-} -- | Identical to @"Control.Lens".`Control.Lens.transformMOf`@ transformMOf :: Monad m => LensLike (WrappedMonad m) a b a b -> (b -> m b) -> a -> m b-transformMOf l f = go- where- go t = mapMOf l go t >>= f+transformMOf = Lens.Micro.transformMOf {-# INLINE transformMOf #-} -- | Identical to @"Control.Lens".`Control.Lens.mapMOf`@ mapMOf :: LensLike (WrappedMonad m) s t a b -> (a -> m b) -> s -> m t-mapMOf l cmd = unwrapMonad #. l (WrapMonad #. cmd)+mapMOf = Lens.Micro.mapMOf {-# INLINE mapMOf #-}++-- | Identical to @"Control.Lens.Plated".`Control.Lens.Plated.cosmosOf`@+cosmosOf :: Traversal s t s t -> Traversal s t s b+cosmosOf = Lens.Micro.cosmosOf+{-# INLINE cosmosOf #-}++-- | Identical to @"Control.Lens.Getter".`Control.Lens.Getter.to`@+to :: (s -> a) -> SimpleGetter s a+to = Lens.Micro.to+{-# INLINE to #-}++-- | Identical to @"Control.Lens.Fold".`Control.Lens.Fold.foldOf`@+foldOf :: Getting a s a -> s -> a+foldOf l = getConst #. l Const+{-# INLINE foldOf #-}
@@ -0,0 +1,297 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiWayIf #-}++-- | Create a package.dhall from files and directory contents.++module Dhall.Package+ ( Options+ , defaultOptions+ , characterSet+ , packageFileName+ , packagingMode+ , PackagingMode(..)+ , writePackage+ , getPackagePathAndContent+ , PackageError(..)+ ) where++import Control.Exception (Exception, throwIO)+import Control.Monad+import Data.List.NonEmpty (NonEmpty (..))+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Traversable (for)+import Dhall.Core+ ( Directory (..)+ , Expr (..)+ , File (..)+ , FilePrefix (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , RecordField (..)+ , makeRecordField+ )+import Dhall.Map (Map)+import qualified Dhall.Map as Map+import Dhall.Pretty (CharacterSet (..))+import qualified Dhall.Pretty+import Dhall.Util (_ERROR, renderExpression)+import Lens.Micro (Lens', lens)+import System.Directory+import System.FilePath++-- | Options for package creation.+data Options = Options+ { optionsCharacterSet :: CharacterSet+ , optionsPackageFileName :: String+ , optionsPackagingMode :: PackagingMode+ }++-- | The default options used for packaging.+--+-- The default values for the different settings are:+--+-- * The character set used is the one given by 'Dhall.Pretty.defaultCharacterSet'.+-- * The package file name is @package.dhall@.+-- * The packaging mode is 'OnlyThisPackage'.+defaultOptions :: Options+defaultOptions = Options+ { optionsCharacterSet = Dhall.Pretty.defaultCharacterSet+ , optionsPackageFileName = "package.dhall"+ , optionsPackagingMode = OnlyThisPackage+ }++-- | Access the character set used to render the package content.+characterSet :: Lens' Options CharacterSet+characterSet = lens optionsCharacterSet (\s x -> s { optionsCharacterSet = x })++-- | Access the file name used for the package file.+packageFileName :: Lens' Options String+packageFileName =+ lens optionsPackageFileName (\s x -> s { optionsPackageFileName = x })++-- | Access the packaging mode.+-- See the documentation of 'getPackagePathAndContent'.+packagingMode :: Lens' Options PackagingMode+packagingMode =+ lens optionsPackagingMode (\s x -> s { optionsPackagingMode = x })++-- | Whether to recursively create a package for each subdirectory or not.+-- See the documentation of 'getPackagePathAndContent'.+data PackagingMode+ = OnlyThisPackage+ | RecursiveSubpackages++-- | Create a package.dhall from files and directory contents.+-- For a description of how the package file is constructed see+-- 'getPackagePathAndContent'.+writePackage :: Options -> NonEmpty FilePath -> IO ()+writePackage options inputs = do+ (outputPath, expr) <- getPackagePathAndContent options inputs+ renderExpression (optionsCharacterSet options) True (Just outputPath) expr++-- | Get the path and the Dhall expression for a package file.+--+-- The location of the resulting package file is determined by the first path of the second argument:+--+-- * If it is a directory, it is also the output directory and the package+-- file will be placed there.+--+-- * If it is a file, then the directory that file resides in is the output+-- directory and the package file will be placed there.+--+-- All inputs provided as the second argument must be either in the output+-- directory or below it. They are processed depending on whether+-- the path points to a directory or a file:+--+-- * If the path points to a directory, all files with a @.dhall@ extensions+-- in that directory are included in the package.+--+-- If you passed `Recurse` to the this function, then in addition to these+-- files all subdirectories are traversed and a sub-package created for each+-- one. That sub-package will be included in the package too.+--+-- * If the path points to a regular file, it is included in the package+-- unless it is the path of the package file itself.+--+getPackagePathAndContent+ :: Options+ -> NonEmpty FilePath+ -> IO (FilePath, Expr s Import)+getPackagePathAndContent options (path :| paths) = do+ outputDir <- do+ isDirectory <- doesDirectoryExist path+ return $ if isDirectory then path else takeDirectory path+ outputDir' <- addTrailingPathSeparator <$> makeAbsolute (normalise outputDir)++ -- Check if the supplied @dir@ argument points to a filesystem entry below+ -- the output directory and return the path relative to the output directory.+ let checkOutputDir dir = do+ absoluteDir <- addTrailingPathSeparator <$> makeAbsolute (normalise dir)+ let relativeDir = makeRelative outputDir' absoluteDir+ unless (isRelative relativeDir) $+ throwIO $ AmbiguousOutputDirectory outputDir dir+ return relativeDir++ resultMap <- go Map.empty checkOutputDir (path:paths)+ return (outputDir </> outputFn, RecordLit $ Map.sort resultMap)+ where+ go+ :: Map Text (RecordField s Import)+ -> (FilePath -> IO FilePath)+ -> [FilePath]+ -> IO (Map Text (RecordField s Import))+ go !acc _checkOutputDir [] = return acc+ go !acc checkOutputDir (p:ps) = do+ isDirectory <- doesDirectoryExist p+ isFile <- doesFileExist p+ if | isDirectory -> do+ void $ checkOutputDir p+ entries <- listDirectory p+ (dhallFiles, subdirectories) <- foldMap+ ( \entry -> do+ let entry' = p </> entry+ isDirectoryEntry <- doesDirectoryExist entry'+ return $ if isDirectoryEntry+ then (mempty, [entry'])+ else if hasDhallExtension entry+ then ([entry'], mempty)+ else mempty+ ) entries+ subpackages <- case optionsPackagingMode options of+ RecursiveSubpackages ->+ for subdirectories $ \subdirectory -> do+ writePackage options (subdirectory :| [])+ return (subdirectory </> outputFn)+ OnlyThisPackage -> return []+ go acc checkOutputDir (dhallFiles <> subpackages <> ps)+ | isFile -> do+ dir <- checkOutputDir $ takeDirectory p++ let p' = normalise $ dir </> takeFileName p++ let resultMap = if p' == outputFn+ then Map.empty+ else filepathToMap outputFn p'++ acc' <- mergeMaps acc resultMap+ go acc' checkOutputDir ps+ | otherwise -> throwIO $ InvalidPath p++ hasDhallExtension :: FilePath -> Bool+ hasDhallExtension entry = takeExtension entry == ".dhall"++ outputFn :: String+ outputFn = optionsPackageFileName options++-- | Construct a nested 'Map' from a 'FilePath'.+-- For example, the filepath @some/file/path.dhall@ will result in something+-- similar to the following:+--+-- fromList+-- [ ("some", fromList+-- [ ("file", fromList+-- [ ("path", ./some/file/path.dhall)+-- ])+-- ])+-- ])+--+-- ... where ./some/file/path.dhall is a Dhall import. If the last component+-- equals the value passed in the @outputFn@ argument we produce a slightly+-- different result. Consider for example the Dhall Prelude: We have some+-- sub-packages there like @List/package.dhall@. If we want to construct the+-- top-level @package.dhall@ we want an entry like+--+-- > List = ./List/package.dhall+--+-- in there and not:+--+-- > List = { package = ./List/package.dhall }+--+filepathToMap :: FilePath -> FilePath -> Map Text (RecordField s Import)+filepathToMap outputFn = go [] . splitDirectories+ where+ go acc [] = go acc ["."]+ go !acc [x] =+ let import_ = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here File+ { directory = Directory acc+ , file = Text.pack x+ }+ }+ , importMode = Code+ }+ in Map.singleton (Text.pack $ dropExtension x) $ makeRecordField $ Embed import_+ go !acc [x, y] | y == outputFn =+ let import_ = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here File+ { directory = Directory (Text.pack x : acc)+ , file = Text.pack y+ }+ }+ , importMode = Code+ }+ in Map.singleton (Text.pack x) $ makeRecordField $ Embed import_+ go !acc (x:xs) = Map.singleton (Text.pack x) $ makeRecordField $ RecordLit $ go (Text.pack x : acc) xs++-- | Merge two 'Map's constructed with 'filepathToMap'.+-- It will throw an error if the arguments are not compatible with each other, e.g.+-- we cannot merge the following two maps:+--+-- > fromList [ ("file", ./file.dhall) ]+-- > fromList [ ("file", fromList [("nested", ./file/nested.dhall)]) ]+--+mergeMaps :: Map Text (RecordField s Import) -> Map Text (RecordField s Import) -> IO (Map Text (RecordField s Import))+mergeMaps x y = do+ let x' = fmap (:| []) x+ y' = fmap (:| []) y+ z = Map.unionWith (<>) x' y'+ for z $ \case+ v@RecordField{recordFieldValue = Embed{}} :| [] -> return v+ vs | Just rs <- traverse extractRecordLit vs -> makeRecordField . RecordLit . Map.sort <$> foldM mergeMaps Map.empty rs+ | otherwise -> throwIO $ IncompatiblePaths $ foldMap extractEmbeds vs+ where+ extractEmbeds :: RecordField s Import -> [Import]+ extractEmbeds RecordField{recordFieldValue = Embed import_} = [import_]+ extractEmbeds RecordField{recordFieldValue = RecordLit xs} = foldMap extractEmbeds xs+ extractEmbeds _ = mempty++ extractRecordLit :: RecordField s Import -> Maybe (Map Text (RecordField s Import))+ extractRecordLit RecordField{recordFieldValue = RecordLit xs} = Just xs+ extractRecordLit _ = Nothing++-- | Exception thrown when creating a package file.+data PackageError+ = AmbiguousOutputDirectory FilePath FilePath+ | IncompatiblePaths [Import]+ | InvalidPath FilePath++instance Exception PackageError++instance Show PackageError where+ show (AmbiguousOutputDirectory dir1 dir2) =+ _ERROR <> ": ❰dhall package❱ failed because the inputs make it impossible to\n\+ \determine the output directory of the package file. You asked to include files\n\+ \from the following directories in the package:\n\+ \\n" <> dir1 <>+ "\n" <> dir2 <>+ "\n\n\+ \Although those paths might point to the same location they are not lexically the\n\+ \same."++ show (IncompatiblePaths imports) =+ _ERROR <> ": ❰dhall package❱ failed because some inputs are not compatible with\n\+ \each other:\n\+ \\n" <> unlines (map (show . Dhall.Pretty.prettyExpr . Embed) imports)++ show (InvalidPath fp) =+ _ERROR <> ": ❰dhall package❱ failed because the input does not exist or is\n\+ \neither a directory nor a regular file:\n\+ \\n" <> fp
@@ -1,5 +1,5 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} -- | This module contains Dhall's parsing logic @@ -7,31 +7,35 @@ -- * Utilities exprFromText , exprAndHeaderFromText+ , censor+ , createHeader -- * Parsers , expr, exprA -- * Types+ , Header(..) , Src(..) , SourcedException(..) , ParseError(..) , Parser(..) ) where -import Control.Exception (Exception)-import Data.Semigroup (Semigroup(..))-import Data.Text (Text)-import Data.Void (Void)-import Dhall.Core-import Dhall.Src (Src(..))-import Prelude hiding (const, pi)+import Control.Applicative (many)+import Control.Exception (Exception)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Src (Src (..))+import Dhall.Syntax+import Text.Megaparsec (ParseErrorBundle (..), PosState (..)) -import qualified Data.Text+import qualified Data.Text as Text+import qualified Dhall.Core as Core import qualified Text.Megaparsec import Dhall.Parser.Combinators-import Dhall.Parser.Token import Dhall.Parser.Expression+import Dhall.Parser.Token hiding (text) -- | Parser for a top-level Dhall expression expr :: Parser (Expr Src Import)@@ -41,28 +45,39 @@ -- over any parseable type, allowing the language to be extended as needed. exprA :: Parser a -> Parser (Expr Src a) exprA = completeExpression+{-# DEPRECATED exprA "Support for parsing custom imports will be dropped in a future release" #-} -- | A parsing error-data ParseError = ParseError-#if MIN_VERSION_megaparsec(7, 0, 0)- { unwrap :: Text.Megaparsec.ParseErrorBundle Text Void-#else- { unwrap :: Text.Megaparsec.ParseError Char Void-#endif+data ParseError = ParseError {+ unwrap :: Text.Megaparsec.ParseErrorBundle Text Void , input :: Text } +{-| Replace the source code with spaces when rendering error messages++ This utility is used to implement the @--censor@ flag+-}+censor :: ParseError -> ParseError+censor parseError =+ parseError+ { unwrap =+ (unwrap parseError)+ { bundlePosState =+ (bundlePosState (unwrap parseError))+ { pstateInput =+ Core.censorText+ (pstateInput (bundlePosState (unwrap parseError)))+ }+ }+ }+ instance Show ParseError where show (ParseError {..}) =-#if MIN_VERSION_megaparsec(7, 0, 0) "\n\ESC[1;31mError\ESC[0m: Invalid input\n\n" <> Text.Megaparsec.errorBundlePretty unwrap-#else- "\n\ESC[1;31mError\ESC[0m: Invalid input\n\n" <> Text.Megaparsec.parseErrorPretty unwrap-#endif instance Exception ParseError --- | Parse an expression from `Text` containing a Dhall program+-- | Parse an expression from `Text.Text` containing a Dhall program exprFromText :: String -- ^ User-friendly name describing the input expression, -- used in parsing error messages@@ -70,29 +85,46 @@ -> Either ParseError (Expr Src Import) exprFromText delta text = fmap snd (exprAndHeaderFromText delta text) -{-| Like `exprFromText` but also returns the leading comments and whitespace- (i.e. header) up to the last newline before the code begins+-- | A header corresponds to the leading comment at the top of a Dhall file.+--+-- The header includes comment characters but is stripped of leading spaces and+-- trailing newlines+newtype Header = Header Text deriving Show - In other words, if you have a Dhall file of the form:+-- | Create a header with stripped leading spaces and trailing newlines+createHeader :: Text -> Header+createHeader text = Header (prefix <> newSuffix)+ where+ isWhitespace c = c == ' ' || c == '\n' || c == '\r' || c == '\t' -> -- Comment 1-> {- Comment -} 2+ prefix = Text.dropAround isWhitespace text - Then this will preserve @Comment 1@, but not @Comment 2@+ newSuffix+ | Text.null prefix = ""+ | otherwise = "\n" - This is used by @dhall-format@ to preserve leading comments and whitespace--}+-- | Like `exprFromText` but also returns the leading comments and whitespace+-- (i.e. header) up to the last newline before the code begins+--+-- In other words, if you have a Dhall file of the form:+--+-- > -- Comment 1+-- > {- Comment -} 2+--+-- Then this will preserve @Comment 1@, but not @Comment 2@+--+-- This is used by @dhall-format@ to preserve leading comments and whitespace exprAndHeaderFromText :: String -- ^ User-friendly name describing the input expression, -- used in parsing error messages -> Text -- ^ Input expression to parse- -> Either ParseError (Text, Expr Src Import)+ -> Either ParseError (Header, Expr Src Import) exprAndHeaderFromText delta text = case result of Left errInfo -> Left (ParseError { unwrap = errInfo, input = text })- Right (txt, r) -> Right (Data.Text.dropWhileEnd (/= '\n') txt, r)+ Right (txt, r) -> Right (createHeader txt, r) where parser = do- (bytes, _) <- Text.Megaparsec.match whitespace+ (bytes, _) <- Text.Megaparsec.match (many shebang *> whitespace) r <- expr Text.Megaparsec.eof return (bytes, r)
@@ -1,45 +1,53 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}-module Dhall.Parser.Combinators where +{-| This module contains Dhall's parser combinators+-} -import Control.Applicative (Alternative (..), liftA2)-import Control.Exception (Exception)-import Control.Monad (MonadPlus (..))-import Data.Semigroup (Semigroup (..))-import Data.Sequence (ViewL (..))-import Data.String (IsString (..))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Pretty (..))-import Data.Void (Void)-import Dhall.Map (Map)-import Dhall.Set (Set)-import Dhall.Src (Src(..))-import Prelude hiding (const, pi)-import Text.Parser.Combinators (try, (<?>))-import Text.Parser.Token (TokenParsing (..))+module Dhall.Parser.Combinators+ ( Parser(..)+ , SourcedException(..)+ , laxSrcEq+ , count+ , range+ , option+ , star+ , plus+ , satisfy+ , Dhall.Parser.Combinators.takeWhile+ , takeWhile1+ , toMap+ , toMapWith+ , base+ ) where ++import Control.Applicative (Alternative (..), liftA2)+import Control.Exception (Exception)+import Control.Monad (MonadPlus (..))+import Data.String (IsString (..))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Map (Map)+import Dhall.Src (Src (..))+import Prettyprinter (Pretty (..))+import Text.Parser.Combinators (try, (<?>))+import Text.Parser.Token (TokenParsing (..))+ import qualified Control.Monad.Fail-import qualified Data.Char-import qualified Data.Sequence-import qualified Data.Set+import qualified Data.Char as Char import qualified Data.Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty import qualified Dhall.Map import qualified Dhall.Pretty-import qualified Dhall.Set+import qualified Prettyprinter.Render.String as Pretty import qualified Text.Megaparsec-#if !MIN_VERSION_megaparsec(7, 0, 0)-import qualified Text.Megaparsec.Char as Text.Megaparsec (satisfy)-#endif import qualified Text.Megaparsec.Char import qualified Text.Parser.Char import qualified Text.Parser.Combinators import qualified Text.Parser.Token.Style +-- | An exception annotated with a `Src` span data SourcedException e = SourcedException Src e instance Exception e => Exception (SourcedException e)@@ -50,11 +58,11 @@ <> "\n" <> "\n" <> Pretty.renderString- (Pretty.layoutPretty Dhall.Pretty.layoutOpts (pretty source))+ (Dhall.Pretty.layout (pretty source)) --- | Doesn't force the 'Text' part+-- | Doesn't force the 'Data.Text.Text' part laxSrcEq :: Src -> Src -> Bool-laxSrcEq (Src p q _) (Src p' q' _) = eq p p' && eq q q'+laxSrcEq (Src p q _) (Src p' q' _) = eq p p' && eq q q' where -- Don't compare filename (which is FilePath = String) eq :: Text.Megaparsec.SourcePos -> Text.Megaparsec.SourcePos -> Bool@@ -128,9 +136,7 @@ -- {-# INLINE mplus #-} instance Text.Megaparsec.MonadParsec Void Text Parser where- failure u e = Parser (Text.Megaparsec.failure u e)-- fancyFailure e = Parser (Text.Megaparsec.fancyFailure e)+ parseError e = Parser (Text.Megaparsec.parseError e) label l (Parser p) = Parser (Text.Megaparsec.label l p) @@ -163,16 +169,16 @@ updateParserState f = Parser (Text.Megaparsec.updateParserState f) -instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Parser a) where+#if MIN_VERSION_megaparsec(9,4,0)+ mkParsec f = Parser (Text.Megaparsec.mkParsec f)+#endif++instance Semigroup a => Semigroup (Parser a) where (<>) = liftA2 (<>) -instance (Data.Semigroup.Semigroup a, Monoid a) => Monoid (Parser a) where+instance (Semigroup a, Monoid a) => Monoid (Parser a) where mempty = pure mempty -#if !(MIN_VERSION_base(4,11,0))- mappend = (<>)-#endif- instance IsString a => IsString (Parser a) where fromString x = fromString x <$ Text.Megaparsec.Char.string (fromString x) @@ -198,11 +204,7 @@ notChar = Text.Megaparsec.Char.char -#if MIN_VERSION_megaparsec(7, 0, 0) anyChar = Text.Megaparsec.anySingle-#else- anyChar = Text.Megaparsec.Char.anyChar-#endif string = fmap Data.Text.unpack . Text.Megaparsec.Char.string . fromString @@ -211,16 +213,18 @@ instance TokenParsing Parser where someSpace = Text.Parser.Token.Style.buildSomeSpaceParser- (Parser (Text.Megaparsec.skipSome (Text.Megaparsec.satisfy Data.Char.isSpace)))+ (Parser (Text.Megaparsec.skipSome (Text.Megaparsec.satisfy Char.isSpace))) Text.Parser.Token.Style.haskellCommentStyle highlight _ = id semi = token (Text.Megaparsec.Char.char ';' <?> ";") +-- | @count n p@ parses @n@ occurrences of @p@ count :: (Semigroup a, Monoid a) => Int -> Parser a -> Parser a count n parser = mconcat (replicate n parser) +-- | @range lo hi p@ parses @n@ ocurrences of @p@ where @lo <= n <= hi@ range :: (Semigroup a, Monoid a) => Int -> Int -> Parser a -> Parser a range minimumBound maximumMatches parser = count minimumBound parser <> loop maximumMatches@@ -228,47 +232,61 @@ loop 0 = mempty loop n = (parser <> loop (n - 1)) <|> mempty +-- | @option p@ tries to apply parser @p@ returning @mempty@ if parsing failed option :: (Alternative f, Monoid a) => f a -> f a option p = p <|> pure mempty +-- | @star p@ tries to apply a parser @0@ or more times star :: (Alternative f, Monoid a) => f a -> f a star p = plus p <|> pure mempty +-- | @plus p@ tries to apply a parser @1@ or more times plus :: (Alternative f, Monoid a) => f a -> f a plus p = mappend <$> p <*> star p +-- | @satisfy p@ creates a parser that consumes and return the next character+-- if it satisfies the predicate @p@ satisfy :: (Char -> Bool) -> Parser Text satisfy = fmap Data.Text.singleton . Text.Parser.Char.satisfy +-- | @takeWhile p@ creates a parser that accepts the longest sequence of characters+-- that match the given predicate possibly returning an empty sequence takeWhile :: (Char -> Bool) -> Parser Text takeWhile predicate = Parser (Text.Megaparsec.takeWhileP Nothing predicate) +-- | @takeWhile1 p@ creates a parser that accepts the longest sequence of characters+-- that match the given predicate. It fails when no character was consumed takeWhile1 :: (Char -> Bool) -> Parser Text takeWhile1 predicate = Parser (Text.Megaparsec.takeWhile1P Nothing predicate) -noDuplicates :: Ord a => [a] -> Parser (Set a)-noDuplicates = go Dhall.Set.empty+-- | Creates a map with the given key-value pairs, failing if there was a+-- duplicate key.+toMap :: [(Text, a)] -> Parser (Map Text a)+toMap kvs = Dhall.Map.unorderedTraverseWithKey (\_k v -> v) m where- go found [] = return found- go found (x:xs) =- if Data.Set.member x (Dhall.Set.toSet found)- then fail "Duplicate key"- else go (Dhall.Set.append x found) xs+ m = Dhall.Map.fromListWithKey err (map (\(k, v) -> (k, pure v)) kvs) -toMap :: [(Text, a)] -> Parser (Map Text a)-toMap kvs = do- let adapt (k, v) = (k, pure v)- let m = fromListWith (<|>) (fmap adapt kvs)- let action k vs = case Data.Sequence.viewl vs of- EmptyL -> empty- v :< vs' ->- if null vs'- then pure v- else- Text.Parser.Combinators.unexpected+ err k _v1 _v2 = Text.Parser.Combinators.unexpected ("duplicate field: " ++ Data.Text.unpack k)- Dhall.Map.traverseWithKey action m++-- | Creates a 'Map Text a' using the provided combining function and the+-- key-value pairs+toMapWith+ :: (Text -> Parser a -> Parser a -> Parser a)+ -> [(Text, a)]+ -> Parser (Map Text a)+toMapWith combine kvs = sequence m where- fromListWith combine = foldr cons mempty- where- cons (k, v) = Dhall.Map.insertWith combine k v+ m = Dhall.Map.fromListWithKey combine (map (\(k, v) -> (k, pure v)) kvs)++-- | Convert a list of digits to the equivalent number+base :: Num n => [Char] -> n -> n+digits `base` b = foldl snoc 0 (map (fromIntegral . digitToNumber) digits)+ where+ snoc result number = result * b + number++ digitToNumber c+ | '0' <= c && c <= '9' = 0x0 + Char.ord c - Char.ord '0'+ | 'A' <= c && c <= 'F' = 0xA + Char.ord c - Char.ord 'A'+ | 'a' <= c && c <= 'f' = 0xa + Char.ord c - Char.ord 'a'+ | otherwise = error "Invalid hexadecimal digit"
@@ -1,840 +1,1279 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE OverloadedLists #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}---- | Parsing Dhall expressions.-module Dhall.Parser.Expression where--import Control.Applicative (Alternative(..), optional)-import Data.ByteArray.Encoding (Base(..))-import Data.Functor (void)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Semigroup (Semigroup(..))-import Data.Text (Text)-import Dhall.Core-import Dhall.Src (Src(..))-import Prelude hiding (const, pi)-import Text.Parser.Combinators (choice, try, (<?>))--import qualified Crypto.Hash-import qualified Data.ByteArray.Encoding-import qualified Data.ByteString-import qualified Data.Char-import qualified Data.Foldable-import qualified Data.List.NonEmpty-import qualified Data.Sequence-import qualified Data.Text-import qualified Data.Text.Encoding-import qualified Text.Megaparsec-#if !MIN_VERSION_megaparsec(7, 0, 0)-import qualified Text.Megaparsec.Char as Text.Megaparsec-#endif-import qualified Text.Parser.Char--import Dhall.Parser.Combinators-import Dhall.Parser.Token--getSourcePos :: Text.Megaparsec.MonadParsec e s m =>- m Text.Megaparsec.SourcePos-getSourcePos =-#if MIN_VERSION_megaparsec(7, 0, 0)- Text.Megaparsec.getSourcePos-#else- Text.Megaparsec.getPosition-#endif-{-# INLINE getSourcePos #-}--getOffset :: Text.Megaparsec.MonadParsec e s m => m Int-#if MIN_VERSION_megaparsec(7, 0, 0)-getOffset = Text.Megaparsec.stateOffset <$> Text.Megaparsec.getParserState-#else-getOffset = Text.Megaparsec.stateTokensProcessed <$> Text.Megaparsec.getParserState-#endif-{-# INLINE getOffset #-}--setOffset :: Text.Megaparsec.MonadParsec e s m => Int -> m ()-#if MIN_VERSION_megaparsec(7, 0, 0)-setOffset o = Text.Megaparsec.updateParserState $ \(Text.Megaparsec.State s _ pst) ->- Text.Megaparsec.State s o pst-#else-setOffset o = Text.Megaparsec.updateParserState $ \(Text.Megaparsec.State s p _ stw) ->- Text.Megaparsec.State s p o stw-#endif-{-# INLINE setOffset #-}--noted :: Parser (Expr Src a) -> Parser (Expr Src a)-noted parser = do- before <- getSourcePos- (tokens, e) <- Text.Megaparsec.match parser- after <- getSourcePos- let src₀ = Src before after tokens- case e of- Note src₁ _ | laxSrcEq src₀ src₁ -> return e- _ -> return (Note src₀ e)--shallowDenote :: Expr s a -> Expr s a-shallowDenote (Note _ e) = shallowDenote e-shallowDenote e = e--completeExpression :: Parser a -> Parser (Expr Src a)-completeExpression embedded = completeExpression_- where- completeExpression_ = do- whitespace- expression-- expression =- noted- ( choice- [ alternative0- , alternative1- , alternative2- , alternative3- , alternative4- ]- ) <?> "expression"- where- alternative0 = do- _lambda- _openParens- a <- label- _colon- b <- expression- _closeParens- _arrow- c <- expression- return (Lam a b c)-- alternative1 = do- _if- a <- expression- _then- b <- expression- _else- c <- expression- return (BoolIf a b c)-- alternative2 = do- let binding = do- _let-- c <- label- d <- optional (do- _colon- expression )-- _equal-- e <- expression-- return (Binding c d e)-- as <- Data.List.NonEmpty.some1 binding-- _in-- b <- expression-- return (Let as b)-- alternative3 = do- _forall- _openParens- a <- label- _colon- b <- expression- _closeParens- _arrow- c <- expression- return (Pi a b c)-- alternative4 = do- a <- operatorExpression-- let alternative4A = do- _arrow- b <- expression- return (Pi "_" a b)-- let alternative4B = do- _colon-- b <- expression-- case (shallowDenote a, shallowDenote b) of- (ListLit _ xs, App f c) ->- case shallowDenote f of- List -> case xs of- [] -> return (ListLit (Just c) xs)- _ -> return (Annot a b)- Optional -> case xs of- [x] -> return (OptionalLit c (Just x))- [] -> return (OptionalLit c Nothing)- _ -> return (Annot a b)- _ ->- return (Annot a b)- (Merge c d _, e) ->- return (Merge c d (Just e))- _ -> return (Annot a b)-- alternative4A <|> alternative4B <|> pure a-- operatorExpression = precedence0Expression-- makeOperatorExpression subExpression operatorParser =- noted (do- a <- subExpression- b <- Text.Megaparsec.many $ do- op <- operatorParser- r <- subExpression-- return (\l -> l `op` r)- return (foldl (\x f -> f x) a b) )-- precedence0Operator =- ImportAlt <$ _importAlt- <|> BoolOr <$ _or- <|> TextAppend <$ _textAppend- <|> NaturalPlus <$ _plus- <|> ListAppend <$ _listAppend-- precedence1Operator =- BoolAnd <$ _and- <|> Combine <$ _combine-- precedence2Operator =- CombineTypes <$ _combineTypes- <|> Prefer <$ _prefer- <|> NaturalTimes <$ _times- <|> BoolEQ <$ _doubleEqual-- precedence3Operator = BoolNE <$ _notEqual-- precedence0Expression =- makeOperatorExpression precedence1Expression precedence0Operator-- precedence1Expression =- makeOperatorExpression precedence2Expression precedence1Operator-- precedence2Expression =- makeOperatorExpression precedence3Expression precedence2Operator-- precedence3Expression =- makeOperatorExpression applicationExpression precedence3Operator-- applicationExpression = do- f <- (do _Some; return Some)- <|> return id- a <- noted importExpression- b <- Text.Megaparsec.many (noted importExpression)- return (foldl app (f a) b)- where- app nL@(Note (Src before _ bytesL) _) nR@(Note (Src _ after bytesR) _) =- Note (Src before after (bytesL <> bytesR)) (App nL nR)- app nL nR =- App nL nR-- importExpression = noted (choice [ alternative0, alternative1 ])- where- alternative0 = do- a <- embedded- return (Embed a)-- alternative1 = selectorExpression-- selectorExpression = noted (do- a <- primitiveExpression-- let recordType = _openParens *> expression <* _closeParens-- let field x e = Field e x- let projectBySet xs e = Project e (Left xs)- let projectByExpression xs e = Project e (Right xs)-- let alternatives =- fmap field anyLabel- <|> fmap projectBySet labels- <|> fmap projectByExpression recordType-- b <- Text.Megaparsec.many (try (do _dot; alternatives))- return (foldl (\e k -> k e) a b) )-- primitiveExpression =- noted- ( choice- [ alternative00- , alternative01- , alternative02- , alternative03- , alternative04- , alternative05- , alternative06- , alternative07- , alternative37- , alternative09-- , builtin <?> "built-in expression"- ]- )- <|> alternative38- where- alternative00 = do- n <- getOffset- a <- try doubleLiteral- b <- if isInfinite a- then setOffset n *> fail "double out of bounds"- else return a- return (DoubleLit b)-- alternative01 = do- a <- try naturalLiteral- return (NaturalLit a)-- alternative02 = do- a <- try integerLiteral- return (IntegerLit a)-- alternative03 = textLiteral-- alternative04 = (do- _openBrace- a <- recordTypeOrLiteral- _closeBrace- return a ) <?> "record type or literal"-- alternative05 = (do- _openAngle- a <- unionTypeOrLiteral- _closeAngle- return a ) <?> "union type or literal"-- alternative06 = listLiteral-- alternative07 = do- _merge- a <- importExpression- b <- importExpression- return (Merge a b Nothing)-- alternative09 = do- a <- try doubleInfinity- return (DoubleLit a)-- builtin = do- let predicate c =- c == 'N'- || c == 'I'- || c == 'D'- || c == 'L'- || c == 'O'- || c == 'B'- || c == 'S'- || c == 'T'- || c == 'F'- || c == 'K'-- let nan = (0.0/0.0)-- c <- Text.Megaparsec.lookAhead (Text.Megaparsec.satisfy predicate)-- case c of- 'N' ->- choice- [ NaturalFold <$ _NaturalFold- , NaturalBuild <$ _NaturalBuild- , NaturalIsZero <$ _NaturalIsZero- , NaturalEven <$ _NaturalEven- , NaturalOdd <$ _NaturalOdd- , NaturalToInteger <$ _NaturalToInteger- , NaturalToInteger <$ _NaturalToInteger- , NaturalShow <$ _NaturalShow- , Natural <$ _Natural- , None <$ _None- , DoubleLit nan <$ _NaN- ]- 'I' ->- choice- [ IntegerShow <$ _IntegerShow- , IntegerToDouble <$ _IntegerToDouble- , Integer <$ _Integer- ]-- 'D' ->- choice- [ DoubleShow <$ _DoubleShow- , Double <$ _Double- ]- 'L' ->- choice- [ ListBuild <$ _ListBuild- , ListFold <$ _ListFold- , ListLength <$ _ListLength- , ListHead <$ _ListHead- , ListLast <$ _ListLast- , ListIndexed <$ _ListIndexed- , ListReverse <$ _ListReverse- , List <$ _List- ]- 'O' ->- choice- [ OptionalFold <$ _OptionalFold- , OptionalBuild <$ _OptionalBuild- , Optional <$ _Optional- ]- 'B' -> Bool <$ _Bool- 'S' -> Const Sort <$ _Sort- 'T' ->- choice- [ TextShow <$ _TextShow- , Text <$ _Text- , BoolLit True <$ _True- , Const Type <$ _Type- ]- 'F' -> BoolLit False <$ _False- 'K' -> Const Kind <$ _Kind- _ -> empty-- alternative37 = do- a <- identifier- return (Var a)-- alternative38 = do- _openParens- a <- expression- _closeParens- return a-- doubleQuotedChunk =- choice- [ interpolation- , unescapedCharacterFast- , unescapedCharacterSlow- , escapedCharacter- ]- where- interpolation = do- _ <- Text.Parser.Char.text "${"- e <- completeExpression_- _ <- Text.Parser.Char.char '}'- return (Chunks [(mempty, e)] mempty)-- unescapedCharacterFast = do- t <- Text.Megaparsec.takeWhile1P Nothing predicate- return (Chunks [] t)- where- predicate c =- ( ('\x20' <= c && c <= '\x21' )- || ('\x23' <= c && c <= '\x5B' )- || ('\x5D' <= c && c <= '\x10FFFF')- ) && c /= '$'-- unescapedCharacterSlow = do- _ <- Text.Parser.Char.char '$'- return (Chunks [] "$")-- escapedCharacter = do- _ <- Text.Parser.Char.char '\\'- c <- choice- [ quotationMark- , dollarSign- , backSlash- , forwardSlash- , backSpace- , formFeed- , lineFeed- , carriageReturn- , tab- , unicode- ]- return (Chunks [] (Data.Text.singleton c))- where- quotationMark = Text.Parser.Char.char '"'-- dollarSign = Text.Parser.Char.char '$'-- backSlash = Text.Parser.Char.char '\\'-- forwardSlash = Text.Parser.Char.char '/'-- backSpace = do _ <- Text.Parser.Char.char 'b'; return '\b'-- formFeed = do _ <- Text.Parser.Char.char 'f'; return '\f'-- lineFeed = do _ <- Text.Parser.Char.char 'n'; return '\n'-- carriageReturn = do _ <- Text.Parser.Char.char 'r'; return '\r'-- tab = do _ <- Text.Parser.Char.char 't'; return '\t'-- unicode = do- _ <- Text.Parser.Char.char 'u';- n0 <- hexNumber- n1 <- hexNumber- n2 <- hexNumber- n3 <- hexNumber- let n = ((n0 * 16 + n1) * 16 + n2) * 16 + n3- return (Data.Char.chr n)-- doubleQuotedLiteral = do- _ <- Text.Parser.Char.char '"'- chunks <- Text.Megaparsec.many doubleQuotedChunk- _ <- Text.Parser.Char.char '"'- return (mconcat chunks)-- singleQuoteContinue =- choice- [ escapeSingleQuotes- , interpolation- , escapeInterpolation- , endLiteral- , unescapedCharacterFast- , unescapedCharacterSlow- , tab- , endOfLine- ]- where- escapeSingleQuotes = do- _ <- "'''" :: Parser Text- b <- singleQuoteContinue- return ("''" <> b)-- interpolation = do- _ <- Text.Parser.Char.text "${"- a <- completeExpression_- _ <- Text.Parser.Char.char '}'- b <- singleQuoteContinue- return (Chunks [(mempty, a)] mempty <> b)-- escapeInterpolation = do- _ <- Text.Parser.Char.text "''${"- b <- singleQuoteContinue- return ("${" <> b)-- endLiteral = do- _ <- Text.Parser.Char.text "''"- return mempty-- unescapedCharacterFast = do- a <- Text.Megaparsec.takeWhile1P Nothing predicate- b <- singleQuoteContinue- return (Chunks [] a <> b)- where- predicate c =- ('\x20' <= c && c <= '\x10FFFF') && c /= '$' && c /= '\''-- unescapedCharacterSlow = do- a <- satisfy predicate- b <- singleQuoteContinue- return (Chunks [] a <> b)- where- predicate c = c == '$' || c == '\''-- endOfLine = do- a <- "\n" <|> "\r\n"- b <- singleQuoteContinue- return (Chunks [] a <> b)-- tab = do- _ <- Text.Parser.Char.char '\t'- b <- singleQuoteContinue- return ("\t" <> b)-- singleQuoteLiteral = do- _ <- Text.Parser.Char.text "''"- _ <- endOfLine- a <- singleQuoteContinue-- return (toDoubleQuoted a)- where- endOfLine =- void (Text.Parser.Char.char '\n' )- <|> void (Text.Parser.Char.text "\r\n")-- textLiteral = (do- literal <- doubleQuotedLiteral <|> singleQuoteLiteral- whitespace- return (TextLit literal) ) <?> "text literal"-- recordTypeOrLiteral =- choice- [ alternative0- , alternative1- , alternative2- ]- where- alternative0 = do- _equal- return (RecordLit mempty)-- alternative1 = nonEmptyRecordTypeOrLiteral-- alternative2 = return (Record mempty)-- nonEmptyRecordTypeOrLiteral = do- a <- anyLabel-- let nonEmptyRecordType = do- _colon- b <- expression- e <- Text.Megaparsec.many (do- _comma- c <- anyLabel- _colon- d <- expression- return (c, d) )- m <- toMap ((a, b) : e)- return (Record m)-- let nonEmptyRecordLiteral = do- _equal- b <- expression- e <- Text.Megaparsec.many (do- _comma- c <- anyLabel- _equal- d <- expression- return (c, d) )- m <- toMap ((a, b) : e)- return (RecordLit m)-- nonEmptyRecordType <|> nonEmptyRecordLiteral-- unionTypeOrLiteral =- nonEmptyUnionTypeOrLiteral- <|> return (Union mempty)-- nonEmptyUnionTypeOrLiteral = do- (f, kvs) <- loop- m <- toMap kvs- return (f m)- where- loop = do- a <- anyLabel-- let alternative0 = do- _equal- b <- expression- kvs <- Text.Megaparsec.many (do- _bar- c <- anyLabel- d <- optional (do _colon; expression)- return (c, d) )- return (UnionLit a b, kvs)-- let alternative1 = do- b <- optional (do _colon; expression)-- let alternative2 = do- _bar- (f, kvs) <- loop- return (f, (a, b):kvs)-- let alternative3 = return (Union, [(a, b)])-- alternative2 <|> alternative3-- alternative0 <|> alternative1-- listLiteral = (do- _openBracket- a <- Text.Megaparsec.sepBy expression _comma- _closeBracket- return (ListLit Nothing (Data.Sequence.fromList a)) ) <?> "list literal"--env :: Parser ImportType-env = do- _ <- Text.Parser.Char.text "env:"- a <- (alternative0 <|> alternative1)- whitespace- return (Env a)- where- alternative0 = bashEnvironmentVariable-- alternative1 = do- _ <- Text.Parser.Char.char '"'- a <- posixEnvironmentVariable- _ <- Text.Parser.Char.char '"'- return a--localRaw :: Parser ImportType-localRaw =- choice- [ parentPath- , herePath- , homePath- , try absolutePath- ]- where- parentPath = do- _ <- ".." :: Parser Text- file <- file_ FileComponent-- return (Local Parent file)-- herePath = do- _ <- "." :: Parser Text- file <- file_ FileComponent-- return (Local Here file)-- homePath = do- _ <- "~" :: Parser Text- file <- file_ FileComponent-- return (Local Home file)-- absolutePath = do- file <- file_ FileComponent-- return (Local Absolute file)--local :: Parser ImportType-local = do- a <- localRaw- whitespace- return a--http :: Parser ImportType-http = do- url <- httpRaw- whitespace- headers <- optional (do- _using- (completeExpression import_ <|> (_openParens *> completeExpression import_ <* _closeParens)) )- return (Remote (url { headers }))--missing :: Parser ImportType-missing = do- _missing- return Missing--importType_ :: Parser ImportType-importType_ = do- let predicate c =- c == '~' || c == '.' || c == '/' || c == 'h' || c == 'e' || c == 'm'-- _ <- Text.Megaparsec.lookAhead (Text.Megaparsec.satisfy predicate)-- choice [ local, http, env, missing ]--importHashed_ :: Parser ImportHashed-importHashed_ = do- importType <- importType_- hash <- optional importHash_- return (ImportHashed {..})- where- importHash_ = do- _ <- Text.Parser.Char.text "sha256:"- text <- count 64 (satisfy hexdig <?> "hex digit")- whitespace- let strictBytes16 = Data.Text.Encoding.encodeUtf8 text- strictBytes <- case Data.ByteArray.Encoding.convertFromBase Base16 strictBytes16 of- Left string -> fail string- Right strictBytes -> return (strictBytes :: Data.ByteString.ByteString)- case Crypto.Hash.digestFromByteString strictBytes of- Nothing -> fail "Invalid sha256 hash"- Just h -> pure h--import_ :: Parser Import-import_ = (do- importHashed <- importHashed_- importMode <- alternative <|> pure Code- return (Import {..}) ) <?> "import"- where- alternative = do- _as- _Text- return RawText---- | Similar to `Dhall.Core.renderChunks` except that this doesn't bother to--- render interpolated expressions to avoid a `Buildable a` constraint. The--- interpolated contents are not necessary for computing how much to dedent a--- multi-line string------ This also doesn't include the surrounding quotes since they would interfere--- with the whitespace detection-renderChunks :: Chunks s a -> Text-renderChunks (Chunks a b) = foldMap renderChunk a <> b- where- renderChunk :: (Text, Expr s a) -> Text- renderChunk (c, _) = c <> "${x}"--splitOn :: Text -> Text -> NonEmpty Text-splitOn needle haystack =- case Data.Text.splitOn needle haystack of- [] -> "" :| []- t : ts -> t :| ts--linesLiteral :: Chunks s a -> NonEmpty (Chunks s a)-linesLiteral (Chunks [] suffix) =- fmap (Chunks []) (splitOn "\n" suffix)-linesLiteral (Chunks ((prefix, interpolation) : pairs₀) suffix₀) =- foldr- Data.List.NonEmpty.cons- (Chunks ((lastLine, interpolation) : pairs₁) suffix₁ :| chunks)- (fmap (Chunks []) initLines)- where- splitLines = splitOn "\n" prefix-- initLines = Data.List.NonEmpty.init splitLines- lastLine = Data.List.NonEmpty.last splitLines-- Chunks pairs₁ suffix₁ :| chunks = linesLiteral (Chunks pairs₀ suffix₀)--unlinesLiteral :: NonEmpty (Chunks s a) -> Chunks s a-unlinesLiteral chunks =- Data.Foldable.fold (Data.List.NonEmpty.intersperse "\n" chunks)--emptyLine :: Chunks s a -> Bool-emptyLine (Chunks [] "" ) = True-emptyLine (Chunks [] "\r") = True -- So that `\r\n` is treated as a blank line-emptyLine _ = False--leadingSpaces :: Chunks s a -> Text-leadingSpaces chunks = Data.Text.takeWhile isSpace firstText- where- isSpace c = c == '\x20' || c == '\x09'-- firstText =- case chunks of- Chunks [] suffix -> suffix- Chunks ((prefix, _) : _ ) _ -> prefix--dropLiteral :: Int -> Chunks s a -> Chunks s a-dropLiteral n (Chunks [] suffix) =- Chunks [] (Data.Text.drop n suffix)-dropLiteral n (Chunks ((prefix, interpolation) : rest) suffix) =- Chunks ((Data.Text.drop n prefix, interpolation) : rest) suffix--toDoubleQuoted :: Chunks Src a -> Chunks Src a-toDoubleQuoted literal =- unlinesLiteral (fmap (dropLiteral indent) literals)- where- literals = linesLiteral literal-- sharedPrefix ab ac =- case Data.Text.commonPrefixes ab ac of- Just (a, _b, _c) -> a- Nothing -> ""-- -- The standard specifies to filter out blank lines for all lines *except*- -- for the last line- filteredLines = newInit <> pure oldLast- where- oldInit = Data.List.NonEmpty.init literals-- oldLast = Data.List.NonEmpty.last literals-- newInit = filter (not . emptyLine) oldInit-- longestSharedPrefix =- case filteredLines of- l : ls ->- Data.Foldable.foldl' sharedPrefix (leadingSpaces l) (fmap leadingSpaces ls)- [] ->- ""-- indent = Data.Text.length longestSharedPrefix+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Parsing Dhall expressions.+module Dhall.Parser.Expression where++import Control.Applicative (Alternative (..), liftA2, optional)+import Data.Foldable (foldl')+import Data.List.NonEmpty (NonEmpty (..))+import Data.Text (Text)+import Dhall.Src (Src (..))+import Dhall.Syntax+import Text.Parser.Combinators (choice, try, (<?>))++import qualified Control.Monad+import qualified Control.Monad.Combinators as Combinators+import qualified Control.Monad.Combinators.NonEmpty as Combinators.NonEmpty+import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Base16 as Base16+import qualified Data.Char as Char+import qualified Data.List+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Sequence+import qualified Data.Text+import qualified Data.Text.Encoding+import qualified Data.Time as Time+import qualified Dhall.Crypto+import qualified Text.Megaparsec++import Dhall.Parser.Combinators+import Dhall.Parser.Token++-- | Get the current source offset (in tokens)+getOffset :: Text.Megaparsec.MonadParsec e s m => m Int+getOffset = Text.Megaparsec.stateOffset <$> Text.Megaparsec.getParserState+{-# INLINE getOffset #-}++-- | Set the current source offset+setOffset :: Text.Megaparsec.MonadParsec e s m => Int -> m ()+setOffset o = Text.Megaparsec.updateParserState $ \state ->+ state+ { Text.Megaparsec.stateOffset = o }+{-# INLINE setOffset #-}++{-| Wrap a `Parser` to still match the same text but return only the `Src`+ span+-}+src :: Parser a -> Parser Src+src parser = do+ before <- Text.Megaparsec.getSourcePos+ (tokens, _) <- Text.Megaparsec.match parser+ after <- Text.Megaparsec.getSourcePos+ return (Src before after tokens)++-- | Same as `src`, except also return the parsed value+srcAnd :: Parser a -> Parser (Src, a)+srcAnd parser = do+ before <- Text.Megaparsec.getSourcePos+ (tokens, x) <- Text.Megaparsec.match parser+ after <- Text.Megaparsec.getSourcePos+ return (Src before after tokens, x)++{-| Wrap a `Parser` to still match the same text, but to wrap the resulting+ `Expr` in a `Note` constructor containing the `Src` span+-}+noted :: Parser (Expr Src a) -> Parser (Expr Src a)+noted parser = do+ before <- Text.Megaparsec.getSourcePos+ (tokens, e) <- Text.Megaparsec.match parser+ after <- Text.Megaparsec.getSourcePos+ let src₀ = Src before after tokens+ case e of+ Note src₁ _ | laxSrcEq src₀ src₁ -> return e+ _ -> return (Note src₀ e)++{-| Parse a complete expression (with leading and trailing whitespace)++ This corresponds to the @complete-expression@ rule from the official+ grammar+-}+completeExpression :: Parser a -> Parser (Expr Src a)+completeExpression embedded = completeExpression_+ where+ Parsers {..} = parsers embedded++{-| Parse an \"import expression\"++ This is not the same thing as @`fmap` `Embed`@. This parses any+ expression of the same or higher precedence as an import expression (such+ as a selector expression). For example, this parses @(1)@++ This corresponds to the @import-expression@ rule from the official grammar+-}+importExpression :: Parser a -> Parser (Expr Src a)+importExpression embedded = importExpression_+ where+ Parsers {..} = parsers embedded++{-| For efficiency (and simplicity) we only expose two parsers from the+ result of the `parsers` function, since these are the only parsers needed+ outside of this module+-}+data Parsers a = Parsers+ { completeExpression_ :: Parser (Expr Src a)+ , importExpression_ :: Parser (Expr Src a)+ , letBinding :: Parser (Binding Src a)+ }++{-| Parse a numeric `TimeZone`++ This corresponds to the @time-numoffset@ rule from the official grammar+-}+timeNumOffset :: Parser (Expr s a)+timeNumOffset = do+ s <- signPrefix++ hour <- timeHour++ _ <- text ":"++ minute <- timeMinute++ let minutes = s (hour * 60 + minute)++ return (TimeZoneLiteral (Time.TimeZone minutes Prelude.False ""))++{-| Parse a numeric `TimeZone` or a @Z@++ This corresponds to the @time-offset@ rule from the official grammar+-}+timeOffset :: Parser (Expr s a)+timeOffset =+ (do _ <- text "Z"++ return (TimeZoneLiteral (Time.TimeZone 0 Prelude.False ""))+ )+ <|> timeNumOffset++{-| Parse a `Time`++ This corresponds to the @partial-time@ rule from the official grammar+-}+partialTime :: Parser (Expr s a)+partialTime = do+ hour <- timeHour++ _ <- text ":"++ minute <- timeMinute++ _ <- text ":"++ second <- timeSecond++ (fraction, precision) <- timeSecFrac <|> pure (0, 0)++ let time = Time.TimeOfDay hour minute (second + fraction)++ return (TimeLiteral time precision)++{-| Parse a `Date`++ This corresponds to the @full-date@ rule from the official grammar+-}+fullDate :: Parser (Expr s a)+fullDate = do+ year <- dateFullYear++ _ <- text "-"++ month <- dateMonth++ _ <- text "-"++ day <- dateMday++ case Time.fromGregorianValid year month day of+ Nothing -> fail "Invalid calendar day"+ Just d -> return (DateLiteral d)++{-| Parse a `Date`, `Time`, `TimeZone` or any valid permutation of them as a+ record++ This corresponds to the @temporal-literal@ rule from the official grammar+-}+temporalLiteral :: Parser (Expr s a)+temporalLiteral =+ try (do+ date <- fullDate++ _ <- text "T" <|> text "t"++ time <- partialTime++ timeZone <- timeOffset++ return+ (RecordLit+ [ ("date" , makeRecordField date)+ , ("time" , makeRecordField time)+ , ("timeZone", makeRecordField timeZone)+ ]+ )+ )+ <|> try (do+ date <- fullDate++ _ <- text "T" <|> text "t"++ time <- partialTime++ return+ (RecordLit+ [ ("date", makeRecordField date)+ , ("time", makeRecordField time)+ ]+ )+ )+ <|> try (do+ time <- partialTime++ timeZone <- timeOffset++ return+ (RecordLit+ [ ("time" , makeRecordField time)+ , ("timeZone", makeRecordField timeZone)+ ]+ )+ )+ <|> try fullDate+ <|> try partialTime+ <|> try timeNumOffset++-- | Parse a \"shebang\" line (i.e. an initial line beginning with @#!@)+shebang :: Parser ()+shebang = do+ _ <- text "#!"++ let predicate c = ('\x20' <= c && c <= '\x10FFFF') || c == '\t'++ _ <- Dhall.Parser.Combinators.takeWhile predicate++ _ <- endOfLine++ return ()++-- | Given a parser for imports,+parsers :: forall a. Parser a -> Parsers a+parsers embedded = Parsers{..}+ where+ completeExpression_ =+ whitespace+ *> expression+ <* whitespace+ <* optional lineCommentPrefix++ letBinding = do+ src0 <- try (_let *> src nonemptyWhitespace)++ c <- label++ src1 <- src whitespace++ d <- optional (do+ _colon++ src2 <- src nonemptyWhitespace++ e <- expression++ whitespace++ return (Just src2, e) )++ _equal++ src3 <- src whitespace++ f <- expression++ whitespace++ return (Binding (Just src0) c (Just src1) d (Just src3) f)++ expression =+ noted+ ( choice+ [ alternative0+ , alternative1+ , alternative2+ , alternative3+ , alternative4+ , alternative5+ ]+ ) <?> "expression"+ where+ alternative0 = do+ cs <- _lambda+ whitespace+ _openParens+ src0 <- src whitespace+ a <- label+ src1 <- src whitespace+ _colon+ src2 <- src nonemptyWhitespace+ b <- expression+ whitespace+ _closeParens+ whitespace+ cs' <- _arrow+ whitespace+ c <- expression+ return (Lam (Just (cs <> cs')) (FunctionBinding (Just src0) a (Just src1) (Just src2) b) c)++ alternative1 = do+ try (_if *> nonemptyWhitespace)+ a <- expression+ whitespace+ try (_then *> nonemptyWhitespace)+ b <- expression+ whitespace+ try (_else *> nonemptyWhitespace)+ c <- expression+ return (BoolIf a b c)++ alternative2 = do+ as <- NonEmpty.some1 letBinding++ try (_in *> nonemptyWhitespace)++ b <- expression++ -- 'Note's in let-in-let:+ --+ -- Subsequent @let@s that are not separated by an @in@ only get a+ -- single surrounding 'Note'. For example:+ --+ -- let x = a+ -- let y = b+ -- in let z = c+ -- in x+ --+ -- is parsed as+ --+ -- (Note …+ -- (Let x …+ -- (Let y …+ -- (Note …+ -- (Let z …+ return (Dhall.Syntax.wrapInLets as b)++ alternative3 = do+ cs <- try (_forall <* whitespace <* _openParens)+ whitespace+ a <- label+ whitespace+ _colon+ nonemptyWhitespace+ b <- expression+ whitespace+ _closeParens+ whitespace+ cs' <- _arrow+ whitespace+ c <- expression+ return (Pi (Just (cs <> cs')) a b c)++ alternative4 = do+ try (_assert *> whitespace *> _colon)+ nonemptyWhitespace+ a <- expression+ return (Assert a)++ alternative5 = do+ (a0Info, a0) <- applicationExpressionWithInfo++ let (parseFirstOperatorExpression, parseOperatorExpression) =+ operatorExpression (pure a0)++ let alternative5A = do+ case a0Info of+ ImportExpr -> return ()+ _ -> empty++ bs <- some (do+ try (nonemptyWhitespace *> _with *> nonemptyWhitespace)++ let withComponent =+ fmap WithLabel anyLabelOrSome+ <|> fmap (\_ -> WithQuestion) (text "?")++ keys <- Combinators.NonEmpty.sepBy1 withComponent (try (whitespace *> _dot) *> whitespace)++ whitespace++ _equal++ whitespace++ value <- parseOperatorExpression++ return (\e -> With e keys value) )++ return (foldl (\e f -> f e) a0 bs)++ let alternative5B = do+ a <- parseFirstOperatorExpression++ whitespace++ let alternative5B0 = do+ cs <- _arrow+ whitespace+ b <- expression+ whitespace+ return (Pi (Just cs) "_" a b)++ let alternative5B1 = do+ _colon+ nonemptyWhitespace+ case (shallowDenote a, a0Info) of+ (ListLit Nothing [], _) -> do+ b <- expression++ return (ListLit (Just b) [])+ (Merge c d Nothing, NakedMergeOrSomeOrToMap) -> do+ b <- expression++ return (Merge c d (Just b))+ (ToMap c Nothing, NakedMergeOrSomeOrToMap) -> do+ b <- expression++ return (ToMap c (Just b))+ _ -> do+ b <- expression++ return (Annot a b)++ let alternative5B2 =+ case shallowDenote a of+ ListLit Nothing [] ->+ fail "Empty list literal without annotation"+ _ -> pure a++ alternative5B0 <|> alternative5B1 <|> alternative5B2++ alternative5A <|> alternative5B++ -- The firstApplicationExpression argument is necessary in order to+ -- left-factor the parsers for function types and @with@ expressions to+ -- minimize backtracking+ --+ -- For a longer explanation, see:+ --+ -- https://github.com/dhall-lang/dhall-haskell/pull/1770#discussion_r419022486+ operatorExpression firstApplicationExpression =+ foldr cons nil operatorParsers+ where+ cons operatorParser (p0, p) =+ ( makeOperatorExpression p0 operatorParser p+ , makeOperatorExpression p operatorParser p+ )++ nil = (firstApplicationExpression, applicationExpression)++ makeOperatorExpression firstSubExpression operatorParser subExpression = do+ a <- firstSubExpression++ bs <- Text.Megaparsec.many $ do+ (Src _ _ textOp, op0) <- srcAnd (try (whitespace *> operatorParser))++ r0 <- subExpression++ let l@(Note (Src startL _ textL) _) `op` r@(Note (Src _ endR textR) _) =+ Note (Src startL endR (textL <> textOp <> textR)) (l `op0` r)+ -- We shouldn't hit this branch if things are working, but+ -- that is not enforced in the types+ l `op` r =+ l `op0` r++ return (`op` r0)++ return (foldl' (\x f -> f x) a bs)++ operatorParsers :: [Parser (Expr s a -> Expr s a -> Expr s a)]+ operatorParsers =+ [ Equivalent . Just <$> _equivalent <* whitespace+ , ImportAlt <$ _importAlt <* nonemptyWhitespace+ , BoolOr <$ _or <* whitespace+ , NaturalPlus <$ _plus <* nonemptyWhitespace+ , TextAppend <$ _textAppend <* whitespace+ , ListAppend <$ _listAppend <* whitespace+ , BoolAnd <$ _and <* whitespace+ , (\cs -> Combine (Just cs) Nothing) <$> _combine <* whitespace+ , (\cs -> Prefer (Just cs) PreferFromSource) <$> _prefer <* whitespace+ , CombineTypes . Just <$> _combineTypes <* whitespace+ , NaturalTimes <$ _times <* whitespace+ -- Make sure that `==` is not actually the prefix of `===`+ , BoolEQ <$ try (_doubleEqual <* Text.Megaparsec.notFollowedBy (char '=')) <* whitespace+ , BoolNE <$ _notEqual <* whitespace+ ]++ applicationExpression = snd <$> applicationExpressionWithInfo++ applicationExpressionWithInfo :: Parser (ApplicationExprInfo, Expr Src a)+ applicationExpressionWithInfo = do+ let alternative0 = do+ try (_merge *> nonemptyWhitespace)++ a <- importExpression_ <* nonemptyWhitespace++ return (\b -> Merge a b Nothing, Just "second argument to ❰merge❱")++ let alternative1 = do+ try (_Some *> nonemptyWhitespace)++ return (Some, Just "argument to ❰Some❱")++ let alternative2 = do+ try (_toMap *> nonemptyWhitespace)++ return (\a -> ToMap a Nothing, Just "argument to ❰toMap❱")++ let alternative3 = do+ try (_showConstructor *> nonemptyWhitespace)++ return (\a -> ShowConstructor a, Just "argument to ❰showConstructor❱")++ let alternative4 =+ return (id, Nothing)++ (f, maybeMessage) <- alternative0 <|> alternative1 <|> alternative2 <|> alternative3 <|> alternative4++ let adapt parser =+ case maybeMessage of+ Nothing -> parser+ Just message -> parser <?> message++ a <- adapt (noted importExpression_)++ bs <- Text.Megaparsec.many . try $ do+ (sep, _) <- Text.Megaparsec.match nonemptyWhitespace+ b <- importExpression_+ return (sep, b)++ let c = foldl' app (f a) bs++ let info =+ case (maybeMessage, bs) of+ (Just _ , []) -> NakedMergeOrSomeOrToMap+ (Nothing, []) -> ImportExpr+ _ -> ApplicationExpr++ return (info, c)+ where+ app a (sep, b)+ | Note (Src left _ bytesL) _ <- a+ , Note (Src _ right bytesR) _ <- b+ = Note (Src left right (bytesL <> sep <> bytesR)) (App a b)+ app a (_, b) =+ App a b++ importExpression_ = noted (choice [ alternative0, alternative1 ])+ where+ alternative0 = do+ a <- embedded+ return (Embed a)++ alternative1 = completionExpression++ completionExpression = noted (do+ a <- selectorExpression++ mb <- optional (do+ try (whitespace *> _doubleColon)++ whitespace++ selectorExpression )++ case mb of+ Nothing -> return a+ Just b -> return (RecordCompletion a b) )++ selectorExpression = noted (do+ a <- primitiveExpression++ let recordType = _openParens *> whitespace *> expression <* whitespace <* _closeParens++ let field x e = Field e x+ let projectBySet xs e = Project e (Left xs)+ let projectByExpression xs e = Project e (Right xs)++ let alternatives = do+ src0 <- src whitespace++ let fieldSelection = do+ l <- anyLabel++ pos <- Text.Megaparsec.getSourcePos++ -- FIXME: Suffix whitespace can't be parsed given our limitation+ -- about whitespace treatment, but for @dhall-docs@ this+ -- is enough+ let src1 = Src pos pos ""++ return (FieldSelection (Just src0) l (Just src1))++ let result =+ fmap field fieldSelection+ <|> fmap projectBySet labels+ <|> fmap projectByExpression recordType++ result++ b <- Text.Megaparsec.many (try (whitespace *> _dot *> alternatives))++ return (foldl' (\e k -> k e) a b) )++ primitiveExpression =+ noted+ ( choice+ [ bytesLiteral+ , temporalLiteral+ , alternative00+ , alternative01+ , alternative02+ , textLiteral+ , alternative04+ , unionType+ , listLiteral+ , alternative37+ , alternative09+ , builtin+ ]+ )+ <|> alternative38+ where+ alternative00 = do+ n <- getOffset+ a <- try doubleLiteral+ b <- if isInfinite a+ then setOffset n *> fail "double out of bounds"+ else return a+ return (DoubleLit (DhallDouble b))++ alternative01 = do+ a <- try naturalLiteral+ return (NaturalLit a)++ alternative02 = do+ a <- try integerLiteral+ return (IntegerLit a)++ alternative04 = (do+ _openBrace++ src0 <- src whitespace+ mComma <- optional _comma++ -- `src1` corresponds to the prefix whitespace of the first key-value+ -- pair. This is done to avoid using `try` to recover the consumed+ -- whitespace when the comma is not consumed+ src1 <- case mComma of+ Nothing -> return src0+ Just _ -> src whitespace++ a <- recordTypeOrLiteral src1++ _closeBrace++ return a ) <?> "literal"++ alternative09 = do+ a <- try doubleInfinity+ return (DoubleLit (DhallDouble a))++ builtin = do+ let predicate c =+ c == 'N'+ || c == 'I'+ || c == 'D'+ || c == 'L'+ || c == 'O'+ || c == 'B'+ || c == 'S'+ || c == 'T'+ || c == 'F'+ || c == 'K'++ let nan = DhallDouble (0.0/0.0)++ c <- Text.Megaparsec.lookAhead (Text.Megaparsec.satisfy predicate)++ case c of+ 'N' ->+ choice+ [ NaturalFold <$ _NaturalFold+ , NaturalBuild <$ _NaturalBuild+ , NaturalIsZero <$ _NaturalIsZero+ , NaturalEven <$ _NaturalEven+ , NaturalOdd <$ _NaturalOdd+ , NaturalSubtract <$ _NaturalSubtract+ , NaturalToInteger <$ _NaturalToInteger+ , NaturalShow <$ _NaturalShow+ , Natural <$ _Natural+ , None <$ _None+ , DoubleLit nan <$ _NaN+ ]+ 'I' ->+ choice+ [ IntegerClamp <$ _IntegerClamp+ , IntegerNegate <$ _IntegerNegate+ , IntegerShow <$ _IntegerShow+ , IntegerToDouble <$ _IntegerToDouble+ , Integer <$ _Integer+ ]++ 'D' ->+ choice+ [ DateShow <$ _DateShow+ , Date <$ _Date+ , DoubleShow <$ _DoubleShow+ , Double <$ _Double+ ]+ 'L' ->+ choice+ [ ListBuild <$ _ListBuild+ , ListFold <$ _ListFold+ , ListLength <$ _ListLength+ , ListHead <$ _ListHead+ , ListLast <$ _ListLast+ , ListIndexed <$ _ListIndexed+ , ListReverse <$ _ListReverse+ , List <$ _List+ ]+ 'O' -> Optional <$ _Optional+ 'B' ->+ choice+ [ Bool <$ _Bool+ , Bytes <$ _Bytes+ ]+ 'S' -> Const Sort <$ _Sort+ 'T' ->+ choice+ [ TextReplace <$ _TextReplace+ , TextShow <$ _TextShow+ , Text <$ _Text+ , TimeZoneShow <$ _TimeZoneShow+ , TimeZone <$ _TimeZone+ , TimeShow <$ _TimeShow+ , Time <$ _Time+ , BoolLit True <$ _True+ , Const Type <$ _Type+ ]+ 'F' -> BoolLit False <$ _False+ 'K' -> Const Kind <$ _Kind+ _ -> empty++ alternative37 = do+ a <- identifier+ return (Var a)++ alternative38 = do+ _openParens+ whitespace+ a <- expression+ whitespace+ _closeParens+ return a++ doubleQuotedChunk =+ choice+ [ interpolation+ , unescapedCharacterFast+ , unescapedCharacterSlow+ , escapedCharacter+ ]+ where+ interpolation = do+ _ <- text "${"+ e <- completeExpression_+ _ <- char '}'+ return (Chunks [(mempty, e)] mempty)++ unescapedCharacterFast = do+ t <- Text.Megaparsec.takeWhile1P Nothing predicate+ return (Chunks [] t)+ where+ predicate c =+ ( ('\x20' <= c && c <= '\x21' )+ || ('\x23' <= c && c <= '\x5B' )+ || ('\x5D' <= c && c <= '\x10FFFF')+ ) && c /= '$'++ unescapedCharacterSlow = do+ _ <- char '$'+ return (Chunks [] "$")++ escapedCharacter = do+ _ <- char '\\'+ c <- choice+ [ quotationMark+ , dollarSign+ , backSlash+ , forwardSlash+ , backSpace+ , formFeed+ , lineFeed+ , carriageReturn+ , tab+ , unicode+ ]+ return (Chunks [] (Data.Text.singleton c))+ where+ quotationMark = char '"'++ dollarSign = char '$'++ backSlash = char '\\'++ forwardSlash = char '/'++ backSpace = do _ <- char 'b'; return '\b'++ formFeed = do _ <- char 'f'; return '\f'++ lineFeed = do _ <- char 'n'; return '\n'++ carriageReturn = do _ <- char 'r'; return '\r'++ tab = do _ <- char 't'; return '\t'++ unicode = do+ _ <- char 'u';++ let toNumber = Data.List.foldl' (\x y -> x * 16 + y) 0++ let fourCharacterEscapeSequence = do+ ns <- Control.Monad.replicateM 4 hexNumber++ let number = toNumber ns++ Control.Monad.guard (validCodepoint number)+ <|> fail "Invalid Unicode code point"++ return number++ let bracedEscapeSequence = do+ _ <- char '{'+ ns <- some hexNumber++ let number = toNumber ns++ Control.Monad.guard (number <= 0x10FFFD && validCodepoint number)+ <|> fail "Invalid Unicode code point"++ _ <- char '}'++ return number++ n <- bracedEscapeSequence <|> fourCharacterEscapeSequence++ return (Char.chr n)++ doubleQuotedLiteral = do+ _ <- char '"'+ chunks <- Text.Megaparsec.many doubleQuotedChunk+ _ <- char '"'+ return (mconcat chunks)++ singleQuoteContinue =+ choice+ [ escapeSingleQuotes+ , interpolation+ , escapeInterpolation+ , endLiteral+ , unescapedCharacterFast+ , unescapedCharacterSlow+ , tab+ , endOfLine_+ ]+ where+ escapeSingleQuotes = do+ _ <- "'''" :: Parser Text+ b <- singleQuoteContinue+ return ("''" <> b)++ interpolation = do+ _ <- text "${"+ a <- completeExpression_+ _ <- char '}'+ b <- singleQuoteContinue+ return (Chunks [(mempty, a)] mempty <> b)++ escapeInterpolation = do+ _ <- text "''${"+ b <- singleQuoteContinue+ return ("${" <> b)++ endLiteral = do+ _ <- text "''"+ return mempty++ unescapedCharacterFast = do+ a <- Text.Megaparsec.takeWhile1P Nothing predicate+ b <- singleQuoteContinue+ return (Chunks [] a <> b)+ where+ predicate c =+ ('\x20' <= c && c <= '\x10FFFF') && c /= '$' && c /= '\''++ unescapedCharacterSlow = do+ a <- satisfy predicate+ b <- singleQuoteContinue+ return (Chunks [] a <> b)+ where+ predicate c = c == '$' || c == '\''++ endOfLine_ = do+ a <- "\n" <|> "\r\n"+ b <- singleQuoteContinue+ return (Chunks [] a <> b)++ tab = do+ _ <- char '\t' <?> "tab"+ b <- singleQuoteContinue+ return ("\t" <> b)++ singleQuoteLiteral = do+ _ <- text "''"++ _ <- endOfLine++ a <- singleQuoteContinue++ return (Dhall.Syntax.toDoubleQuoted a)++ textLiteral = (do+ literal <- doubleQuotedLiteral <|> singleQuoteLiteral+ return (TextLit literal) ) <?> "literal"++ bytesLiteral = (do+ _ <- text "0x\""++ let byte = do+ nibble0 <- Text.Megaparsec.satisfy hexdig+ nibble1 <- Text.Megaparsec.satisfy hexdig+ return ([nibble0, nibble1] `base` 16)++ bytes <- Text.Megaparsec.many byte++ _ <- char '"'++ return (BytesLit (ByteString.pack bytes)) ) <?> "literal"++ recordTypeOrLiteral firstSrc0 =+ choice+ [ emptyRecordLiteral+ , nonEmptyRecordTypeOrLiteral firstSrc0+ , emptyRecordType+ ]++ emptyRecordLiteral = do+ _equal++ _ <- optional (try (whitespace *> _comma))++ whitespace+ return (RecordLit mempty)++ emptyRecordType = return (Record mempty)++ nonEmptyRecordTypeOrLiteral firstSrc0 = do+ let nonEmptyRecordType = do+ (firstKeySrc1, a) <- try $ do+ a <- anyLabelOrSome+ s <- src whitespace+ _colon+ return (s, a)++ firstKeySrc2 <- src nonemptyWhitespace++ b <- expression++ e <- Text.Megaparsec.many $ do+ (src0', c) <- try $ do+ _comma+ src0' <- src whitespace+ c <- anyLabelOrSome+ return (src0', c)++ src1 <- src whitespace++ _colon++ src2 <- src nonemptyWhitespace++ d <- expression++ whitespace++ return (c, RecordField (Just src0') d (Just src1) (Just src2))++ _ <- optional (whitespace *> _comma)+ whitespace++ m <- toMap ((a, RecordField (Just firstSrc0) b (Just firstKeySrc1) (Just firstKeySrc2)) : e)++ return (Record m)++ let keysValue maybeSrc = do+ firstSrc0' <- case maybeSrc of+ Just src0 -> return src0+ Nothing -> src whitespace+ firstLabel <- anyLabelOrSome+ firstSrc1 <- src whitespace++ let parseLabelWithWhsp = try $ do+ _dot+ src0 <- src whitespace+ l <- anyLabelOrSome+ src1 <- src whitespace+ return (src0, l, src1)++ restKeys <- Combinators.many parseLabelWithWhsp+ let keys = (firstSrc0', firstLabel, firstSrc1) :| restKeys++ let normalRecordEntry = do+ try _equal++ lastSrc2 <- src whitespace++ value <- expression++ let cons (s0, key, s1) (key', values) =+ (key, RecordField (Just s0) (RecordLit [ (key', values) ]) (Just s1) Nothing)++ let (lastSrc0, lastLabel, lastSrc1) = NonEmpty.last keys+ let nil = (lastLabel, RecordField (Just lastSrc0) value (Just lastSrc1) (Just lastSrc2))++ return (foldr cons nil (NonEmpty.init keys))++ let punnedEntry =+ case keys of+ (s0, x, s1) :| [] -> return (x, RecordField (Just s0) (Var (V x 0)) (Just s1) Nothing)+ _ -> empty++ (normalRecordEntry <|> punnedEntry) <* whitespace++ let nonEmptyRecordLiteral = do+ a <- keysValue (Just firstSrc0)++ as <- many (try (_comma *> keysValue Nothing))++ _ <- optional (whitespace *> _comma)++ whitespace++ let combine k = liftA2 $ \rf rf' -> makeRecordField $ Combine mempty (Just k)+ (recordFieldValue rf')+ (recordFieldValue rf)++ m <- toMapWith combine (a : as)++ return (RecordLit m)++ nonEmptyRecordType <|> nonEmptyRecordLiteral++ unionType = (do+ _openAngle++ whitespace++ let unionTypeEntry = do+ a <- anyLabelOrSome++ whitespace++ b <- optional (_colon *> nonemptyWhitespace *> expression <* whitespace)++ return (a, b)++ let nonEmptyUnionType = do+ kv <- try (optional (_bar *> whitespace) *> unionTypeEntry)++ kvs <- many (try (_bar *> whitespace *> unionTypeEntry))++ m <- toMap (kv : kvs)++ _ <- optional (_bar *> whitespace)++ _closeAngle++ return (Union m)++ let emptyUnionType = do+ try (optional (_bar *> whitespace) *> _closeAngle)++ return (Union mempty)++ nonEmptyUnionType <|> emptyUnionType ) <?> "literal"++ listLiteral = (do+ _openBracket++ whitespace++ let nonEmptyListLiteral = do+ a <- try (optional (_comma *> whitespace) *> expression)++ whitespace++ as <- many (try (_comma *> whitespace *> expression) <* whitespace)++ _ <- optional (_comma *> whitespace)++ _closeBracket++ return (ListLit Nothing (Data.Sequence.fromList (a : as)))++ let emptyListLiteral = do+ try (optional (_comma *> whitespace) *> _closeBracket)++ return (ListLit Nothing mempty)++ nonEmptyListLiteral <|> emptyListLiteral) <?> "literal"++{-| Parse an environment variable import++ This corresponds to the @env@ rule from the official grammar+-}+env :: Parser ImportType+env = do+ _ <- text "env:"+ a <- (alternative0 <|> alternative1)+ return (Env a)+ where+ alternative0 = bashEnvironmentVariable++ alternative1 = do+ _ <- char '"'+ a <- posixEnvironmentVariable+ _ <- char '"'+ return a++-- | Parse a local import without trailing whitespace+localOnly :: Parser ImportType+localOnly =+ choice+ [ parentPath+ , herePath+ , homePath+ , try absolutePath+ ]+ where+ parentPath = do+ _ <- ".." :: Parser Text+ file <- file_ FileComponent++ return (Local Parent file)++ herePath = do+ _ <- "." :: Parser Text+ file <- file_ FileComponent++ return (Local Here file)++ homePath = do+ _ <- "~" :: Parser Text+ file <- file_ FileComponent++ return (Local Home file)++ absolutePath = do+ file <- file_ FileComponent++ return (Local Absolute file)++{-| Parse a local import++ This corresponds to the @local@ rule from the official grammar+-}+local :: Parser ImportType+local = do+ a <- localOnly+ return a++{-| Parse an HTTP(S) import++ This corresponds to the @http@ rule from the official grammar+-}+http :: Parser ImportType+http = do+ url <- httpRaw+ headers <- optional (do+ try (whitespace *> _using *> nonemptyWhitespace)+ importExpression import_ )+ return (Remote (url { headers }))++{-| Parse a `Missing` import++ This corresponds to the @missing@ rule from the official grammar+-}+missing :: Parser ImportType+missing = do+ _missing+ return Missing++{-| Parse an `ImportType`++ This corresponds to the @import-type@ rule from the official grammar+-}+importType_ :: Parser ImportType+importType_ = do+ let predicate c =+ c == '~' || c == '.' || c == '/' || c == 'h' || c == 'e' || c == 'm'++ _ <- Text.Megaparsec.lookAhead (Text.Megaparsec.satisfy predicate)++ choice [ local, http, env, missing ]++{-| Parse a `Dhall.Crypto.SHA256Digest`++ This corresponds to the @hash@ rule from the official grammar+-}+importHash_ :: Parser Dhall.Crypto.SHA256Digest+importHash_ = do+ _ <- text "sha256:"+ t <- count 64 (satisfy hexdig <?> "hex digit")+ let strictBytes16 = Data.Text.Encoding.encodeUtf8 t+ strictBytes <- case Base16.decode strictBytes16 of+ Left string -> fail string+ Right strictBytes -> return strictBytes+ case Dhall.Crypto.sha256DigestFromByteString strictBytes of+ Nothing -> fail "Invalid sha256 hash"+ Just h -> pure h++{-| Parse an `ImportHashed`++ This corresponds to the @import-hashed@ rule from the official grammar+-}+importHashed_ :: Parser ImportHashed+importHashed_ = do+ importType <- importType_+ hash <- optional (try (nonemptyWhitespace *> importHash_))+ return (ImportHashed {..})++{-| Parse an `Import`++ This corresponds to the @import@ rule from the official grammar+-}+import_ :: Parser Import+import_ = (do+ importHashed <- importHashed_+ importMode <- alternative <|> pure Code+ return (Import {..}) ) <?> "import"+ where+ alternative = do+ try (whitespace *> _as *> nonemptyWhitespace)++ (_Text >> pure RawText)+ <|> (_Location >> pure Location)+ <|> (_Bytes >> pure RawBytes)++-- | 'ApplicationExprInfo' distinguishes certain subtypes of application+-- expressions.+data ApplicationExprInfo+ = NakedMergeOrSomeOrToMap+ -- ^ @merge x y@, @Some x@ or @toMap x@, unparenthesized.+ | ImportExpr+ -- ^ An import expression.+ | ApplicationExpr+ -- ^ Any other application expression.
@@ -1,790 +1,1438 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE OverloadedStrings #-}--- | Parse Dhall tokens. Even though we don't have a tokenizer per-se this---- module is useful for keeping some small parsing utilities.-module Dhall.Parser.Token (- whitespace,- bashEnvironmentVariable,- posixEnvironmentVariable,- ComponentType(..),- file_,- label,- anyLabel,- labels,- httpRaw,- hexdig,- identifier,- hexNumber,- doubleLiteral,- doubleInfinity,- naturalLiteral,- integerLiteral,- _Optional,- _if,- _then,- _else,- _let,- _in,- _as,- _using,- _merge,- _constructors,- _Some,- _None,- _NaturalFold,- _NaturalBuild,- _NaturalIsZero,- _NaturalEven,- _NaturalOdd,- _NaturalToInteger,- _NaturalShow,- _IntegerShow,- _IntegerToDouble,- _DoubleShow,- _ListBuild,- _ListFold,- _ListLength,- _ListHead,- _ListLast,- _ListIndexed,- _ListReverse,- _OptionalFold,- _OptionalBuild,- _Bool,- _Natural,- _Integer,- _Double,- _Text,- _TextShow,- _List,- _True,- _False,- _NaN,- _Type,- _Kind,- _Sort,- _equal,- _or,- _plus,- _textAppend,- _listAppend,- _and,- _times,- _doubleEqual,- _notEqual,- _dot,- _openBrace,- _closeBrace,- _openBracket,- _closeBracket,- _openAngle,- _closeAngle,- _bar,- _comma,- _openParens,- _closeParens,- _colon,- _at,- _missing,- _importAlt,- _combine,- _combineTypes,- _prefer,- _lambda,- _forall,- _arrow,- ) where--import Dhall.Parser.Combinators--import Control.Applicative (Alternative(..), optional)-import Data.Functor (void)-import Data.Semigroup (Semigroup(..))-import Data.Text (Text)-import Dhall.Core-import Dhall.Set (Set)-import Prelude hiding (const, pi)-import Text.Parser.Combinators (choice, try, (<?>))--import qualified Control.Monad-import qualified Data.Char-import qualified Data.HashSet-import qualified Data.List.NonEmpty-import qualified Data.Text-import qualified Dhall.Set-import qualified Network.URI.Encode as URI.Encode-import qualified Text.Megaparsec-import qualified Text.Megaparsec.Char.Lexer-import qualified Text.Parser.Char-import qualified Text.Parser.Combinators--import Numeric.Natural (Natural)-import Prelude hiding (const, pi)--import qualified Text.Parser.Token---whitespace :: Parser ()-whitespace = Text.Parser.Combinators.skipMany whitespaceChunk--nonemptyWhitespace :: Parser ()-nonemptyWhitespace = Text.Parser.Combinators.skipSome whitespaceChunk--alpha :: Char -> Bool-alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')--digit :: Char -> Bool-digit c = '\x30' <= c && c <= '\x39'--hexdig :: Char -> Bool-hexdig c =- ('0' <= c && c <= '9')- || ('A' <= c && c <= 'F')- || ('a' <= c && c <= 'f')--signPrefix :: Num a => Parser (a -> a)-signPrefix = (do- let positive = fmap (\_ -> id ) (Text.Parser.Char.char '+')- let negative = fmap (\_ -> negate) (Text.Parser.Char.char '-')- positive <|> negative ) <?> "sign"--doubleLiteral :: Parser Double-doubleLiteral = (do- sign <- signPrefix <|> pure id- a <- Text.Parser.Token.double- return (sign a) ) <?> "double literal"--doubleInfinity :: Parser Double-doubleInfinity = (do- let negative = fmap (\_ -> negate) (Text.Parser.Char.char '-')- sign <- negative <|> pure id- a <- Text.Parser.Char.text "Infinity" >> whitespace >> return (1.0/0.0)- return (sign a) ) <?> "double infinity"--integerLiteral :: Parser Integer-integerLiteral = (do- sign <- signPrefix- a <- Text.Megaparsec.Char.Lexer.decimal- whitespace- return (sign a) ) <?> "integer literal"--naturalLiteral :: Parser Natural-naturalLiteral = (do- a <- Text.Megaparsec.Char.Lexer.decimal- whitespace- return a ) <?> "natural literal"--identifier :: Parser Var-identifier = do- x <- label-- let indexed = do- _ <- Text.Parser.Char.char '@'- n <- Text.Megaparsec.Char.Lexer.decimal- whitespace- return n-- n <- indexed <|> pure 0- return (V x n)--whitespaceChunk :: Parser ()-whitespaceChunk =- choice- [ void (Dhall.Parser.Combinators.takeWhile1 predicate)- , void (Text.Parser.Char.text "\r\n")- , lineComment- , blockComment- ] <?> "whitespace"- where- predicate c = c == ' ' || c == '\t' || c == '\n'--hexNumber :: Parser Int-hexNumber = choice [ hexDigit, hexUpper, hexLower ]- where- hexDigit = do- c <- Text.Parser.Char.satisfy predicate- return (Data.Char.ord c - Data.Char.ord '0')- where- predicate c = '0' <= c && c <= '9'-- hexUpper = do- c <- Text.Parser.Char.satisfy predicate- return (10 + Data.Char.ord c - Data.Char.ord 'A')- where- predicate c = 'A' <= c && c <= 'F'-- hexLower = do- c <- Text.Parser.Char.satisfy predicate- return (10 + Data.Char.ord c - Data.Char.ord 'a')- where- predicate c = 'a' <= c && c <= 'f'--lineComment :: Parser ()-lineComment = do- _ <- Text.Parser.Char.text "--"-- let predicate c = ('\x20' <= c && c <= '\x10FFFF') || c == '\t'-- _ <- Dhall.Parser.Combinators.takeWhile predicate-- endOfLine-- return ()- where- endOfLine =- void (Text.Parser.Char.char '\n' )- <|> void (Text.Parser.Char.text "\r\n")--blockComment :: Parser ()-blockComment = do- _ <- Text.Parser.Char.text "{-"- blockCommentContinue--blockCommentChunk :: Parser ()-blockCommentChunk =- choice- [ blockComment -- Nested block comment- , characters- , character- , endOfLine- ]- where- characters = void (Dhall.Parser.Combinators.takeWhile1 predicate)- where- predicate c =- '\x20' <= c && c <= '\x10FFFF' && c /= '-' && c /= '{'- || c == '\n'- || c == '\t'-- character = void (Text.Parser.Char.satisfy predicate)- where- predicate c = '\x20' <= c && c <= '\x10FFFF' || c == '\n' || c == '\t'-- endOfLine = void (Text.Parser.Char.text "\r\n")--blockCommentContinue :: Parser ()-blockCommentContinue = endOfComment <|> continue- where- endOfComment = void (Text.Parser.Char.text "-}")-- continue = do- blockCommentChunk- blockCommentContinue--simpleLabel :: Bool -> Parser Text-simpleLabel allowReserved = try (do- c <- Text.Parser.Char.satisfy headCharacter- rest <- Dhall.Parser.Combinators.takeWhile tailCharacter- let text = Data.Text.cons c rest- Control.Monad.guard (allowReserved || not (Data.HashSet.member text reservedIdentifiers))- return text )- where- headCharacter c = alpha c || c == '_'-- tailCharacter c = alpha c || digit c || c == '_' || c == '-' || c == '/'--backtickLabel :: Parser Text-backtickLabel = do- _ <- Text.Parser.Char.char '`'- t <- takeWhile1 predicate- _ <- Text.Parser.Char.char '`'- return t- where- predicate c =- '\x20' <= c && c <= '\x5F'- || '\x61' <= c && c <= '\x7E'--labels :: Parser (Set Text)-labels = do- _openBrace- xs <- nonEmptyLabels <|> emptyLabels- _closeBrace- return xs- where- emptyLabels = pure Dhall.Set.empty-- nonEmptyLabels = do- x <- anyLabel- xs <- many (do _ <- _comma; anyLabel)- noDuplicates (x : xs)---label :: Parser Text-label = (do- t <- backtickLabel <|> simpleLabel False- whitespace- return t ) <?> "label"--anyLabel :: Parser Text-anyLabel = (do- t <- backtickLabel <|> simpleLabel True- whitespace- return t ) <?> "any label"--bashEnvironmentVariable :: Parser Text-bashEnvironmentVariable = satisfy predicate0 <> star (satisfy predicate1)- where- predicate0 c = alpha c || c == '_'-- predicate1 c = alpha c || digit c || c == '_'--posixEnvironmentVariable :: Parser Text-posixEnvironmentVariable = plus posixEnvironmentVariableCharacter--posixEnvironmentVariableCharacter :: Parser Text-posixEnvironmentVariableCharacter =- escapeCharacter <|> satisfy predicate1- where- escapeCharacter = do- _ <- Text.Parser.Char.char '\\'-- c <- Text.Parser.Char.satisfy (`elem` ("\"\\abfnrtv" :: String))-- case c of- '"' -> return "\""- '\\' -> return "\\"- 'a' -> return "\a"- 'b' -> return "\b"- 'f' -> return "\f"- 'n' -> return "\n"- 'r' -> return "\r"- 't' -> return "\t"- 'v' -> return "\v"- _ -> empty-- predicate1 c =- ('\x20' <= c && c <= '\x21')- || ('\x23' <= c && c <= '\x3C')- || ('\x3E' <= c && c <= '\x5B')- || ('\x5D' <= c && c <= '\x7E')--quotedPathCharacter :: Char -> Bool-quotedPathCharacter c =- ('\x20' <= c && c <= '\x21')- || ('\x23' <= c && c <= '\x2E')- || ('\x30' <= c && c <= '\x10FFFF')--data ComponentType = URLComponent | FileComponent--pathComponent :: ComponentType -> Parser Text-pathComponent componentType = do- _ <- "/" :: Parser Text-- let pathData = do- text <- Text.Megaparsec.takeWhile1P Nothing Dhall.Core.pathCharacter-- case componentType of- FileComponent -> return text- URLComponent -> return (URI.Encode.decodeText text)-- let quotedPathData = do- _ <- Text.Parser.Char.char '"'- text <- Text.Megaparsec.takeWhile1P Nothing quotedPathCharacter- _ <- Text.Parser.Char.char '"'-- return text-- pathData <|> quotedPathData--file_ :: ComponentType -> Parser File-file_ componentType = do- path <- Data.List.NonEmpty.some1 (pathComponent componentType)-- let directory = Directory (reverse (Data.List.NonEmpty.init path))- let file = Data.List.NonEmpty.last path-- return (File {..})--scheme_ :: Parser Scheme-scheme_ =- ("http" :: Parser Text)- *> ((("s" :: Parser Text) *> pure HTTPS) <|> pure HTTP)- <* ("://" :: Parser Text)--httpRaw :: Parser URL-httpRaw = do- scheme <- scheme_- authority <- authority_- path <- file_ URLComponent- query <- optional (("?" :: Parser Text) *> query_)-- let headers = Nothing-- return (URL {..})--authority_ :: Parser Text-authority_ = option (try (userinfo <> "@")) <> host <> option (":" <> port)--userinfo :: Parser Text-userinfo = star (satisfy predicate <|> pctEncoded)- where- predicate c = unreserved c || subDelims c || c == ':'--host :: Parser Text-host = choice [ ipLiteral, ipV4Address, regName ]--port :: Parser Text-port = star (satisfy digit)--ipLiteral :: Parser Text-ipLiteral = "[" <> (ipV6Address <|> ipVFuture) <> "]"--ipVFuture :: Parser Text-ipVFuture = "v" <> plus (satisfy hexdig) <> "." <> plus (satisfy predicate)- where- predicate c = unreserved c || subDelims c || c == ':'--ipV6Address :: Parser Text-ipV6Address =- choice- [ try alternative0- , try alternative1- , try alternative2- , try alternative3- , try alternative4- , try alternative5- , try alternative6- , try alternative7- , alternative8- ]- where- alternative0 = count 6 (h16 <> ":") <> ls32-- alternative1 = "::" <> count 5 (h16 <> ":") <> ls32-- alternative2 = option h16 <> "::" <> count 4 (h16 <> ":") <> ls32-- alternative3 =- option (h16 <> range 0 1 (try (":" <> h16)))- <> "::"- <> count 3 (h16 <> ":")- <> ls32-- alternative4 =- option (h16 <> range 0 2 (try (":" <> h16)))- <> "::"- <> count 2 (h16 <> ":")- <> ls32-- alternative5 =- option (h16 <> range 0 3 (try (":" <> h16)))- <> "::"- <> h16- <> ":"- <> ls32-- alternative6 =- option (h16 <> range 0 4 (try (":" <> h16))) <> "::" <> ls32-- alternative7 =- option (h16 <> range 0 5 (try (":" <> h16))) <> "::" <> h16-- alternative8 =- option (h16 <> range 0 6 (try (":" <> h16))) <> "::"--h16 :: Parser Text-h16 = range 1 3 (satisfy hexdig)--ls32 :: Parser Text-ls32 = try (h16 <> ":" <> h16) <|> ipV4Address--ipV4Address :: Parser Text-ipV4Address = decOctet <> "." <> decOctet <> "." <> decOctet <> "." <> decOctet--decOctet :: Parser Text-decOctet =- choice- [ try alternative4- , try alternative3- , try alternative2- , try alternative1- , alternative0- ]- where- alternative0 = satisfy digit-- alternative1 = satisfy predicate <> satisfy digit- where- predicate c = '\x31' <= c && c <= '\x39'-- alternative2 = "1" <> count 2 (satisfy digit)-- alternative3 = "2" <> satisfy predicate <> satisfy digit- where- predicate c = '\x30' <= c && c <= '\x34'-- alternative4 = "25" <> satisfy predicate- where- predicate c = '\x30' <= c && c <= '\x35'--regName :: Parser Text-regName = star (satisfy predicate <|> pctEncoded)- where- predicate c = unreserved c || subDelims c--pchar :: Parser Text-pchar = satisfy predicate <|> pctEncoded- where- predicate c = unreserved c || subDelims c || c == ':' || c == '@'--query_ :: Parser Text-query_ = star (pchar <|> satisfy predicate)- where- predicate c = c == '/' || c == '?'--pctEncoded :: Parser Text-pctEncoded = "%" <> count 2 (satisfy hexdig)--subDelims :: Char -> Bool-subDelims c = c `elem` ("!$&'()*+,;=" :: String)--unreserved :: Char -> Bool-unreserved c =- alpha c || digit c || c == '-' || c == '.' || c == '_' || c == '~'--reserved :: Data.Text.Text -> Parser ()-reserved x = do _ <- Text.Parser.Char.text x; whitespace--reservedChar :: Char -> Parser ()-reservedChar c = do _ <- Text.Parser.Char.char c; whitespace--keyword :: Data.Text.Text -> Parser ()-keyword x = try (do _ <- Text.Parser.Char.text x; nonemptyWhitespace)--_if :: Parser ()-_if = keyword "if"--_then :: Parser ()-_then = keyword "then"--_else :: Parser ()-_else = keyword "else"--_let :: Parser ()-_let = keyword "let"--_in :: Parser ()-_in = keyword "in"--_as :: Parser ()-_as = keyword "as"--_using :: Parser ()-_using = keyword "using"--_merge :: Parser ()-_merge = keyword "merge"--_constructors :: Parser ()-_constructors = keyword "constructors"--_Some :: Parser ()-_Some = keyword "Some"--_None :: Parser ()-_None = reserved "None"--_NaturalFold :: Parser ()-_NaturalFold = reserved "Natural/fold"--_NaturalBuild :: Parser ()-_NaturalBuild = reserved "Natural/build"--_NaturalIsZero :: Parser ()-_NaturalIsZero = reserved "Natural/isZero"--_NaturalEven :: Parser ()-_NaturalEven = reserved "Natural/even"--_NaturalOdd :: Parser ()-_NaturalOdd = reserved "Natural/odd"--_NaturalToInteger :: Parser ()-_NaturalToInteger = reserved "Natural/toInteger"--_NaturalShow :: Parser ()-_NaturalShow = reserved "Natural/show"--_IntegerShow :: Parser ()-_IntegerShow = reserved "Integer/show"--_IntegerToDouble :: Parser ()-_IntegerToDouble = reserved "Integer/toDouble"--_DoubleShow :: Parser ()-_DoubleShow = reserved "Double/show"--_ListBuild :: Parser ()-_ListBuild = reserved "List/build"--_ListFold :: Parser ()-_ListFold = reserved "List/fold"--_ListLength :: Parser ()-_ListLength = reserved "List/length"--_ListHead :: Parser ()-_ListHead = reserved "List/head"--_ListLast :: Parser ()-_ListLast = reserved "List/last"--_ListIndexed :: Parser ()-_ListIndexed = reserved "List/indexed"--_ListReverse :: Parser ()-_ListReverse = reserved "List/reverse"--_OptionalFold :: Parser ()-_OptionalFold = reserved "Optional/fold"--_OptionalBuild :: Parser ()-_OptionalBuild = reserved "Optional/build"--_Bool :: Parser ()-_Bool = reserved "Bool"--_Optional :: Parser ()-_Optional = reserved "Optional"--_Natural :: Parser ()-_Natural = reserved "Natural"--_Integer :: Parser ()-_Integer = reserved "Integer"--_Double :: Parser ()-_Double = reserved "Double"--_Text :: Parser ()-_Text = reserved "Text"--_TextShow :: Parser ()-_TextShow = reserved "Text/show"--_List :: Parser ()-_List = reserved "List"--_True :: Parser ()-_True = reserved "True"--_False :: Parser ()-_False = reserved "False"--_NaN :: Parser ()-_NaN = reserved "NaN"--_Type :: Parser ()-_Type = reserved "Type"--_Kind :: Parser ()-_Kind = reserved "Kind"--_Sort :: Parser ()-_Sort = reserved "Sort"--_equal :: Parser ()-_equal = reservedChar '='--_or :: Parser ()-_or = reserved "||"--_plus :: Parser ()-_plus = reservedChar '+'--_textAppend :: Parser ()-_textAppend = reserved "++"--_listAppend :: Parser ()-_listAppend = reservedChar '#'--_and :: Parser ()-_and = reserved "&&"--_times :: Parser ()-_times = reservedChar '*'--_doubleEqual :: Parser ()-_doubleEqual = reserved "=="--_notEqual :: Parser ()-_notEqual = reserved "!="--_dot :: Parser ()-_dot = reservedChar '.'--_openBrace :: Parser ()-_openBrace = reservedChar '{'--_closeBrace :: Parser ()-_closeBrace = reservedChar '}'--_openBracket :: Parser ()-_openBracket = reservedChar '['--_closeBracket :: Parser ()-_closeBracket = reservedChar ']'--_openAngle :: Parser ()-_openAngle = reservedChar '<'--_closeAngle :: Parser ()-_closeAngle = reservedChar '>'--_bar :: Parser ()-_bar = reservedChar '|'--_comma :: Parser ()-_comma = reservedChar ','--_openParens :: Parser ()-_openParens = reservedChar '('--_closeParens :: Parser ()-_closeParens = reservedChar ')'--_colon :: Parser ()-_colon = reservedChar ':'--_at :: Parser ()-_at = reservedChar '@'--_missing :: Parser ()-_missing = reserved "missing"--_importAlt :: Parser ()-_importAlt = reservedChar '?'--_combine :: Parser ()-_combine = do- void (Text.Parser.Char.char '∧' <?> "\"∧\"") <|> void (Text.Parser.Char.text "/\\")- whitespace--_combineTypes :: Parser ()-_combineTypes = do- void (Text.Parser.Char.char '⩓' <?> "\"⩓\"") <|> void (Text.Parser.Char.text "//\\\\")- whitespace--_prefer :: Parser ()-_prefer = do- void (Text.Parser.Char.char '⫽' <?> "\"⫽\"") <|> void (Text.Parser.Char.text "//")- whitespace--_lambda :: Parser ()-_lambda = do- _ <- Text.Parser.Char.satisfy predicate- whitespace- where- predicate 'λ' = True- predicate '\\' = True- predicate _ = False--_forall :: Parser ()-_forall = do- void (Text.Parser.Char.char '∀' <?> "\"∀\"") <|> void (Text.Parser.Char.text "forall")- whitespace--_arrow :: Parser ()-_arrow = do- void (Text.Parser.Char.char '→' <?> "\"→\"") <|> void (Text.Parser.Char.text "->")- whitespace+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Parse Dhall tokens. Even though we don't have a tokenizer per-se this+--- module is useful for keeping some small parsing utilities.+module Dhall.Parser.Token (+ endOfLine,+ validCodepoint,+ whitespace,+ lineComment,+ lineCommentPrefix,+ blockComment,+ nonemptyWhitespace,+ bashEnvironmentVariable,+ posixEnvironmentVariable,+ ComponentType(..),+ text,+ char,+ file_,+ label,+ anyLabelOrSome,+ anyLabel,+ labels,+ httpRaw,+ hexdig,+ identifier,+ hexNumber,+ signPrefix,+ doubleLiteral,+ doubleInfinity,+ naturalLiteral,+ integerLiteral,+ dateFullYear,+ dateMonth,+ dateMday,+ timeHour,+ timeMinute,+ timeSecond,+ timeSecFrac,+ _Optional,+ _if,+ _then,+ _else,+ _let,+ _in,+ _as,+ _using,+ _merge,+ _toMap,+ _showConstructor,+ _assert,+ _Some,+ _None,+ _NaturalFold,+ _NaturalBuild,+ _NaturalIsZero,+ _NaturalEven,+ _NaturalOdd,+ _NaturalToInteger,+ _NaturalShow,+ _NaturalSubtract,+ _IntegerClamp,+ _IntegerNegate,+ _IntegerShow,+ _IntegerToDouble,+ _DoubleShow,+ _ListBuild,+ _ListFold,+ _ListLength,+ _ListHead,+ _ListLast,+ _ListIndexed,+ _ListReverse,+ _Bool,+ _Bytes,+ _Natural,+ _Integer,+ _Double,+ _Text,+ _TextReplace,+ _TextShow,+ _Date,+ _DateShow,+ _Time,+ _TimeShow,+ _TimeZone,+ _TimeZoneShow,+ _List,+ _True,+ _False,+ _NaN,+ _Type,+ _Kind,+ _Sort,+ _Location,+ _equal,+ _or,+ _plus,+ _textAppend,+ _listAppend,+ _and,+ _times,+ _doubleEqual,+ _notEqual,+ _dot,+ _openBrace,+ _closeBrace,+ _openBracket,+ _closeBracket,+ _openAngle,+ _closeAngle,+ _bar,+ _comma,+ _openParens,+ _closeParens,+ _colon,+ _at,+ _equivalent,+ _missing,+ _importAlt,+ _combine,+ _combineTypes,+ _prefer,+ _lambda,+ _forall,+ _arrow,+ _doubleColon,+ _with,+ ) where++import Dhall.Parser.Combinators++import Control.Applicative (Alternative (..), optional)+import Data.Bits ((.&.))+import Data.Fixed (Pico)+import Data.Functor (void, ($>))+import Data.Ratio ((%))+import Data.Text (Text)+import Dhall.Syntax+import Text.Parser.Combinators (choice, try, (<?>))++import qualified Control.Monad as Monad+import qualified Data.Char as Char+import qualified Data.Foldable+import qualified Data.HashSet+import qualified Data.List as List+import qualified Data.List.NonEmpty+import qualified Data.Scientific as Scientific+import qualified Data.Text+import qualified Text.Megaparsec+import qualified Text.Megaparsec.Char.Lexer+import qualified Text.Parser.Char+import qualified Text.Parser.Combinators+import qualified Text.Parser.Token++import Numeric.Natural (Natural)++-- | Match an end-of-line character sequence+endOfLine :: Parser Text+endOfLine =+ ( Text.Parser.Char.text "\n" + <|> Text.Parser.Char.text "\r\n"+ ) <?> "newline"++-- | Returns `True` if the given `Int` is a valid Unicode codepoint+validCodepoint :: Int -> Bool+validCodepoint c =+ not (category == Char.Surrogate+ || c .&. 0xFFFE == 0xFFFE+ || c .&. 0xFFFF == 0xFFFF)+ where+ category = Char.generalCategory (Char.chr c)++{-| Parse 0 or more whitespace characters (including comments)++ This corresponds to the @whsp@ rule in the official grammar+-}+whitespace :: Parser ()+whitespace = Text.Parser.Combinators.skipMany whitespaceChunk++{-| Parse 1 or more whitespace characters (including comments)++ This corresponds to the @whsp1@ rule in the official grammar+-}+nonemptyWhitespace :: Parser ()+nonemptyWhitespace = Text.Parser.Combinators.skipSome whitespaceChunk++alpha :: Char -> Bool+alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')++digit :: Char -> Bool+digit c = '\x30' <= c && c <= '\x39'++alphaNum :: Char -> Bool+alphaNum c = alpha c || digit c++{-| Parse a hex digit (uppercase or lowercase)++ This corresponds to the @HEXDIG@ rule in the official grammar+-}+hexdig :: Char -> Bool+hexdig c =+ ('0' <= c && c <= '9')+ || ('A' <= c && c <= 'F')+ || ('a' <= c && c <= 'f')++-- | Parse a leading @+@ or @-@ sign+signPrefix :: Num a => Parser (a -> a)+signPrefix = (do+ let positive = fmap (\_ -> id ) (char '+')+ let negative = fmap (\_ -> negate) (char '-')+ positive <|> negative ) <?> "sign"++{-| Parse a `Dhall.Syntax.Double` literal++ This corresponds to the @double-literal@ rule from the official grammar+-}+doubleLiteral :: Parser Double+doubleLiteral = (do+ -- We don't use `Text.Parser.Token.double` since that consumes trailing+ -- whitespace and there is no whitespace-free alternative. See:+ --+ -- https://github.com/dhall-lang/dhall-haskell/pull/1646+ -- https://github.com/dhall-lang/dhall-haskell/pull/1647+ --+ -- We also don't use `Text.Megaparsec.Char.Lexer.float` because that+ -- transitively depends on `Data.Char.toTitle` which is broken on older+ -- versions of GHCJS that we still support. See:+ --+ -- https://github.com/dhall-lang/dhall-haskell/pull/1681+ -- https://github.com/ghcjs/ghcjs-base/issues/62+ --+ -- Also, hand-writing the parser code for `Double` literals helps to better+ -- ensure that we follow the standard exactly as written.+ sign <- signPrefix <|> pure id++ x <- Text.Parser.Token.decimal++ let alternative0 = do+ y <- fraction++ e <- exponent' <|> pure 1++ return ((fromInteger x + y) * e)++ let alternative1 = do+ expo <- exponent'++ return (fromInteger x * expo)++ n <- alternative0 <|> alternative1++ return (sign (Scientific.toRealFloat n)) ) <?> "literal"+ where+ fraction = do+ _ <- Text.Parser.Char.char '.'++ digits <- some Text.Parser.Char.digit++ let snoc y d =+ y + Scientific.scientific (fromIntegral (Char.digitToInt d)) (Scientific.base10Exponent y - 1)++ return (List.foldl' snoc 0 digits)++ exponent' = do+ _ <- Text.Parser.Char.oneOf "eE"++ sign <- signPrefix <|> pure id++ x <- Text.Parser.Token.decimal++ return (Scientific.scientific 1 (fromInteger (sign x)))++{-| Parse a signed @Infinity@++ This corresponds to the @minus-infinity-literal@ and @plus-infinity-literal@+ rules from the official grammar+-}+doubleInfinity :: Parser Double+doubleInfinity = (do+ let negative = fmap (\_ -> negate) (char '-')+ sign <- negative <|> pure id+ a <- text "Infinity" >> return (1.0/0.0)+ return (sign a) ) <?> "literal"++{-| Parse an `Dhall.Syntax.Integer` literal++ This corresponds to the @integer-literal@ rule from the official grammar+-}+integerLiteral :: Parser Integer+integerLiteral = (do+ sign <- signPrefix+ a <- naturalLiteral+ return (sign (fromIntegral a)) ) <?> "literal"++{-| Parse a `Dhall.Syntax.Natural` literal++ This corresponds to the @natural-literal@ rule from the official grammar+-}+naturalLiteral :: Parser Natural+naturalLiteral = (do+ a <- binary+ <|> hexadecimal+ <|> decimal+ <|> (char '0' $> 0)+ return a ) <?> "literal"+ where+ binary = try (char '0' >> char 'b' >> Text.Megaparsec.Char.Lexer.binary)+ hexadecimal = try (char '0' >> char 'x' >> Text.Megaparsec.Char.Lexer.hexadecimal)+ decimal = do+ n <- headDigit+ ns <- many tailDigit+ return (mkNum (n:ns))+ where+ headDigit = decimalDigit nonZeroDigit <?> "non-zero digit"+ where+ nonZeroDigit c = '1' <= c && c <= '9'++ tailDigit = decimalDigit digit <?> "digit"++ decimalDigit predicate = do+ c <- Text.Parser.Char.satisfy predicate+ return (fromIntegral (Char.ord c - Char.ord '0'))++ mkNum = Data.Foldable.foldl' step 0+ where+ step acc x = acc * 10 + x++{-| Parse a 4-digit year++ This corresponds to the @date-fullyear@ rule from the official grammar+-}+dateFullYear :: Parser Integer+dateFullYear = do+ digits <- Monad.replicateM 4 (Text.Parser.Char.satisfy digit)++ return (digits `base` 10)++{-| Parse a 2-digit month++ This corresponds to the @date-month@ rule from the official grammar+-}+dateMonth :: Parser Int+dateMonth = do+ digits <- Monad.replicateM 2 (Text.Parser.Char.satisfy digit)++ let month = digits `base` 10++ if 1 <= month && month <= 12+ then return month+ else fail "Invalid month"++{-| Parse a 2-digit day of the month++ This corresponds to the @date-mday@ rule from the official grammar+-}+dateMday :: Parser Int+dateMday = do+ digits <- Monad.replicateM 2 (Text.Parser.Char.satisfy digit)++ let day = digits `base` 10++ if 1 <= day && day <= 31+ then return day+ else fail "Invalid day"++{-| Parse a 2-digit hour++ This corresponds to the @time-hour@ rule from the official grammar+-}+timeHour :: Parser Int+timeHour = do+ digits <- Monad.replicateM 2 (Text.Parser.Char.satisfy digit)++ let hour = digits `base` 10++ if 0 <= hour && hour < 24+ then return hour+ else fail "Invalid hour"++{-| Parse a 2-digit minute++ This corresponds to the @time-minute@ rule from the official grammar+-}+timeMinute :: Parser Int+timeMinute = do+ digits <- Monad.replicateM 2 (Text.Parser.Char.satisfy digit)++ let minute = digits `base` 10++ if 0 <= minute && minute < 60+ then return minute+ else fail "Invalid minute"++{-| Parse a 2-digit second++ This corresponds to the @time-second@ rule from the official grammar+-}+timeSecond :: Parser Pico+timeSecond = do+ digits <- Monad.replicateM 2 (Text.Parser.Char.satisfy digit)++ let second = digits `base` 10++ if 0 <= second && second < 60+ then return second+ else fail "Invalid second"++{-| Parse the fractional component of a second++ This corresponds to the @time-secfrac@ rule from the official grammar+-}+timeSecFrac :: Parser (Pico, Word)+timeSecFrac = do+ _ <- Text.Parser.Char.text "."++ digits <- some (Text.Parser.Char.satisfy digit)++ let precision = fromIntegral (length digits)++ return (fromRational ((digits `base` 10) % (10 ^ precision)), precision)++{-| Parse an identifier (i.e. a variable or built-in)++ Variables can have an optional index to disambiguate shadowed variables++ This corresponds to the @identifier@ rule from the official grammar+-}+identifier :: Parser Var+identifier = do+ x <- label++ let indexed = try $ do+ whitespace+ _at+ whitespace+ n <- naturalLiteral+ return (fromIntegral n)++ n <- indexed <|> pure 0+ return (V x n)++whitespaceChunk :: Parser ()+whitespaceChunk =+ choice+ [ void (Dhall.Parser.Combinators.takeWhile1 predicate)+ , void (Text.Parser.Char.text "\r\n" <?> "newline")+ , void lineComment+ , void blockComment+ ] <?> "whitespace"+ where+ predicate c = c == ' ' || c == '\t' || c == '\n'++-- | Parse a hexademical number and convert to the corresponding `Int`+hexNumber :: Parser Int+hexNumber = choice [ hexDigit, hexUpper, hexLower ]+ where+ hexDigit = do+ c <- Text.Parser.Char.satisfy predicate+ return (Char.ord c - Char.ord '0')+ where+ predicate c = '0' <= c && c <= '9'++ hexUpper = do+ c <- Text.Parser.Char.satisfy predicate+ return (10 + Char.ord c - Char.ord 'A')+ where+ predicate c = 'A' <= c && c <= 'F'++ hexLower = do+ c <- Text.Parser.Char.satisfy predicate+ return (10 + Char.ord c - Char.ord 'a')+ where+ predicate c = 'a' <= c && c <= 'f'++-- | Same as `lineComment` except that this doesn't parse the end-of-line+-- character+lineCommentPrefix :: Parser Text+lineCommentPrefix = do+ _ <- text "--"++ let predicate c = ('\x20' <= c && c <= '\x10FFFF') || c == '\t'++ commentText <- Dhall.Parser.Combinators.takeWhile predicate++ return ("--" <> commentText)++-- | Parse a Dhall's single-line comment, starting from `--` and until the+-- last character of the line /before/ the end-of-line character+lineComment :: Parser Text+lineComment = try (lineCommentPrefix <* endOfLine)++-- | Parsed text doesn't include opening braces+blockComment :: Parser Text+blockComment = do+ _ <- text "{-"+ c <- blockCommentContinue+ pure ("{-" <> c <> "-}")++blockCommentChunk :: Parser Text+blockCommentChunk =+ choice+ [ blockComment -- Nested block comment+ , characters+ , character+ , endOfLine+ ]+ where+ characters = (Dhall.Parser.Combinators.takeWhile1 predicate)+ where+ predicate c =+ '\x20' <= c && c <= '\x10FFFF' && c /= '-' && c /= '{'+ || c == '\n'+ || c == '\t'++ character = (Dhall.Parser.Combinators.satisfy predicate)+ where+ predicate c = '\x20' <= c && c <= '\x10FFFF' || c == '\n' || c == '\t'++blockCommentContinue :: Parser Text+blockCommentContinue = endOfComment <|> continue+ where+ endOfComment = void (text "-}") *> pure ""++ continue = do+ c <- blockCommentChunk+ c' <- blockCommentContinue+ pure (c <> c')++simpleLabel :: Bool -> Parser Text+simpleLabel allowReserved = try $ do+ c <- Text.Parser.Char.satisfy headCharacter+ rest <- Dhall.Parser.Combinators.takeWhile tailCharacter+ let t = Data.Text.cons c rest+ let isNotAKeyword = not $ t `Data.HashSet.member` reservedKeywords+ let isNotAReservedIdentifier = not $ t `Data.HashSet.member` reservedIdentifiers+ Monad.guard (isNotAKeyword && (allowReserved || isNotAReservedIdentifier))+ return t++headCharacter :: Char -> Bool+headCharacter c = alpha c || c == '_'++tailCharacter :: Char -> Bool+tailCharacter c = alphaNum c || c == '_' || c == '-' || c == '/'++backtickLabel :: Parser Text+backtickLabel = do+ _ <- char '`'+ t <- Dhall.Parser.Combinators.takeWhile predicate+ _ <- char '`'+ return t+ where+ predicate c =+ '\x20' <= c && c <= '\x5F'+ || '\x61' <= c && c <= '\x7E'++{-| Parse a braced sequence of comma-separated labels++ For example, this is used to parse the record projection syntax++ This corresponds to the @labels@ rule in the official grammar+-}+labels :: Parser [Text]+labels = do+ _openBrace++ whitespace++ nonEmptyLabels <|> emptyLabels+ where+ emptyLabels = do+ try (optional (_comma *> whitespace) *> _closeBrace)++ pure []++ nonEmptyLabels = do+ x <- try (optional (_comma *> whitespace) *> anyLabelOrSome)++ whitespace++ xs <- many (try (_comma *> whitespace *> anyLabelOrSome) <* whitespace)++ _ <- optional (_comma *> whitespace)++ _closeBrace++ return (x : xs)++{-| Parse a label (e.g. a variable\/field\/alternative name)++ Rejects labels that match built-in names (e.g. @Natural/even@)++ This corresponds to the @nonreserved-label@ rule in the official grammar+-}+label :: Parser Text+label = backtickLabel <|> simpleLabel False <?> "label"++{-| Same as `label` except that built-in names are allowed++ This corresponds to the @any-label@ rule in the official grammar+-}+anyLabel :: Parser Text+anyLabel = (do+ t <- backtickLabel <|> simpleLabel True+ return t ) <?> "any label"++{-| Same as `anyLabel` except that `Some` is allowed++ This corresponds to the @any-label-or-some@ rule in the official grammar+-}++anyLabelOrSome :: Parser Text+anyLabelOrSome = try anyLabel <|> ("Some" <$ _Some)++{-| Parse a valid Bash environment variable name++ This corresponds to the @bash-environment-variable@ rule in the official+ grammar+-}+bashEnvironmentVariable :: Parser Text+bashEnvironmentVariable = satisfy predicate0 <> star (satisfy predicate1)+ where+ predicate0 c = alpha c || c == '_'++ predicate1 c = alphaNum c || c == '_'++{-| Parse a valid POSIX environment variable name, which permits a wider range+ of characters than a Bash environment variable name++ This corresponds to the @posix-environment-variable@ rule in the official+ grammar+-}+posixEnvironmentVariable :: Parser Text+posixEnvironmentVariable = plus posixEnvironmentVariableCharacter++posixEnvironmentVariableCharacter :: Parser Text+posixEnvironmentVariableCharacter =+ escapeCharacter <|> satisfy predicate1+ where+ escapeCharacter = do+ _ <- char '\\'++ c <- Text.Parser.Char.satisfy (`elem` ("\"\\abfnrtv" :: String))++ case c of+ '"' -> return "\""+ '\\' -> return "\\"+ 'a' -> return "\a"+ 'b' -> return "\b"+ 'f' -> return "\f"+ 'n' -> return "\n"+ 'r' -> return "\r"+ 't' -> return "\t"+ 'v' -> return "\v"+ _ -> empty++ predicate1 c =+ ('\x20' <= c && c <= '\x21')+ || ('\x23' <= c && c <= '\x3C')+ || ('\x3E' <= c && c <= '\x5B')+ || ('\x5D' <= c && c <= '\x7E')++quotedPathCharacter :: Char -> Bool+quotedPathCharacter c =+ ('\x20' <= c && c <= '\x21')+ || ('\x23' <= c && c <= '\x2E')+ || ('\x30' <= c && c <= '\x10FFFF')++{-| The @pathComponent@ function uses this type to distinguish whether to parse+ a URL path component or a file path component+-}+data ComponentType = URLComponent | FileComponent++-- | Parse a path component+pathComponent :: ComponentType -> Parser Text+pathComponent componentType = do+ _ <- "/" :: Parser Text++ let pathData =+ case componentType of+ FileComponent ->+ Text.Megaparsec.takeWhile1P Nothing Dhall.Syntax.pathCharacter+ URLComponent ->+ star pchar++ let quotedPathData = do+ _ <- char '"'+ t <- Text.Megaparsec.takeWhile1P Nothing quotedPathCharacter+ _ <- char '"'+ return t++ case componentType of+ FileComponent -> quotedPathData <|> pathData+ URLComponent -> pathData++-- | Parse a `File`+file_ :: ComponentType -> Parser File+file_ componentType = do+ let emptyPath =+ case componentType of+ URLComponent -> pure (pure "")+ FileComponent -> empty++ path <- Data.List.NonEmpty.some1 (pathComponent componentType) <|> emptyPath++ let directory = Directory (reverse (Data.List.NonEmpty.init path))+ let file = Data.List.NonEmpty.last path++ return (File {..})++scheme_ :: Parser Scheme+scheme_ =+ ("http" :: Parser Text)+ *> ((("s" :: Parser Text) *> pure HTTPS) <|> pure HTTP)+ <* ("://" :: Parser Text)++{-| Parse an HTTP(S) URL without trailing whitespace++ This corresponds to the @http-raw@ rule in the official grammar+-}+httpRaw :: Parser URL+httpRaw = do+ scheme <- scheme_+ authority <- authority_+ path <- file_ URLComponent+ query <- optional (("?" :: Parser Text) *> query_)++ let headers = Nothing++ return (URL {..})++authority_ :: Parser Text+authority_ = option (try (userinfo <> "@")) <> host <> option (":" <> port)++userinfo :: Parser Text+userinfo = star (satisfy predicate <|> pctEncoded)+ where+ predicate c = unreserved c || subDelims c || c == ':'++host :: Parser Text+host = choice [ ipLiteral, try ipV4Address, domain ]++port :: Parser Text+port = star (satisfy digit)++ipLiteral :: Parser Text+ipLiteral = "[" <> (ipV6Address <|> ipVFuture) <> "]"++ipVFuture :: Parser Text+ipVFuture = "v" <> plus (satisfy hexdig) <> "." <> plus (satisfy predicate)+ where+ predicate c = unreserved c || subDelims c || c == ':'++ipV6Address :: Parser Text+ipV6Address =+ choice+ [ try alternative0+ , try alternative1+ , try alternative2+ , try alternative3+ , try alternative4+ , try alternative5+ , try alternative6+ , try alternative7+ , alternative8+ ]+ where+ alternative0 = count 6 (h16 <> ":") <> ls32++ alternative1 = "::" <> count 5 (h16 <> ":") <> ls32++ alternative2 = option h16 <> "::" <> count 4 (h16 <> ":") <> ls32++ alternative3 =+ option (h16 <> range 0 1 (try (":" <> h16)))+ <> "::"+ <> count 3 (h16 <> ":")+ <> ls32++ alternative4 =+ option (h16 <> range 0 2 (try (":" <> h16)))+ <> "::"+ <> count 2 (h16 <> ":")+ <> ls32++ alternative5 =+ option (h16 <> range 0 3 (try (":" <> h16)))+ <> "::"+ <> h16+ <> ":"+ <> ls32++ alternative6 =+ option (h16 <> range 0 4 (try (":" <> h16))) <> "::" <> ls32++ alternative7 =+ option (h16 <> range 0 5 (try (":" <> h16))) <> "::" <> h16++ alternative8 =+ option (h16 <> range 0 6 (try (":" <> h16))) <> "::"++h16 :: Parser Text+h16 = range 1 3 (satisfy hexdig)++ls32 :: Parser Text+ls32 = try (h16 <> ":" <> h16) <|> ipV4Address++ipV4Address :: Parser Text+ipV4Address = decOctet <> "." <> decOctet <> "." <> decOctet <> "." <> decOctet++decOctet :: Parser Text+decOctet =+ choice+ [ try alternative4+ , try alternative3+ , try alternative2+ , try alternative1+ , alternative0+ ]+ where+ alternative0 = satisfy digit++ alternative1 = satisfy predicate <> satisfy digit+ where+ predicate c = '\x31' <= c && c <= '\x39'++ alternative2 = "1" <> count 2 (satisfy digit)++ alternative3 = "2" <> satisfy predicate <> satisfy digit+ where+ predicate c = '\x30' <= c && c <= '\x34'++ alternative4 = "25" <> satisfy predicate+ where+ predicate c = '\x30' <= c && c <= '\x35'++domain :: Parser Text+domain = domainLabel <> star ("." <> domainLabel ) <> option "."++domainLabel :: Parser Text+domainLabel = plus alphaNum_ <> star (plus "-" <> plus alphaNum_)+ where+ alphaNum_ = satisfy alphaNum++pchar :: Parser Text+pchar = satisfy predicate <|> pctEncoded+ where+ predicate c = unreserved c || subDelims c || c == ':' || c == '@'++query_ :: Parser Text+query_ = star (pchar <|> satisfy predicate)+ where+ predicate c = c == '/' || c == '?'++pctEncoded :: Parser Text+pctEncoded = "%" <> count 2 (satisfy hexdig)++subDelims :: Char -> Bool+subDelims c = c `elem` ("!$&'*+;=" :: String)++unreserved :: Char -> Bool+unreserved c =+ alphaNum c || c == '-' || c == '.' || c == '_' || c == '~'++{-| A variation on `Text.Parser.Char.text` that doesn't quote the expected+ in error messages+-}+text :: Data.Text.Text -> Parser Text+text t = Text.Parser.Char.text t <?> Data.Text.unpack t+{-# INLINE text #-}++{-| A variation on `Text.Parser.Char.char` that doesn't quote the expected+ token in error messages+-}+char :: Char -> Parser Char+char c = Text.Parser.Char.char c <?> [ c ]+{-# INLINE char #-}++reserved :: Data.Text.Text -> Parser ()+reserved x = void (text x)++reservedChar :: Char -> Parser ()+reservedChar c = void (char c)++builtin :: Data.Text.Text -> Parser ()+builtin x = reserved x <?> "built-in"+{-# INLINE builtin #-}++operator :: Data.Text.Text -> Parser ()+operator x = reserved x <?> "operator"+{-# INLINE operator #-}++operatorChar :: Char -> Parser ()+operatorChar x = reservedChar x <?> "operator"+{-# INLINE operatorChar #-}++keyword :: Data.Text.Text -> Parser ()+keyword x = try (void (text x)) <?> "keyword"++{-| Parse the @if@ keyword++ This corresponds to the @if@ rule from the official grammar+-}+_if :: Parser ()+_if = keyword "if"++{-| Parse the @then@ keyword++ This corresponds to the @then@ rule from the official grammar+-}+_then :: Parser ()+_then = keyword "then"++{-| Parse the @else@ keyword++ This corresponds to the @else@ rule from the official grammar+-}+_else :: Parser ()+_else = keyword "else"++{-| Parse the @let@ keyword++ This corresponds to the @let@ rule from the official grammar+-}+_let :: Parser ()+_let = keyword "let"++{-| Parse the @in@ keyword++ This corresponds to the @in@ rule from the official grammar+-}+_in :: Parser ()+_in = keyword "in"++{-| Parse the @as@ keyword++ This corresponds to the @as@ rule from the official grammar+-}+_as :: Parser ()+_as = keyword "as"++{-| Parse the @using@ keyword++ This corresponds to the @using@ rule from the official grammar+-}+_using :: Parser ()+_using = keyword "using"++{-| Parse the @merge@ keyword++ This corresponds to the @merge@ rule from the official grammar+-}+_merge :: Parser ()+_merge = keyword "merge"++{-| Parse the @toMap@ keyword++ This corresponds to the @toMap@ rule from the official grammar+-}+_toMap :: Parser ()+_toMap = keyword "toMap"++{-| Parse the @showConstructor@ keyword++ This corresponds to the @showConstructor@ rule from the official grammar+-}+_showConstructor :: Parser ()+_showConstructor = keyword "showConstructor"++{-| Parse the @assert@ keyword++ This corresponds to the @assert@ rule from the official grammar+-}+_assert :: Parser ()+_assert = keyword "assert"++-- | Parse the @with@ keyword+_with :: Parser ()+_with = keyword "with"++{-| Parse the @Some@ built-in++ This corresponds to the @Some@ rule from the official grammar+-}+_Some :: Parser ()+_Some = keyword "Some"++{-| Parse the @None@ built-in++ This corresponds to the @None@ rule from the official grammar+-}+_None :: Parser ()+_None = builtin "None"++{-| Parse the @Natural/fold@ built-in++ This corresponds to the @Natural-fold@ rule from the official grammar+-}+_NaturalFold :: Parser ()+_NaturalFold = builtin "Natural/fold"++{-| Parse the @Natural/build@ built-in++ This corresponds to the @Natural-build@ rule from the official grammar+-}+_NaturalBuild :: Parser ()+_NaturalBuild = builtin "Natural/build"++{-| Parse the @Natural/isZero@ built-in++ This corresponds to the @Natural-isZero@ rule from the official grammar+-}+_NaturalIsZero :: Parser ()+_NaturalIsZero = builtin "Natural/isZero"++{-| Parse the @Natural/even@ built-in++ This corresponds to the @Natural-even@ rule from the official grammar+-}+_NaturalEven :: Parser ()+_NaturalEven = builtin "Natural/even"++{-| Parse the @Natural/odd@ built-in++ This corresponds to the @Natural-odd@ rule from the official grammar+-}+_NaturalOdd :: Parser ()+_NaturalOdd = builtin "Natural/odd"++{-| Parse the @Natural/toInteger@ built-in++ This corresponds to the @Natural-toInteger@ rule from the official grammar+-}+_NaturalToInteger :: Parser ()+_NaturalToInteger = builtin "Natural/toInteger"++{-| Parse the @Natural/show@ built-in++ This corresponds to the @Natural-show@ rule from the official grammar+-}+_NaturalShow :: Parser ()+_NaturalShow = builtin "Natural/show"++{-| Parse the @Natural/subtract@ built-in++ This corresponds to the @Natural-subtract@ rule from the official grammar+-}+_NaturalSubtract :: Parser ()+_NaturalSubtract = builtin "Natural/subtract"++{-| Parse the @Integer/clamp@ built-in++ This corresponds to the @Integer-clamp@ rule from the official grammar+-}+_IntegerClamp :: Parser ()+_IntegerClamp = builtin "Integer/clamp"++{-| Parse the @Integer/negate@ built-in++ This corresponds to the @Integer-negate@ rule from the official grammar+-}+_IntegerNegate :: Parser ()+_IntegerNegate = builtin "Integer/negate"++{-| Parse the @Integer/show@ built-in++ This corresponds to the @Integer-show@ rule from the official grammar+-}+_IntegerShow :: Parser ()+_IntegerShow = builtin "Integer/show"++{-| Parse the @Integer/toDouble@ built-in++ This corresponds to the @Integer-toDouble@ rule from the official grammar+-}+_IntegerToDouble :: Parser ()+_IntegerToDouble = builtin "Integer/toDouble"++{-| Parse the @Double/show@ built-in++ This corresponds to the @Double-show@ rule from the official grammar+-}+_DoubleShow :: Parser ()+_DoubleShow = builtin "Double/show"++{-| Parse the @List/build@ built-in++ This corresponds to the @List-build@ rule from the official grammar+-}+_ListBuild :: Parser ()+_ListBuild = builtin "List/build"++{-| Parse the @List/fold@ built-in++ This corresponds to the @List-fold@ rule from the official grammar+-}+_ListFold :: Parser ()+_ListFold = builtin "List/fold"++{-| Parse the @List/length@ built-in++ This corresponds to the @List-length@ rule from the official grammar+-}+_ListLength :: Parser ()+_ListLength = builtin "List/length"++{-| Parse the @List/head@ built-in++ This corresponds to the @List-head@ rule from the official grammar+-}+_ListHead :: Parser ()+_ListHead = builtin "List/head"++{-| Parse the @List/last@ built-in++ This corresponds to the @List-last@ rule from the official grammar+-}+_ListLast :: Parser ()+_ListLast = builtin "List/last"++{-| Parse the @List/indexed@ built-in++ This corresponds to the @List-indexed@ rule from the official grammar+-}+_ListIndexed :: Parser ()+_ListIndexed = builtin "List/indexed"++{-| Parse the @List/reverse@ built-in++ This corresponds to the @List-reverse@ rule from the official grammar+-}+_ListReverse :: Parser ()+_ListReverse = builtin "List/reverse"++{-| Parse the @Bool@ built-in++ This corresponds to the @Bool@ rule from the official grammar+-}+_Bool :: Parser ()+_Bool = builtin "Bool"++{-| Parse the @Bytes@ built-in++ This corresponds to the @Bytes@ rule from the official grammar+-}+_Bytes :: Parser ()+_Bytes = builtin "Bytes"++{-| Parse the @Optional@ built-in++ This corresponds to the @Optional@ rule from the official grammar+-}+_Optional :: Parser ()+_Optional = builtin "Optional"++{-| Parse the @Natural@ built-in++ This corresponds to the @Natural@ rule from the official grammar+-}+_Natural :: Parser ()+_Natural = builtin "Natural"++{-| Parse the @Integer@ built-in++ This corresponds to the @Integer@ rule from the official grammar+-}+_Integer :: Parser ()+_Integer = builtin "Integer"++{-| Parse the @Double@ built-in++ This corresponds to the @Double@ rule from the official grammar+-}+_Double :: Parser ()+_Double = builtin "Double"++{-| Parse the @Text@ built-in++ This corresponds to the @Text@ rule from the official grammar+-}+_Text :: Parser ()+_Text = builtin "Text"++{-| Parse the @Text/replace@ built-in++ This corresponds to the @Text-replace@ rule from the official grammar+-}+_TextReplace :: Parser ()+_TextReplace = builtin "Text/replace"++{-| Parse the @Text/show@ built-in++ This corresponds to the @Text-show@ rule from the official grammar+-}+_TextShow :: Parser ()+_TextShow = builtin "Text/show"++{-| Parse the @Date@ bult-in++ This corresponds to the @Date@ rule from the official grammar+-}+_Date :: Parser ()+_Date = builtin "Date"++{-| Parse the @Date/show@ built-in++ This corresponds to the @Date-show@ rule from the official grammar+-}+_DateShow :: Parser ()+_DateShow = builtin "Date/show"++{-| Parse the @Time@ bult-in++ This corresponds to the @Time@ rule from the official grammar+-}+_Time :: Parser ()+_Time = builtin "Time"++{-| Parse the @Time/show@ built-in++ This corresponds to the @Time-show@ rule from the official grammar+-}+_TimeShow :: Parser ()+_TimeShow = builtin "Time/show"++{-| Parse the @TimeZone@ bult-in++ This corresponds to the @TimeZone@ rule from the official grammar+-}+_TimeZone :: Parser ()+_TimeZone = builtin "TimeZone"++{-| Parse the @TimeZone/show@ built-in++ This corresponds to the @TimeZone-show@ rule from the official grammar+-}+_TimeZoneShow :: Parser ()+_TimeZoneShow = builtin "TimeZone/show"++{-| Parse the @List@ built-in++ This corresponds to the @List@ rule from the official grammar+-}+_List :: Parser ()+_List = builtin "List"++{-| Parse the @True@ built-in++ This corresponds to the @True@ rule from the official grammar+-}+_True :: Parser ()+_True = builtin "True"++{-| Parse the @False@ built-in++ This corresponds to the @False@ rule from the official grammar+-}+_False :: Parser ()+_False = builtin "False"++{-| Parse a @NaN@ literal++ This corresponds to the @NaN@ rule from the official grammar+-}+_NaN :: Parser ()+_NaN = builtin "NaN"++{-| Parse the @Type@ built-in++ This corresponds to the @Type@ rule from the official grammar+-}+_Type :: Parser ()+_Type = builtin "Type"++{-| Parse the @Kind@ built-in++ This corresponds to the @Kind@ rule from the official grammar+-}+_Kind :: Parser ()+_Kind = builtin "Kind"++{-| Parse the @Sort@ built-in++ This corresponds to the @Sort@ rule from the official grammar+-}+_Sort :: Parser ()+_Sort = builtin "Sort"++{-| Parse the @Location@ keyword++ This corresponds to the @Location@ rule from the official grammar+-}+_Location :: Parser ()+_Location = builtin "Location"++-- | Parse the @=@ symbol+_equal :: Parser ()+_equal = reservedChar '='++-- | Parse the @||@ symbol+_or :: Parser ()+_or = operator "||"++-- | Parse the @+@ symbol+_plus :: Parser ()+_plus = operatorChar '+'++-- | Parse the @++@ symbol+_textAppend :: Parser ()+_textAppend = operator "++"++-- | Parse the @#@ symbol+_listAppend :: Parser ()+_listAppend = operatorChar '#'++-- | Parse the @&&@ symbol+_and :: Parser ()+_and = operator "&&"++-- | Parse the @*@ symbol+_times :: Parser ()+_times = operatorChar '*'++-- | Parse the @==@ symbol+_doubleEqual :: Parser ()+_doubleEqual = operator "=="++-- | Parse the @!=@ symbol+_notEqual :: Parser ()+_notEqual = operator "!="++-- | Parse the @.@ symbol+_dot :: Parser ()+_dot = operatorChar '.'++-- | Parse the @{@ symbol+_openBrace :: Parser ()+_openBrace = reservedChar '{'++-- | Parse the @}@ symbol+_closeBrace :: Parser ()+_closeBrace = reservedChar '}'++-- | Parse the @[@] symbol+_openBracket :: Parser ()+_openBracket = reservedChar '['++-- | Parse the @]@ symbol+_closeBracket :: Parser ()+_closeBracket = reservedChar ']'++-- | Parse the @<@ symbol+_openAngle :: Parser ()+_openAngle = reservedChar '<'++-- | Parse the @>@ symbol+_closeAngle :: Parser ()+_closeAngle = reservedChar '>'++-- | Parse the @|@ symbol+_bar :: Parser ()+_bar = reservedChar '|'++-- | Parse the @,@ symbol+_comma :: Parser ()+_comma = reservedChar ',' <?> "\',\'"++-- | Parse the @(@ symbol+_openParens :: Parser ()+_openParens = reservedChar '('++-- | Parse the @)@ symbol+_closeParens :: Parser ()+_closeParens = reservedChar ')'++-- | Parse the @:@ symbol+_colon :: Parser ()+_colon = reservedChar ':'++-- | Parse the @\@@ symbol+_at :: Parser ()+_at = reservedChar '@' <?> "\"@\""++-- | Parse the equivalence symbol (@===@ or @≡@)+_equivalent :: Parser CharacterSet+_equivalent =+ (Unicode <$ char '≡' <?> "\"≡\"")+ <|> (ASCII <$ text "===" <?> "===")++-- | Parse the @missing@ keyword+_missing :: Parser ()+_missing =+ keyword "missing"+ *> Text.Megaparsec.notFollowedBy (Text.Parser.Char.satisfy tailCharacter)++-- | Parse the @?@ symbol+_importAlt :: Parser ()+_importAlt = operatorChar '?'++-- | Parse the record combine operator (@/\\@ or @∧@)+_combine :: Parser CharacterSet+_combine =+ (Unicode <$ char '∧' <?> "\"∧\"")+ <|> (ASCII <$ text "/\\" <?> "/\\")++-- | Parse the record type combine operator (@//\\\\@ or @⩓@)+_combineTypes :: Parser CharacterSet+_combineTypes =+ (Unicode <$ char '⩓' <?> "\"⩓\"")+ <|> (ASCII <$ text "//\\\\" <?> "//\\\\")++-- | Parse the record \"prefer\" operator (@//@ or @⫽@)+_prefer :: Parser CharacterSet+_prefer =+ (Unicode <$ char '⫽' <?> "\"⫽\"")+ <|> (ASCII <$ text "//" <?> "//")++-- | Parse a lambda (@\\@ or @λ@)+_lambda :: Parser CharacterSet+_lambda =+ (Unicode <$ char 'λ' <?> "\"λ\"")+ <|> (ASCII <$ char '\\' <?> "\\")++-- | Parse a forall (@forall@ or @∀@)+_forall :: Parser CharacterSet+_forall =+ (Unicode <$ char '∀' <?> "\"∀\"")+ <|> (ASCII <$ text "forall" <?> "forall")++-- | Parse a right arrow (@->@ or @→@)+_arrow :: Parser CharacterSet+_arrow =+ (Unicode <$ char '→' <?> "\"→\"")+ <|> (ASCII <$ text "->" <?> "->")++-- | Parse a double colon (@::@)+_doubleColon :: Parser ()+_doubleColon = operator "::"
@@ -8,16 +8,18 @@ , prettyExpr , CharacterSet(..)+ , defaultCharacterSet+ , detectCharacterSet , prettyCharacterSet - , layoutOpts+ , Dhall.Pretty.Internal.layout+ , Dhall.Pretty.Internal.layoutOpts++ , escapeEnvironmentVariable+ , UnescapedLabel(..)+ , escapeLabel++ , temporalToText ) where import Dhall.Pretty.Internal-import qualified Data.Text.Prettyprint.Doc as Pretty---- | Default layout options-layoutOpts :: Pretty.LayoutOptions-layoutOpts =- Pretty.defaultLayoutOptions- { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }
@@ -1,989 +1,1991 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# OPTIONS_GHC -Wall #-}--{-| This module provides internal pretty-printing utilities which are used by- other modules but are not part of the public facing API--}--module Dhall.Pretty.Internal (- Ann(..)- , annToAnsiStyle- , prettyExpr-- , CharacterSet(..)- , prettyCharacterSet-- , prettyVar- , pretty- , escapeText-- , prettyConst- , prettyLabel- , prettyAnyLabel- , prettyLabels- , prettyNatural- , prettyNumber- , prettyDouble- , prettyToStrictText- , prettyToString-- , docToStrictText-- , builtin- , keyword- , literal- , operator-- , colon- , comma- , dot- , equals- , forall- , label- , lambda- , langle- , lbrace- , lbracket- , lparen- , pipe- , rangle- , rarrow- , rbrace- , rbracket- , rparen- ) where--import Dhall.Core--#if MIN_VERSION_base(4,8,0)-#else-import Control.Applicative (Applicative(..), (<$>))-#endif-import Data.Foldable-import Data.Monoid ((<>))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty, space)-import Dhall.Map (Map)-import Dhall.Set (Set)-import Numeric.Natural (Natural)-import Prelude hiding (succ)-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal--import qualified Data.Char-import qualified Data.HashSet-import qualified Data.List-import qualified Data.Set-import qualified Data.Text as Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty-import qualified Dhall.Map-import qualified Dhall.Set--{-| Annotation type used to tag elements in a pretty-printed document for- syntax highlighting purposes--}-data Ann- = Keyword -- ^ Used for syntactic keywords- | Syntax -- ^ Syntax punctuation such as commas, parenthesis, and braces- | Label -- ^ Record labels- | Literal -- ^ Literals such as integers and strings- | Builtin -- ^ Builtin types and values- | Operator -- ^ Operators--{-| Convert annotations to their corresponding color for syntax highlighting- purposes--}-annToAnsiStyle :: Ann -> Terminal.AnsiStyle-annToAnsiStyle Keyword = Terminal.bold <> Terminal.colorDull Terminal.Green-annToAnsiStyle Syntax = Terminal.bold <> Terminal.colorDull Terminal.Green-annToAnsiStyle Label = mempty-annToAnsiStyle Literal = Terminal.colorDull Terminal.Magenta-annToAnsiStyle Builtin = Terminal.underlined-annToAnsiStyle Operator = Terminal.bold <> Terminal.colorDull Terminal.Green--data CharacterSet = ASCII | Unicode---- | Pretty print an expression-prettyExpr :: Pretty a => Expr s a -> Doc Ann-prettyExpr = prettyCharacterSet Unicode--{-| Internal utility for pretty-printing, used when generating element lists- to supply to `enclose` or `enclose'`. This utility indicates that the- compact represent is the same as the multi-line representation for each- element--}-duplicate :: a -> (a, a)-duplicate x = (x, x)---- Annotation helpers-keyword, syntax, label, literal, builtin, operator :: Doc Ann -> Doc Ann-keyword = Pretty.annotate Keyword-syntax = Pretty.annotate Syntax-label = Pretty.annotate Label-literal = Pretty.annotate Literal-builtin = Pretty.annotate Builtin-operator = Pretty.annotate Operator--comma, lbracket, rbracket, langle, rangle, lbrace, rbrace, lparen, rparen, pipe, backtick, dollar, colon, equals, dot :: Doc Ann-comma = syntax Pretty.comma-lbracket = syntax Pretty.lbracket-rbracket = syntax Pretty.rbracket-langle = syntax Pretty.langle-rangle = syntax Pretty.rangle-lbrace = syntax Pretty.lbrace-rbrace = syntax Pretty.rbrace-lparen = syntax Pretty.lparen-rparen = syntax Pretty.rparen-pipe = syntax Pretty.pipe-backtick = syntax "`"-dollar = syntax "$"-colon = syntax ":"-equals = syntax "="-dot = syntax "."--lambda :: CharacterSet -> Doc Ann-lambda Unicode = syntax "λ"-lambda ASCII = syntax "\\"--forall :: CharacterSet -> Doc Ann-forall Unicode = syntax "∀"-forall ASCII = syntax "forall "--rarrow :: CharacterSet -> Doc Ann-rarrow Unicode = syntax "→"-rarrow ASCII = syntax "->"---- | Pretty-print a list-list :: [Doc Ann] -> Doc Ann-list [] = lbracket <> rbracket-list docs =- enclose- (lbracket <> space)- (lbracket <> space)- (comma <> space)- (comma <> space)- (space <> rbracket)- rbracket- (fmap duplicate docs)---- | Pretty-print union types and literals-angles :: [(Doc Ann, Doc Ann)] -> Doc Ann-angles [] = langle <> rangle-angles docs =- enclose- (langle <> space)- (langle <> space)- (space <> pipe <> space)- (pipe <> space)- (space <> rangle)- rangle- docs---- | Pretty-print record types and literals-braces :: [(Doc Ann, Doc Ann)] -> Doc Ann-braces [] = lbrace <> rbrace-braces docs =- enclose- (lbrace <> space)- (lbrace <> space)- (comma <> space)- (comma <> space)- (space <> rbrace)- rbrace- docs---- | Pretty-print anonymous functions and function types-arrows :: CharacterSet -> [(Doc Ann, Doc Ann)] -> Doc Ann-arrows ASCII =- enclose'- ""- " "- (" " <> rarrow ASCII <> " ")- (rarrow ASCII <> " ")-arrows Unicode =- enclose'- ""- " "- (" " <> rarrow Unicode <> " ")- (rarrow Unicode <> " ")--combine :: CharacterSet -> Text-combine ASCII = "/\\"-combine Unicode = "∧"--combineTypes :: CharacterSet -> Text-combineTypes ASCII = "//\\\\"-combineTypes Unicode = "⩓"--prefer :: CharacterSet -> Text-prefer ASCII = "//"-prefer Unicode = "⫽"--{-| Format an expression that holds a variable number of elements, such as a- list, record, or union--}-enclose- :: Doc ann- -- ^ Beginning document for compact representation- -> Doc ann- -- ^ Beginning document for multi-line representation- -> Doc ann- -- ^ Separator for compact representation- -> Doc ann- -- ^ Separator for multi-line representation- -> Doc ann- -- ^ Ending document for compact representation- -> Doc ann- -- ^ Ending document for multi-line representation- -> [(Doc ann, Doc ann)]- -- ^ Elements to format, each of which is a pair: @(compact, multi-line)@- -> Doc ann-enclose beginShort _ _ _ endShort _ [] =- beginShort <> endShort- where-enclose beginShort beginLong sepShort sepLong endShort endLong docs =- Pretty.group- (Pretty.flatAlt- (Pretty.align- (mconcat (zipWith combineLong (beginLong : repeat sepLong) docsLong) <> endLong)- )- (mconcat (zipWith combineShort (beginShort : repeat sepShort) docsShort) <> endShort)- )- where- docsShort = fmap fst docs-- docsLong = fmap snd docs-- combineLong x y = x <> y <> Pretty.hardline-- combineShort x y = x <> y--{-| Format an expression that holds a variable number of elements without a- trailing document such as nested `let`, nested lambdas, or nested `forall`s--}-enclose'- :: Doc ann- -- ^ Beginning document for compact representation- -> Doc ann- -- ^ Beginning document for multi-line representation- -> Doc ann- -- ^ Separator for compact representation- -> Doc ann- -- ^ Separator for multi-line representation- -> [(Doc ann, Doc ann)]- -- ^ Elements to format, each of which is a pair: @(compact, multi-line)@- -> Doc ann-enclose' beginShort beginLong sepShort sepLong docs =- Pretty.group (Pretty.flatAlt long short)- where- longLines = zipWith (<>) (beginLong : repeat sepLong) docsLong-- long =- Pretty.align (mconcat (Data.List.intersperse Pretty.hardline longLines))-- short = mconcat (zipWith (<>) (beginShort : repeat sepShort) docsShort)-- docsShort = fmap fst docs-- docsLong = fmap snd docs--alpha :: Char -> Bool-alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')--digit :: Char -> Bool-digit c = '\x30' <= c && c <= '\x39'--headCharacter :: Char -> Bool-headCharacter c = alpha c || c == '_'--tailCharacter :: Char -> Bool-tailCharacter c = alpha c || digit c || c == '_' || c == '-' || c == '/'--prettyLabelShared :: Bool -> Text -> Doc Ann-prettyLabelShared allowReserved a = label doc- where- doc =- case Text.uncons a of- Just (h, t)- | headCharacter h && Text.all tailCharacter t && (allowReserved || not (Data.HashSet.member a reservedIdentifiers))- -> Pretty.pretty a- _ -> backtick <> Pretty.pretty a <> backtick--prettyLabel :: Text -> Doc Ann-prettyLabel = prettyLabelShared False--prettyAnyLabel :: Text -> Doc Ann-prettyAnyLabel = prettyLabelShared True--prettyLabels :: Set Text -> Doc Ann-prettyLabels a- | Data.Set.null (Dhall.Set.toSet a) =- lbrace <> rbrace- | otherwise =- braces (map (duplicate . prettyAnyLabel) (Dhall.Set.toList a))--prettyNumber :: Integer -> Doc Ann-prettyNumber = literal . Pretty.pretty--prettyNatural :: Natural -> Doc Ann-prettyNatural = literal . Pretty.pretty--prettyDouble :: Double -> Doc Ann-prettyDouble = literal . Pretty.pretty--prettyConst :: Const -> Doc Ann-prettyConst Type = builtin "Type"-prettyConst Kind = builtin "Kind"-prettyConst Sort = builtin "Sort"--prettyVar :: Var -> Doc Ann-prettyVar (V x 0) = label (Pretty.unAnnotate (prettyLabel x))-prettyVar (V x n) = label (Pretty.unAnnotate (prettyLabel x <> "@" <> prettyNumber n))--prettyCharacterSet :: Pretty a => CharacterSet -> Expr s a -> Doc Ann-prettyCharacterSet characterSet = prettyExpression- where- prettyExpression a0@(Lam _ _ _) =- arrows characterSet (fmap duplicate (docs a0))- where- docs (Lam a b c) = Pretty.group (Pretty.flatAlt long short) : docs c- where- long = (lambda characterSet <> space)- <> Pretty.align- ( (lparen <> space)- <> prettyLabel a- <> Pretty.hardline- <> (colon <> space)- <> prettyExpression b- <> Pretty.hardline- <> rparen- )-- short = (lambda characterSet <> lparen)- <> prettyLabel a- <> (space <> colon <> space)- <> prettyExpression b- <> rparen- docs (Note _ c) = docs c- docs c = [ prettyExpression c ]- prettyExpression a0@(BoolIf _ _ _) =- Pretty.group (Pretty.flatAlt long short)- where- prefixesLong =- " "- : cycle- [ Pretty.hardline <> keyword "then" <> " "- , Pretty.hardline <> keyword "else" <> " "- ]-- prefixesShort =- ""- : cycle- [ space <> keyword "then" <> space- , space <> keyword "else" <> space- ]-- longLines = zipWith (<>) prefixesLong (docsLong a0)-- long =- Pretty.align (mconcat (Data.List.intersperse Pretty.hardline longLines))-- short = mconcat (zipWith (<>) prefixesShort (docsShort a0))-- docsLong (BoolIf a b c) =- docLong ++ docsLong c- where- docLong =- [ keyword "if" <> " " <> prettyExpression a- , prettyExpression b- ]- docsLong (Note _ c) = docsLong c- docsLong c = [ prettyExpression c ]-- docsShort (BoolIf a b c) =- docShort ++ docsShort c- where- docShort =- [ keyword "if" <> " " <> prettyExpression a- , prettyExpression b- ]- docsShort (Note _ c) = docsShort c- docsShort c = [ prettyExpression c ]- prettyExpression (Let as b) =- enclose' "" "" space Pretty.hardline- (fmap duplicate (fmap docA (toList as)) ++ [ docB ])- where- docA (Binding c Nothing e) =- Pretty.group (Pretty.flatAlt long short)- where- long = keyword "let" <> space- <> Pretty.align- ( prettyLabel c- <> space <> equals- <> Pretty.hardline- <> " "- <> prettyExpression e- )-- short = keyword "let" <> space- <> prettyLabel c- <> (space <> equals <> space)- <> prettyExpression e- docA (Binding c (Just d) e) =- Pretty.group (Pretty.flatAlt long short)- where- long = keyword "let" <> space- <> Pretty.align- ( prettyLabel c- <> Pretty.hardline- <> colon <> space- <> prettyExpression d- <> Pretty.hardline- <> equals <> space- <> prettyExpression e- )-- short = keyword "let" <> space- <> prettyLabel c- <> space <> colon <> space- <> prettyExpression d- <> space <> equals <> space- <> prettyExpression e-- docB =- ( keyword "in" <> " " <> prettyExpression b- , keyword "in" <> " " <> prettyExpression b- )- prettyExpression a0@(Pi _ _ _) =- arrows characterSet (fmap duplicate (docs a0))- where- docs (Pi "_" b c) = prettyOperatorExpression b : docs c- docs (Pi a b c) = Pretty.group (Pretty.flatAlt long short) : docs c- where- long = forall characterSet <> space- <> Pretty.align- ( lparen <> space- <> prettyLabel a- <> Pretty.hardline- <> colon <> space- <> prettyExpression b- <> Pretty.hardline- <> rparen- )-- short = forall characterSet <> lparen- <> prettyLabel a- <> space <> colon <> space- <> prettyExpression b- <> rparen- docs (Note _ c) = docs c- docs c = [ prettyExpression c ]- prettyExpression (Note _ a) =- prettyExpression a- prettyExpression a0 =- prettyAnnotatedExpression a0-- prettyAnnotatedExpression :: Pretty a => Expr s a -> Doc Ann- prettyAnnotatedExpression (Merge a b (Just c)) =- Pretty.group (Pretty.flatAlt long short)- where- long =- Pretty.align- ( keyword "merge"- <> Pretty.hardline- <> prettyImportExpression a- <> Pretty.hardline- <> prettyImportExpression b- <> Pretty.hardline- <> colon <> space- <> prettyApplicationExpression c- )-- short = keyword "merge" <> space- <> prettyImportExpression a- <> " "- <> prettyImportExpression b- <> space <> colon <> space- <> prettyApplicationExpression c- prettyAnnotatedExpression (Merge a b Nothing) =- Pretty.group (Pretty.flatAlt long short)- where- long =- Pretty.align- ( keyword "merge"- <> Pretty.hardline- <> prettyImportExpression a- <> Pretty.hardline- <> prettyImportExpression b- )-- short = keyword "merge" <> space- <> prettyImportExpression a- <> " "- <> prettyImportExpression b- prettyAnnotatedExpression a0@(Annot _ _) =- enclose'- ""- " "- (" " <> colon <> " ")- (colon <> space)- (fmap duplicate (docs a0))- where- docs (Annot a b) = prettyOperatorExpression a : docs b- docs (Note _ b) = docs b- docs b = [ prettyExpression b ]- prettyAnnotatedExpression (ListLit (Just a) b) =- list (map prettyExpression (Data.Foldable.toList b))- <> " : "- <> prettyApplicationExpression (App List a)- prettyAnnotatedExpression (OptionalLit a b) =- list (map prettyExpression (Data.Foldable.toList b))- <> " : "- <> prettyApplicationExpression (App Optional a)- prettyAnnotatedExpression (Note _ a) =- prettyAnnotatedExpression a- prettyAnnotatedExpression a0 =- prettyOperatorExpression a0-- prettyOperatorExpression :: Pretty a => Expr s a -> Doc Ann- prettyOperatorExpression = prettyImportAltExpression-- prettyOperator :: Text -> [Doc Ann] -> Doc Ann- prettyOperator op docs =- enclose'- ""- prefix- (" " <> operator (Pretty.pretty op) <> " ")- (operator (Pretty.pretty op) <> spacer)- (reverse (fmap duplicate docs))- where- prefix = if Text.length op == 1 then " " else " "-- spacer = if Text.length op == 1 then " " else " "-- prettyImportAltExpression :: Pretty a => Expr s a -> Doc Ann- prettyImportAltExpression a0@(ImportAlt _ _) =- prettyOperator "?" (docs a0)- where- docs (ImportAlt a b) = prettyOrExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyOrExpression b ]- prettyImportAltExpression (Note _ a) =- prettyImportAltExpression a- prettyImportAltExpression a0 =- prettyOrExpression a0-- prettyOrExpression :: Pretty a => Expr s a -> Doc Ann- prettyOrExpression a0@(BoolOr _ _) =- prettyOperator "||" (docs a0)- where- docs (BoolOr a b) = prettyPlusExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyPlusExpression b ]- prettyOrExpression (Note _ a) =- prettyOrExpression a- prettyOrExpression a0 =- prettyPlusExpression a0-- prettyPlusExpression :: Pretty a => Expr s a -> Doc Ann- prettyPlusExpression a0@(NaturalPlus _ _) =- prettyOperator "+" (docs a0)- where- docs (NaturalPlus a b) = prettyTextAppendExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyTextAppendExpression b ]- prettyPlusExpression (Note _ a) =- prettyPlusExpression a- prettyPlusExpression a0 =- prettyTextAppendExpression a0-- prettyTextAppendExpression :: Pretty a => Expr s a -> Doc Ann- prettyTextAppendExpression a0@(TextAppend _ _) =- prettyOperator "++" (docs a0)- where- docs (TextAppend a b) = prettyListAppendExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyListAppendExpression b ]- prettyTextAppendExpression (Note _ a) =- prettyTextAppendExpression a- prettyTextAppendExpression a0 =- prettyListAppendExpression a0-- prettyListAppendExpression :: Pretty a => Expr s a -> Doc Ann- prettyListAppendExpression a0@(ListAppend _ _) =- prettyOperator "#" (docs a0)- where- docs (ListAppend a b) = prettyAndExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyAndExpression b ]- prettyListAppendExpression (Note _ a) =- prettyListAppendExpression a- prettyListAppendExpression a0 =- prettyAndExpression a0-- prettyAndExpression :: Pretty a => Expr s a -> Doc Ann- prettyAndExpression a0@(BoolAnd _ _) =- prettyOperator "&&" (docs a0)- where- docs (BoolAnd a b) = prettyCombineExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyCombineExpression b ]- prettyAndExpression (Note _ a) =- prettyAndExpression a- prettyAndExpression a0 =- prettyCombineExpression a0-- prettyCombineExpression :: Pretty a => Expr s a -> Doc Ann- prettyCombineExpression a0@(Combine _ _) =- prettyOperator (combine characterSet) (docs a0)- where- docs (Combine a b) = prettyPreferExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyPreferExpression b ]- prettyCombineExpression (Note _ a) =- prettyCombineExpression a- prettyCombineExpression a0 =- prettyPreferExpression a0-- prettyPreferExpression :: Pretty a => Expr s a -> Doc Ann- prettyPreferExpression a0@(Prefer _ _) =- prettyOperator (prefer characterSet) (docs a0)- where- docs (Prefer a b) = prettyCombineTypesExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyCombineTypesExpression b ]- prettyPreferExpression (Note _ a) =- prettyPreferExpression a- prettyPreferExpression a0 =- prettyCombineTypesExpression a0-- prettyCombineTypesExpression :: Pretty a => Expr s a -> Doc Ann- prettyCombineTypesExpression a0@(CombineTypes _ _) =- prettyOperator (combineTypes characterSet) (docs a0)- where- docs (CombineTypes a b) = prettyTimesExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyTimesExpression b ]- prettyCombineTypesExpression (Note _ a) =- prettyCombineTypesExpression a- prettyCombineTypesExpression a0 =- prettyTimesExpression a0-- prettyTimesExpression :: Pretty a => Expr s a -> Doc Ann- prettyTimesExpression a0@(NaturalTimes _ _) =- prettyOperator "*" (docs a0)- where- docs (NaturalTimes a b) = prettyEqualExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyEqualExpression b ]- prettyTimesExpression (Note _ a) =- prettyTimesExpression a- prettyTimesExpression a0 =- prettyEqualExpression a0-- prettyEqualExpression :: Pretty a => Expr s a -> Doc Ann- prettyEqualExpression a0@(BoolEQ _ _) =- prettyOperator "==" (docs a0)- where- docs (BoolEQ a b) = prettyNotEqualExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyNotEqualExpression b ]- prettyEqualExpression (Note _ a) =- prettyEqualExpression a- prettyEqualExpression a0 =- prettyNotEqualExpression a0-- prettyNotEqualExpression :: Pretty a => Expr s a -> Doc Ann- prettyNotEqualExpression a0@(BoolNE _ _) =- prettyOperator "!=" (docs a0)- where- docs (BoolNE a b) = prettyApplicationExpression b : docs a- docs (Note _ b) = docs b- docs b = [ prettyApplicationExpression b ]- prettyNotEqualExpression (Note _ a) =- prettyNotEqualExpression a- prettyNotEqualExpression a0 =- prettyApplicationExpression a0-- prettyApplicationExpression :: Pretty a => Expr s a -> Doc Ann- prettyApplicationExpression a0 = case a0 of- App _ _ -> result- Some _ -> result- Note _ b -> prettyApplicationExpression b- _ -> prettyImportExpression a0- where- result = enclose' "" "" " " "" (fmap duplicate (reverse (docs a0)))-- docs (App a b) = prettyImportExpression b : docs a- docs (Some a) = [ prettyImportExpression a , builtin "Some" ]- docs (Note _ b) = docs b- docs b = [ prettyImportExpression b ]-- prettyImportExpression :: Pretty a => Expr s a -> Doc Ann- prettyImportExpression (Embed a) =- Pretty.pretty a- prettyImportExpression (Note _ a) =- prettyImportExpression a- prettyImportExpression a0 =- prettySelectorExpression a0-- prettySelectorExpression :: Pretty a => Expr s a -> Doc Ann- prettySelectorExpression (Field a b) =- prettySelectorExpression a <> dot <> prettyAnyLabel b- prettySelectorExpression (Project a (Left b)) =- prettySelectorExpression a <> dot <> prettyLabels b- prettySelectorExpression (Project a (Right b)) =- prettySelectorExpression a- <> dot- <> lparen- <> prettyExpression b- <> rparen- prettySelectorExpression (Note _ b) =- prettySelectorExpression b- prettySelectorExpression a0 =- prettyPrimitiveExpression a0-- prettyPrimitiveExpression :: Pretty a => Expr s a -> Doc Ann- prettyPrimitiveExpression (Var a) =- prettyVar a- prettyPrimitiveExpression (Const k) =- prettyConst k- prettyPrimitiveExpression Bool =- builtin "Bool"- prettyPrimitiveExpression Natural =- builtin "Natural"- prettyPrimitiveExpression NaturalFold =- builtin "Natural/fold"- prettyPrimitiveExpression NaturalBuild =- builtin "Natural/build"- prettyPrimitiveExpression NaturalIsZero =- builtin "Natural/isZero"- prettyPrimitiveExpression NaturalEven =- builtin "Natural/even"- prettyPrimitiveExpression NaturalOdd =- builtin "Natural/odd"- prettyPrimitiveExpression NaturalToInteger =- builtin "Natural/toInteger"- prettyPrimitiveExpression NaturalShow =- builtin "Natural/show"- prettyPrimitiveExpression Integer =- builtin "Integer"- prettyPrimitiveExpression IntegerShow =- builtin "Integer/show"- prettyPrimitiveExpression IntegerToDouble =- builtin "Integer/toDouble"- prettyPrimitiveExpression Double =- builtin "Double"- prettyPrimitiveExpression DoubleShow =- builtin "Double/show"- prettyPrimitiveExpression Text =- builtin "Text"- prettyPrimitiveExpression TextShow =- builtin "Text/show"- prettyPrimitiveExpression List =- builtin "List"- prettyPrimitiveExpression ListBuild =- builtin "List/build"- prettyPrimitiveExpression ListFold =- builtin "List/fold"- prettyPrimitiveExpression ListLength =- builtin "List/length"- prettyPrimitiveExpression ListHead =- builtin "List/head"- prettyPrimitiveExpression ListLast =- builtin "List/last"- prettyPrimitiveExpression ListIndexed =- builtin "List/indexed"- prettyPrimitiveExpression ListReverse =- builtin "List/reverse"- prettyPrimitiveExpression Optional =- builtin "Optional"- prettyPrimitiveExpression None =- builtin "None"- prettyPrimitiveExpression OptionalFold =- builtin "Optional/fold"- prettyPrimitiveExpression OptionalBuild =- builtin "Optional/build"- prettyPrimitiveExpression (BoolLit True) =- builtin "True"- prettyPrimitiveExpression (BoolLit False) =- builtin "False"- prettyPrimitiveExpression (IntegerLit a)- | 0 <= a = literal "+" <> prettyNumber a- | otherwise = prettyNumber a- prettyPrimitiveExpression (NaturalLit a) =- prettyNatural a- prettyPrimitiveExpression (DoubleLit a) =- prettyDouble a- prettyPrimitiveExpression (TextLit a) =- prettyChunks a- prettyPrimitiveExpression (Record a) =- prettyRecord a- prettyPrimitiveExpression (RecordLit a) =- prettyRecordLit a- prettyPrimitiveExpression (Union a) =- prettyUnion a- prettyPrimitiveExpression (UnionLit a b c) =- prettyUnionLit a b c- prettyPrimitiveExpression (ListLit Nothing b) =- list (map prettyExpression (Data.Foldable.toList b))- prettyPrimitiveExpression (Note _ b) =- prettyPrimitiveExpression b- prettyPrimitiveExpression a =- Pretty.group (Pretty.flatAlt long short)- where- long =- Pretty.align- (lparen <> space <> prettyExpression a <> Pretty.hardline <> rparen)-- short = lparen <> prettyExpression a <> rparen-- prettyKeyValue :: Pretty a => Doc Ann -> (Text, Expr s a) -> (Doc Ann, Doc Ann)- prettyKeyValue separator (key, val) =- ( prettyAnyLabel key- <> " "- <> separator- <> " "- <> prettyExpression val- , prettyAnyLabel key- <> " "- <> separator- <> long- )- where- long = Pretty.hardline <> " " <> prettyExpression val-- prettyRecord :: Pretty a => Map Text (Expr s a) -> Doc Ann- prettyRecord =- braces . map (prettyKeyValue colon) . Dhall.Map.toList-- prettyRecordLit :: Pretty a => Map Text (Expr s a) -> Doc Ann- prettyRecordLit a- | Data.Foldable.null a =- lbrace <> equals <> rbrace- | otherwise- = braces (map (prettyKeyValue equals) (Dhall.Map.toList a))-- prettyAlternative (key, Just val) = prettyKeyValue colon (key, val)- prettyAlternative (key, Nothing ) = duplicate (prettyAnyLabel key)-- prettyUnion :: Pretty a => Map Text (Maybe (Expr s a)) -> Doc Ann- prettyUnion =- angles . map prettyAlternative . Dhall.Map.toList-- prettyUnionLit- :: Pretty a- => Text -> Expr s a -> Map Text (Maybe (Expr s a)) -> Doc Ann- prettyUnionLit a b c =- angles (front : map prettyAlternative (Dhall.Map.toList c))- where- front = prettyKeyValue equals (a, b)-- prettyChunks :: Pretty a => Chunks s a -> Doc Ann- prettyChunks (Chunks a b) =- if any (\(builder, _) -> hasNewLine builder) a || hasNewLine b- then Pretty.flatAlt long short- else short- where- long =- Pretty.align- ( literal ("''" <> Pretty.hardline)- <> Pretty.align- (foldMap prettyMultilineChunk a <> prettyMultilineBuilder b)- <> literal "''"- )-- short =- literal "\"" <> foldMap prettyChunk a <> literal (prettyText b <> "\"")-- hasNewLine = Text.any (== '\n')-- prettyMultilineChunk (c, d) =- prettyMultilineBuilder c- <> dollar- <> lbrace- <> prettyExpression d- <> rbrace-- prettyMultilineBuilder builder = literal (mconcat docs)- where- lazyLines = Text.splitOn "\n" (escapeSingleQuotedText builder)-- docs =- Data.List.intersperse Pretty.hardline (fmap Pretty.pretty lazyLines)-- prettyChunk (c, d) =- prettyText c- <> syntax "${"- <> prettyExpression d- <> syntax rbrace-- prettyText t = literal (Pretty.pretty (escapeText t))---- | Pretty-print a value-pretty :: Pretty a => a -> Text-pretty = Pretty.renderStrict . Pretty.layoutPretty options . Pretty.pretty- where- options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }---- | Escape a `Text` literal using Dhall's escaping rules for single-quoted--- @Text@-escapeSingleQuotedText :: Text -> Text-escapeSingleQuotedText inputBuilder = outputBuilder- where- outputText = substitute "${" "''${" (substitute "''" "'''" inputBuilder)-- outputBuilder = outputText-- substitute before after = Text.intercalate after . Text.splitOn before--{-| Escape a `Text` literal using Dhall's escaping rules-- Note that the result does not include surrounding quotes--}-escapeText :: Text -> Text-escapeText text = Text.concatMap adapt text- where- adapt c- | '\x20' <= c && c <= '\x21' = Text.singleton c- -- '\x22' == '"'- | '\x23' == c = Text.singleton c- -- '\x24' == '$'- | '\x25' <= c && c <= '\x5B' = Text.singleton c- -- '\x5C' == '\\'- | '\x5D' <= c && c <= '\x10FFFF' = Text.singleton c- | c == '"' = "\\\""- | c == '$' = "\\$"- | c == '\\' = "\\\\"- | c == '\b' = "\\b"- | c == '\f' = "\\f"- | c == '\n' = "\\n"- | c == '\r' = "\\r"- | c == '\t' = "\\t"- | otherwise = "\\u" <> showDigits (Data.Char.ord c)-- showDigits r0 = Text.pack (map showDigit [q1, q2, q3, r3])- where- (q1, r1) = r0 `quotRem` 4096- (q2, r2) = r1 `quotRem` 256- (q3, r3) = r2 `quotRem` 16-- showDigit n- | n < 10 = Data.Char.chr (Data.Char.ord '0' + n)- | otherwise = Data.Char.chr (Data.Char.ord 'A' + n - 10)--prettyToString :: Pretty a => a -> String-prettyToString =- Pretty.renderString . Pretty.layoutPretty options . Pretty.pretty- where- options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }--docToStrictText :: Doc ann -> Text.Text-docToStrictText = Pretty.renderStrict . Pretty.layoutPretty options- where- options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }--prettyToStrictText :: Pretty a => a -> Text.Text-prettyToStrictText = docToStrictText . Pretty.pretty+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -Wall #-}++{-| This module provides internal pretty-printing utilities which are used by+ other modules but are not part of the public facing API+-}++module Dhall.Pretty.Internal (+ Ann(..)+ , annToAnsiStyle+ , prettyExpr+ , prettySrcExpr++ , CharacterSet(..)+ , defaultCharacterSet+ , detectCharacterSet+ , prettyCharacterSet+ , prettyImportExpression++ , prettyVar+ , pretty_+ , escapeText_+ , escapeEnvironmentVariable+ , prettyEnvironmentVariable++ , prettyConst+ , UnescapedLabel(..)+ , escapeLabel+ , prettyLabel+ , prettyAnyLabel+ , prettyLabels+ , prettyNatural+ , prettyNumber+ , prettyInt+ , prettyDouble+ , prettyToStrictText+ , prettyToString+ , prettyBase16+ , layout+ , layoutOpts++ , docToStrictText++ , builtin+ , keyword+ , literal+ , operator++ , colon+ , comma+ , dot+ , equals+ , forall_+ , label+ , lambda+ , langle+ , lbrace+ , lbracket+ , lparen+ , pipe+ , rangle+ , rarrow+ , rbrace+ , rbracket+ , rparen++ , temporalToText+ ) where++import Control.DeepSeq (NFData)+import Data.Aeson+ ( FromJSON (..)+ , Value (String)+ )+import Data.Aeson.Types (typeMismatch, unexpected)+import Data.ByteString (ByteString)+import Data.Data (Data)+import Data.Foldable+import Data.List.NonEmpty (NonEmpty (..))+import Data.Text (Text)+import Dhall.Map (Map)+import Dhall.Src (Src (..))+import Dhall.Syntax+import {-# SOURCE #-} Dhall.Syntax.Instances.Pretty ()+import GHC.Generics (Generic)+import Language.Haskell.TH.Syntax (Lift)+import Lens.Micro (cosmosOf, foldMapOf)+import Numeric.Natural (Natural)+import Prettyprinter (Doc, Pretty, space)++import qualified Control.Exception as Exception+import qualified Data.ByteString.Base16 as Base16+import qualified Data.Char+import qualified Data.HashSet+import qualified Data.List as List+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Maybe+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Encoding+import qualified Data.Time as Time+import qualified Dhall.Map as Map+import qualified Dhall.Syntax.Operations as Operations+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.String as Pretty+import qualified Prettyprinter.Render.Terminal as Terminal+import qualified Prettyprinter.Render.Text as Pretty+import qualified Text.Printf as Printf++{-| Annotation type used to tag elements in a pretty-printed document for+ syntax highlighting purposes+-}+data Ann+ = Keyword -- ^ Used for syntactic keywords+ | Syntax -- ^ Syntax punctuation such as commas, parenthesis, and braces+ | Label -- ^ Record labels+ | Literal -- ^ Literals such as integers and strings+ | Builtin -- ^ Builtin types and values+ | Operator -- ^ Operators+ deriving Show++{-| Convert annotations to their corresponding color for syntax highlighting+ purposes+-}+annToAnsiStyle :: Ann -> Terminal.AnsiStyle+annToAnsiStyle Keyword = Terminal.bold <> Terminal.colorDull Terminal.Green+annToAnsiStyle Syntax = Terminal.bold <> Terminal.colorDull Terminal.Green+annToAnsiStyle Label = mempty+annToAnsiStyle Literal = Terminal.colorDull Terminal.Magenta+annToAnsiStyle Builtin = Terminal.underlined+annToAnsiStyle Operator = Terminal.bold <> Terminal.colorDull Terminal.Green++-- | This type determines whether to render code as `ASCII` or `Unicode`+data CharacterSet = ASCII | Unicode+ deriving (Eq, Ord, Show, Data, Generic, Lift, NFData)++-- | Since ASCII is a subset of Unicode, if either argument is Unicode, the+-- result is Unicode+instance Semigroup CharacterSet where+ Unicode <> _ = Unicode+ _ <> other = other++instance Monoid CharacterSet where+ mempty = ASCII++instance FromJSON CharacterSet where+ parseJSON (String "unicode") = pure Unicode+ parseJSON (String "ascii") = pure ASCII+ parseJSON v@(String _) = unexpected v+ parseJSON v = typeMismatch "String" v++-- | The character set used by default in functions throughout the Dhall code+-- base.+defaultCharacterSet :: CharacterSet+defaultCharacterSet = Unicode++-- | Detect which character set is used for the syntax of an expression+-- If any parts of the expression uses the Unicode syntax, the whole expression+-- is deemed to be using the Unicode syntax.+detectCharacterSet :: Expr Src a -> CharacterSet+detectCharacterSet = foldMapOf (cosmosOf subExpressions) exprToCharacterSet+ where+ exprToCharacterSet = \case+ Embed _ -> mempty -- Don't go down the embed route, otherwise: <<loop>>+ Lam (Just Unicode) _ _ -> Unicode+ Pi (Just Unicode) _ _ _ -> Unicode+ Combine (Just Unicode) _ _ _ -> Unicode+ CombineTypes (Just Unicode) _ _ -> Unicode+ Prefer (Just Unicode) _ _ _ -> Unicode+ Equivalent (Just Unicode) _ _ -> Unicode+ _ -> mempty++-- | Pretty print an expression+prettyExpr :: Pretty a => Expr s a -> Doc Ann+prettyExpr = prettySrcExpr . denote++prettySrcExpr :: Pretty a => Expr Src a -> Doc Ann+prettySrcExpr = prettyCharacterSet defaultCharacterSet++{-| Internal utility for pretty-printing, used when generating element lists+ to supply to `enclose` or `enclose'`. This utility indicates that the+ compact represent is the same as the multi-line representation for each+ element+-}+duplicate :: a -> (a, a)+duplicate x = (x, x)++isWhitespace :: Char -> Bool+isWhitespace c =+ case c of+ ' ' -> True+ '\n' -> True+ '\t' -> True+ '\r' -> True+ _ -> False++{-| Used to render inline `Src` spans preserved by the syntax tree++ >>> let unusedSourcePos = Text.Megaparsec.SourcePos "" (Text.Megaparsec.mkPos 1) (Text.Megaparsec.mkPos 1)+ >>> let nonEmptySrc = Src unusedSourcePos unusedSourcePos "-- Documentation for x\n"+ >>> "let" <> " " <> renderSrc id (Just nonEmptySrc) <> "x = 1 in x"+ let -- Documentation for x+ x = 1 in x+ >>> let emptySrc = Src unusedSourcePos unusedSourcePos " "+ >>> "let" <> " " <> renderSrc id (Just emptySrc) <> "x = 1 in x"+ let x = 1 in x+ >>> "let" <> " " <> renderSrc id Nothing <> "x = 1 in x"+ let x = 1 in x+-}+renderSrc+ :: (Text -> Text)+ -- ^ Used to preprocess the comment string (e.g. to strip whitespace)+ -> Maybe Src+ -- ^ Source span to render (if present)+ -> Doc Ann+renderSrc strip (Just (Src {..}))+ | not (Text.all isWhitespace srcText) =+ renderComment (strip srcText)+renderSrc _ _ =+ mempty++{-| Render a comment.++ Any preprocessing, such as whitespace stripping, needs to be handled by the+ caller, see e.g. 'renderSrc'.++ See the documentation for 'renderSrc' for examples.+-}+renderComment :: Text -> Doc Ann+renderComment text =+ Pretty.align (Pretty.concatWith f newLines <> suffix)+ where+ horizontalSpace c = c == ' ' || c == '\t'++ suffix =+ if Text.null text || Text.last text == '\n'+ then mempty+ else " "++ oldLines = Text.splitOn "\n" text++ spacePrefix = Text.takeWhile horizontalSpace++ commonPrefix a b = case Text.commonPrefixes a b of+ Nothing -> ""+ Just (c, _, _) -> c++ sharedSpacePrefix [] = ""+ sharedSpacePrefix (l : ls) = foldl' commonPrefix (spacePrefix l) ls++ blank = Text.all horizontalSpace++ newLines =+ case oldLines of+ [] ->+ []+ l0 : ls ->+ let sharedPrefix =+ sharedSpacePrefix (filter (not . blank) ls)++ perLine l =+ case Text.stripPrefix sharedPrefix l of+ Nothing -> Pretty.pretty l+ Just l' -> Pretty.pretty l'++ in Pretty.pretty l0 : map perLine ls++ f x y = x <> Pretty.hardline <> y++{-| This is a variant of 'renderSrc' with the following differences:++ * The 'srcText' is stripped of all whitespace at the start and the end.+ * When the stripped 'srcText' is empty, the result is 'Nothing'.+-}+renderSrcMaybe :: Maybe Src -> Maybe (Doc Ann)+renderSrcMaybe (Just Src{..}) =+ case Text.dropAround isWhitespace srcText of+ "" -> Nothing+ t -> Just (renderComment t)+renderSrcMaybe _ = Nothing++{-| @+ 'containsComment' mSrc ≡ 'Data.Maybe.isJust' ('renderSrcMaybe' mSrc)+ @+-}+containsComment :: Maybe Src -> Bool+containsComment Nothing = False+containsComment (Just Src{..}) = not (Text.all isWhitespace srcText)++-- Annotation helpers+keyword, syntax, label, literal, builtin, operator :: Doc Ann -> Doc Ann+keyword = Pretty.annotate Keyword+syntax = Pretty.annotate Syntax+label = Pretty.annotate Label+literal = Pretty.annotate Literal+builtin = Pretty.annotate Builtin+operator = Pretty.annotate Operator++comma, lbracket, rbracket, langle, rangle, lbrace, rbrace, lparen, rparen, pipe, dollar, colon, equals, dot :: Doc Ann+comma = syntax Pretty.comma+lbracket = syntax Pretty.lbracket+rbracket = syntax Pretty.rbracket+langle = syntax Pretty.langle+rangle = syntax Pretty.rangle+lbrace = syntax Pretty.lbrace+rbrace = syntax Pretty.rbrace+lparen = syntax Pretty.lparen+rparen = syntax Pretty.rparen+pipe = syntax Pretty.pipe+dollar = syntax "$"+colon = syntax ":"+equals = syntax "="+dot = syntax "."++lambda :: CharacterSet -> Doc Ann+lambda Unicode = syntax "λ"+lambda ASCII = syntax "\\"++forall_ :: CharacterSet -> Doc Ann+forall_ Unicode = syntax "∀"+forall_ ASCII = syntax "forall "++rarrow :: CharacterSet -> Doc Ann+rarrow Unicode = syntax "→"+rarrow ASCII = syntax "->"++doubleColon :: Doc Ann+doubleColon = syntax "::"++-- | Pretty-print a list+list :: [Doc Ann] -> Doc Ann+list [] = lbracket <> rbracket+list docs =+ enclose+ (lbracket <> space)+ (lbracket <> space)+ (comma <> space)+ (comma <> space)+ (space <> rbracket)+ rbracket+ (fmap duplicate docs)++-- | Pretty-print union types and literals+angles :: [(Doc Ann, Doc Ann)] -> Doc Ann+angles [] = langle <> rangle+angles docs =+ enclose+ (langle <> space)+ (langle <> space)+ (space <> pipe <> space)+ (pipe <> space)+ (space <> rangle)+ rangle+ docs++-- | Pretty-print record types and literals+braces :: [(Doc Ann, Doc Ann)] -> Doc Ann+braces [] = lbrace <> rbrace+braces docs =+ enclose+ (lbrace <> space)+ (lbrace <> space)+ (comma <> space)+ (comma <> space)+ (space <> rbrace)+ rbrace+ docs++hangingBraces :: Int -> [(Doc Ann, Doc Ann)] -> Doc Ann+hangingBraces _ [] =+ lbrace <> rbrace+hangingBraces n docs =+ Pretty.group+ (Pretty.flatAlt+ ( lbrace+ <> Pretty.hardline+ <> Pretty.indent n+ ( mconcat (map (combineLong separator) docsLong)+ <> rbrace+ )+ )+ (mconcat (zipWith (<>) (beginShort : repeat separator) docsShort) <> space <> rbrace)+ )+ where+ separator = comma <> space++ docsShort = fmap fst docs++ docsLong = fmap snd docs++ beginShort = lbrace <> space++ combineLong x y = x <> y <> Pretty.hardline++unsnoc :: [a] -> Maybe ([a], a)+unsnoc [] = Nothing+unsnoc (x0 : xs0) = Just (go id x0 xs0)+ where+ go diffXs x [] = (diffXs [], x)+ go diffXs x (y : ys) = go (diffXs . (x:)) y ys++-- | Pretty-print anonymous functions and function types+arrows :: CharacterSet -> [ Doc Ann ] -> Doc Ann+arrows characterSet docs = Pretty.group (Pretty.flatAlt long short)+ where+ long = Pretty.align (mconcat (List.intersperse Pretty.hardline docs'))+ where+ docs' = case unsnoc docs of+ Nothing -> docs++ Just (init_, last_) -> init' ++ [ last' ]+ where+ appendArrow doc = doc <> space <> rarrow characterSet++ init' = map appendArrow init_++ last' = space <> space <> last_++ short = mconcat (List.intersperse separator docs)+ where+ separator = space <> rarrow characterSet <> space++combine :: CharacterSet -> Text+combine ASCII = "/\\"+combine Unicode = "∧"++combineTypes :: CharacterSet -> Text+combineTypes ASCII = "//\\\\"+combineTypes Unicode = "⩓"++prefer :: CharacterSet -> Text+prefer ASCII = "//"+prefer Unicode = "⫽"++equivalent :: CharacterSet -> Text+equivalent ASCII = "==="+equivalent Unicode = "≡"++{-| Format an expression that holds a variable number of elements, such as a+ list, record, or union+-}+enclose+ :: Doc ann+ -- ^ Beginning document for compact representation+ -> Doc ann+ -- ^ Beginning document for multi-line representation+ -> Doc ann+ -- ^ Separator for compact representation+ -> Doc ann+ -- ^ Separator for multi-line representation+ -> Doc ann+ -- ^ Ending document for compact representation+ -> Doc ann+ -- ^ Ending document for multi-line representation+ -> [(Doc ann, Doc ann)]+ -- ^ Elements to format, each of which is a pair: @(compact, multi-line)@+ -> Doc ann+enclose beginShort _ _ _ endShort _ [] =+ beginShort <> endShort+enclose beginShort beginLong sepShort sepLong endShort endLong docs =+ Pretty.group+ (Pretty.flatAlt+ (Pretty.align+ (mconcat (zipWith combineLong (beginLong : repeat sepLong) docsLong) <> endLong)+ )+ (mconcat (zipWith combineShort (beginShort : repeat sepShort) docsShort) <> endShort)+ )+ where+ docsShort = fmap fst docs++ docsLong = fmap snd docs++ combineLong x y = x <> y <> Pretty.hardline++ combineShort x y = x <> y++{-| Format an expression that holds a variable number of elements without a+ trailing document such as nested @let@, nested lambdas, or nested @forall@s+-}+enclose'+ :: Doc ann+ -- ^ Beginning document for compact representation+ -> Doc ann+ -- ^ Beginning document for multi-line representation+ -> Doc ann+ -- ^ Separator for compact representation+ -> Doc ann+ -- ^ Separator for multi-line representation+ -> [(Doc ann, Doc ann)]+ -- ^ Elements to format, each of which is a pair: @(compact, multi-line)@+ -> Doc ann+enclose' beginShort beginLong sepShort sepLong docs =+ Pretty.group (Pretty.flatAlt long short)+ where+ longLines = zipWith (<>) (beginLong : repeat sepLong) docsLong++ long =+ Pretty.align (mconcat (List.intersperse Pretty.hardline longLines))++ short = mconcat (zipWith (<>) (beginShort : repeat sepShort) docsShort)++ docsShort = fmap fst docs++ docsLong = fmap snd docs++alpha :: Char -> Bool+alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')++digit :: Char -> Bool+digit c = '\x30' <= c && c <= '\x39'++alphaNum :: Char -> Bool+alphaNum c = alpha c || digit c++headCharacter :: Char -> Bool+headCharacter c = alpha c || c == '_'++tailCharacter :: Char -> Bool+tailCharacter c = alphaNum c || c == '_' || c == '-' || c == '/'++-- | The set of labels which do not need to be escaped+data UnescapedLabel+ = NonReservedLabel+ -- ^ This corresponds to the `nonreserved-label` rule in the grammar+ | AnyLabel+ -- ^ This corresponds to the `any-label` rule in the grammar+ | AnyLabelOrSome+ -- ^ This corresponds to the `any-label-or-some` rule in the grammar++-- | Escape a label if it is not valid when unquoted+escapeLabel :: UnescapedLabel -> Text -> Text+escapeLabel allowedLabel l =+ case Text.uncons l of+ Just (h, t)+ | headCharacter h && Text.all tailCharacter t && allowed && l /= "?"+ -> l+ _ -> "`" <> l <> "`"+ where+ allowed = case allowedLabel of+ NonReservedLabel -> notReservedIdentifier+ AnyLabel -> notReservedKeyword+ AnyLabelOrSome -> notReservedKeyword || l == "Some"++ notReservedIdentifier = not (Data.HashSet.member l reservedIdentifiers)++ notReservedKeyword = not (Data.HashSet.member l reservedKeywords)++prettyLabelShared :: UnescapedLabel -> Text -> Doc Ann+prettyLabelShared b l = label (Pretty.pretty (escapeLabel b l))++prettyLabel :: Text -> Doc Ann+prettyLabel = prettyLabelShared NonReservedLabel++prettyAnyLabel :: Text -> Doc Ann+prettyAnyLabel = prettyLabelShared AnyLabel++prettyAnyLabelOrSome :: Text -> Doc Ann+prettyAnyLabelOrSome = prettyLabelShared AnyLabelOrSome++prettyKeys+ :: Foldable list+ => (key -> Doc Ann)+ -> list (Maybe Src, key, Maybe Src)+ -> Doc Ann+prettyKeys prettyK keys = Pretty.group (Pretty.flatAlt long short)+ where+ short = (mconcat . Pretty.punctuate dot . map prettyKey . toList) keys++ long =+ case map prettyKey (toList keys) of+ [] -> mempty+ [doc] -> doc+ doc:docs ->+ Pretty.align+ . mconcat+ . Pretty.punctuate (Pretty.hardline <> ". ")+ $ Pretty.indent 2 doc : docs++ prettyKey (mSrc0, key, mSrc1) =+ Pretty.align+ . mconcat+ . Pretty.punctuate Pretty.hardline+ . Data.Maybe.catMaybes+ $ [ renderSrcMaybe mSrc0+ , Just (prettyK key)+ , renderSrcMaybe mSrc1+ ]++prettyLabels :: [Text] -> Doc Ann+prettyLabels a+ | null a = lbrace <> rbrace+ | otherwise = braces (map (duplicate . prettyAnyLabelOrSome) a)++prettyNumber :: Integer -> Doc Ann+prettyNumber = literal . Pretty.pretty++prettyInt :: Int -> Doc Ann+prettyInt = literal . Pretty.pretty++prettyNatural :: Natural -> Doc Ann+prettyNatural = literal . Pretty.pretty++prettyDouble :: Double -> Doc Ann+prettyDouble = literal . Pretty.pretty++prettyConst :: Const -> Doc Ann+prettyConst Type = builtin "Type"+prettyConst Kind = builtin "Kind"+prettyConst Sort = builtin "Sort"++prettyVar :: Var -> Doc Ann+prettyVar (V x 0) = label (Pretty.unAnnotate (prettyLabel x))+prettyVar (V x n) = label (Pretty.unAnnotate (prettyLabel x <> "@" <> prettyInt n))++prettyEnvironmentVariable :: Text -> Doc ann+prettyEnvironmentVariable t = Pretty.pretty (escapeEnvironmentVariable t)++preserveSource :: Expr Src a -> Maybe (Doc Ann)+preserveSource (Note Src{..} (DoubleLit {})) = Just (Pretty.pretty srcText)+preserveSource (Note Src{..} (IntegerLit {})) = Just (Pretty.pretty srcText)+preserveSource (Note Src{..} (NaturalLit {})) = Just (Pretty.pretty srcText)+preserveSource _ = Nothing++-- | Escape an environment variable if not a valid Bash environment variable+escapeEnvironmentVariable :: Text -> Text+escapeEnvironmentVariable t+ | validBashEnvVar t = t+ | otherwise = "\"" <> escapeText_ t <> "\""+ where+ validBashEnvVar v = case Text.uncons v of+ Nothing -> False+ Just (c, v') ->+ (alpha c || c == '_')+ && Text.all (\c' -> alphaNum c' || c' == '_') v'++{- There is a close correspondence between the pretty-printers in 'prettyCharacterSet'+ and the sub-parsers in 'Dhall.Parser.Expression.parsers'. Most pretty-printers are+ named after the corresponding parser and the relationship between pretty-printers+ exactly matches the relationship between parsers. This leads to the nice emergent+ property of automatically getting all the parentheses and precedences right.++ This approach has one major disadvantage: you can get an infinite loop if+ you add a new constructor to the syntax tree without adding a matching+ case the corresponding builder.+-}++{-| Pretty-print an 'Expr' using the given 'CharacterSet'.++'prettyCharacterSet' largely ignores 'Note's. 'Note's do however matter for+the layout of let-blocks:++>>> let inner = Let (Binding Nothing "x" Nothing Nothing Nothing (NaturalLit 1)) (Var (V "x" 0)) :: Expr Src ()+>>> prettyCharacterSet ASCII (Let (Binding Nothing "y" Nothing Nothing Nothing (NaturalLit 2)) inner)+let y = 2 let x = 1 in x+>>> prettyCharacterSet ASCII (Let (Binding Nothing "y" Nothing Nothing Nothing (NaturalLit 2)) (Note (Src unusedSourcePos unusedSourcePos "") inner))+let y = 2 in let x = 1 in x++This means the structure of parsed let-blocks is preserved.+-}+prettyCharacterSet :: Pretty a => CharacterSet -> Expr Src a -> Doc Ann+prettyCharacterSet characterSet = prettyCompleteExpression+ where+ PrettyPrinters{..} = prettyPrinters characterSet++-- Mainly used by the `Pretty` instance for `Import`+prettyImportExpression :: Pretty a => Expr Src a -> Doc Ann+prettyImportExpression = prettyImportExpression_+ where+ PrettyPrinters{..} = prettyPrinters Unicode++data PrettyPrinters a = PrettyPrinters+ { prettyCompleteExpression :: Expr Src a -> Doc Ann+ , prettyImportExpression_ :: Expr Src a -> Doc Ann+ }++prettyPrinters :: Pretty a => CharacterSet -> PrettyPrinters a+prettyPrinters characterSet =+ PrettyPrinters{..}+ where+ prettyCompleteExpression expression =+ Pretty.group (prettyExpression expression)++ prettyExpression a0@(Lam _ _ _) =+ arrows characterSet (docs a0)+ where+ docs (Lam _ (FunctionBinding { functionBindingVariable = a, functionBindingAnnotation = b }) c) =+ Pretty.group (Pretty.flatAlt long short) : docs c+ where+ long = (lambda characterSet <> space)+ <> Pretty.align+ ( (lparen <> space)+ <> prettyLabel a+ <> Pretty.hardline+ <> (colon <> space)+ <> prettyExpression b+ <> Pretty.hardline+ <> rparen+ )++ short = (lambda characterSet <> lparen)+ <> prettyLabel a+ <> (space <> colon <> space)+ <> prettyExpression b+ <> rparen+ docs c+ | Just doc <- preserveSource c =+ [ doc ]+ | Note _ d <- c =+ docs d+ | otherwise =+ [ prettyExpression c ]+ prettyExpression a0@(BoolIf _ _ _) =+ Pretty.group (Pretty.flatAlt long short)+ where+ prefixesLong =+ ""+ : cycle+ [ keyword "then" <> " "+ , keyword "else" <> " "+ ]++ prefixesShort =+ ""+ : cycle+ [ space <> keyword "then" <> space+ , space <> keyword "else" <> space+ ]++ longLines = zipWith (<>) prefixesLong (docsLong True a0)++ long =+ Pretty.align (mconcat (List.intersperse Pretty.hardline longLines))++ short = mconcat (zipWith (<>) prefixesShort (docsShort a0))++ docsLong initial (BoolIf a b c) =+ docLong ++ docsLong False c+ where+ padding+ | initial = " "+ | otherwise = mempty++ docLong =+ [ keyword "if" <> padding <> " " <> prettyExpression a+ , prettyExpression b+ ]+ docsLong initial c+ | Just doc <- preserveSource c =+ [ doc ]+ | Note _ d <- c =+ docsLong initial d+ | otherwise =+ [ prettyExpression c ]++ docsShort (BoolIf a b c) =+ docShort ++ docsShort c+ where+ docShort =+ [ keyword "if" <> " " <> prettyExpression a+ , prettyExpression b+ ]+ docsShort c+ | Just doc <- preserveSource c =+ [ doc ]+ | Note _ d <- c =+ docsShort d+ | otherwise =+ [ prettyExpression c ]+ prettyExpression (Let a0 b0) =+ enclose' "" "" space Pretty.hardline+ (fmap (duplicate . docA) (toList as) ++ [ docB ])+ where+ MultiLet as b = multiLet a0 b0++ isSpace c = c == ' ' || c == '\t'+ stripSpaces =+ Text.dropAround isSpace+ . Text.intercalate "\n"+ . map (Text.dropWhileEnd isSpace)+ . Text.splitOn "\n"++ -- Strip a single newline character. Needed to ensure idempotency in+ -- cases where we add hard line breaks.+ stripNewline t =+ case Text.uncons t' of+ Just ('\n', t'') -> stripSpaces t''+ _ -> t'+ where t' = stripSpaces t++ docA (Binding src0 c src1 Nothing src2 e) =+ Pretty.group (Pretty.flatAlt long short)+ where+ long = keyword "let" <> space+ <> Pretty.align+ ( renderSrc stripSpaces src0+ <> prettyLabel c <> space <> renderSrc stripSpaces src1+ <> equals <> Pretty.hardline <> renderSrc stripNewline src2+ <> " " <> prettyExpression e+ )++ short = keyword "let" <> space <> renderSrc stripSpaces src0+ <> prettyLabel c <> space <> renderSrc stripSpaces src1+ <> equals <> space <> renderSrc stripSpaces src2+ <> prettyExpression e+ docA (Binding src0 c src1 (Just (src3, d)) src2 e) =+ keyword "let" <> space+ <> Pretty.align+ ( renderSrc stripSpaces src0+ <> prettyLabel c <> Pretty.hardline <> renderSrc stripNewline src1+ <> colon <> space <> renderSrc stripSpaces src3 <> prettyExpression d <> Pretty.hardline+ <> equals <> space <> renderSrc stripSpaces src2+ <> prettyExpression e+ )++ docB =+ ( keyword "in" <> " " <> prettyExpression b+ , keyword "in" <> " " <> prettyExpression b+ )+ prettyExpression a0@(Pi _ _ _ _) =+ arrows characterSet (docs a0)+ where+ docs (Pi _ "_" b c) = prettyOperatorExpression b : docs c+ docs (Pi _ a b c) = Pretty.group (Pretty.flatAlt long short) : docs c+ where+ long = forall_ characterSet <> space+ <> Pretty.align+ ( lparen <> space+ <> prettyLabel a+ <> Pretty.hardline+ <> colon <> space+ <> prettyExpression b+ <> Pretty.hardline+ <> rparen+ )++ short = forall_ characterSet <> lparen+ <> prettyLabel a+ <> space <> colon <> space+ <> prettyExpression b+ <> rparen+ docs c+ | Just doc <- preserveSource c =+ [ doc ]+ | Note _ d <- c =+ docs d+ | otherwise =+ [ prettyExpression c ]+ prettyExpression (With (Dhall.Syntax.shallowDenote -> a) b c) =+ case a of+ With{} ->+ -- Don't parenthesize an inner with-expression+ prettyExpression a+ _ ->+ prettyImportExpression_ a+ <> Pretty.flatAlt long short+ where+ short = " " <> keyword "with" <> " " <> update++ long = Pretty.hardline+ <> " "+ <> Pretty.align (keyword "with" <> " " <> update)++ (update, _) =+ prettyKeyValue prettyKey prettyOperatorExpression equals+ (makeKeyValue b c)++ prettyKey (WithLabel text) = prettyAnyLabelOrSome text+ prettyKey WithQuestion = syntax "?"+ prettyExpression (Assert a) =+ Pretty.group (Pretty.flatAlt long short)+ where+ short = keyword "assert" <> " " <> colon <> " " <> prettyExpression a++ long =+ Pretty.align+ ( " " <> keyword "assert"+ <> Pretty.hardline <> colon <> " " <> prettyExpression a+ )+ prettyExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyExpression b+ | otherwise =+ prettyAnnotatedExpression a++ prettyAnnotatedExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyAnnotatedExpression (Merge a b (Just c)) =+ Pretty.group (Pretty.flatAlt long short)+ where+ long =+ Pretty.align+ ( keyword "merge"+ <> Pretty.hardline+ <> Pretty.indent 2 (prettyImportExpression_ a)+ <> Pretty.hardline+ <> Pretty.indent 2 (prettyImportExpression_ b)+ <> Pretty.hardline+ <> colon <> space+ <> prettyExpression c+ )++ short = keyword "merge" <> space+ <> prettyImportExpression_ a+ <> " "+ <> prettyImportExpression_ b+ <> space <> colon <> space+ <> prettyExpression c+ prettyAnnotatedExpression (ToMap a (Just b)) =+ Pretty.group (Pretty.flatAlt long short)+ where+ long =+ Pretty.align+ ( keyword "toMap"+ <> Pretty.hardline+ <> Pretty.indent 2 (prettyImportExpression_ a)+ <> Pretty.hardline+ <> colon <> space+ <> prettyExpression b+ )++ short = keyword "toMap" <> space+ <> prettyImportExpression_ a+ <> space <> colon <> space+ <> prettyExpression b+ prettyAnnotatedExpression a0@(Annot _ _) =+ enclose'+ ""+ " "+ (" " <> colon <> " ")+ (colon <> space)+ (fmap duplicate (docs a0))+ where+ docs (Annot a b) = prettyOperatorExpression a : docs b+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyExpression a ]+ prettyAnnotatedExpression (ListLit (Just a) b) =+ list (map prettyExpression (Data.Foldable.toList b))+ <> " : "+ <> prettyExpression a+ prettyAnnotatedExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyAnnotatedExpression b+ | otherwise =+ prettyOperatorExpression a++ prettyOperatorExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyOperatorExpression = prettyEquivalentExpression++ prettyOperator :: Text -> [Doc Ann] -> Doc Ann+ prettyOperator op docs =+ enclose'+ ""+ prefix+ (" " <> operator (Pretty.pretty op) <> " ")+ (operator (Pretty.pretty op) <> spacer)+ (reverse (fmap duplicate docs))+ where+ prefix = if Text.length op == 1 then " " else " "++ spacer = if Text.length op == 1 then " " else " "++ prettyEquivalentExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyEquivalentExpression a0@(Equivalent _ _ _) =+ prettyOperator (equivalent characterSet) (docs a0)+ where+ docs (Equivalent _ a b) = prettyImportAltExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyImportAltExpression a ]+ prettyEquivalentExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyEquivalentExpression b+ | otherwise =+ prettyImportAltExpression a++ prettyImportAltExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyImportAltExpression a0@(ImportAlt _ _) =+ prettyOperator "?" (docs a0)+ where+ docs (ImportAlt a b) = prettyOrExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyOrExpression a ]+ prettyImportAltExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyImportAltExpression b+ | otherwise =+ prettyOrExpression a++ prettyOrExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyOrExpression a0@(BoolOr _ _) =+ prettyOperator "||" (docs a0)+ where+ docs (BoolOr a b) = prettyPlusExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyPlusExpression a ]+ prettyOrExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyOrExpression b+ | otherwise =+ prettyPlusExpression a++ prettyPlusExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyPlusExpression a0@(NaturalPlus _ _) =+ prettyOperator "+" (docs a0)+ where+ docs (NaturalPlus a b) = prettyTextAppendExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyTextAppendExpression a ]+ prettyPlusExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyPlusExpression b+ | otherwise =+ prettyTextAppendExpression a++ prettyTextAppendExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyTextAppendExpression a0@(TextAppend _ _) =+ prettyOperator "++" (docs a0)+ where+ docs (TextAppend a b) = prettyListAppendExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyListAppendExpression a ]+ prettyTextAppendExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyTextAppendExpression b+ | otherwise =+ prettyListAppendExpression a++ prettyListAppendExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyListAppendExpression a0@(ListAppend _ _) =+ prettyOperator "#" (docs a0)+ where+ docs (ListAppend a b) = prettyAndExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyAndExpression a ]+ prettyListAppendExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyListAppendExpression b+ | otherwise =+ prettyAndExpression a++ prettyAndExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyAndExpression a0@(BoolAnd _ _) =+ prettyOperator "&&" (docs a0)+ where+ docs (BoolAnd a b) = prettyCombineExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyCombineExpression a ]+ prettyAndExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyAndExpression b+ | otherwise =+ prettyCombineExpression a++ prettyCombineExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyCombineExpression a0@(Combine _ _ _ _) =+ prettyOperator (combine characterSet) (docs a0)+ where+ docs (Combine _ _ a b) = prettyPreferExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyPreferExpression a ]+ prettyCombineExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyCombineExpression b+ | otherwise =+ prettyPreferExpression a++ prettyPreferExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyPreferExpression a0@(Prefer {}) =+ prettyOperator (prefer characterSet) (docs a0)+ where+ docs (Prefer _ _ a b) = prettyCombineTypesExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyCombineTypesExpression a ]+ prettyPreferExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyPreferExpression b+ | otherwise =+ prettyCombineTypesExpression a++ prettyCombineTypesExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyCombineTypesExpression a0@(CombineTypes _ _ _) =+ prettyOperator (combineTypes characterSet) (docs a0)+ where+ docs (CombineTypes _ a b) = prettyTimesExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyTimesExpression a ]+ prettyCombineTypesExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyCombineTypesExpression b+ | otherwise =+ prettyTimesExpression a++ prettyTimesExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyTimesExpression a0@(NaturalTimes _ _) =+ prettyOperator "*" (docs a0)+ where+ docs (NaturalTimes a b) = prettyEqualExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyEqualExpression a ]+ prettyTimesExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyTimesExpression b+ | otherwise =+ prettyEqualExpression a++ prettyEqualExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyEqualExpression a0@(BoolEQ _ _) =+ prettyOperator "==" (docs a0)+ where+ docs (BoolEQ a b) = prettyNotEqualExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyNotEqualExpression a ]+ prettyEqualExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyEqualExpression b+ | otherwise =+ prettyNotEqualExpression a++ prettyNotEqualExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyNotEqualExpression a0@(BoolNE _ _) =+ prettyOperator "!=" (docs a0)+ where+ docs (BoolNE a b) = prettyApplicationExpression b : docs a+ docs a+ | Just doc <- preserveSource a =+ [ doc ]+ | Note _ b <- a =+ docs b+ | otherwise =+ [ prettyApplicationExpression a ]+ prettyNotEqualExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyNotEqualExpression b+ | otherwise =+ prettyApplicationExpression a++ prettyApplicationExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyApplicationExpression = go []+ where+ go args = \case+ App a b -> go (b : args) a+ Some a -> app (builtin "Some") (a : args)+ Merge a b Nothing -> app (keyword "merge") (a : b : args)+ ToMap a Nothing -> app (keyword "toMap") (a : args)+ ShowConstructor a -> app (keyword "showConstructor") (a : args)+ e | Note _ b <- e ->+ go args b+ | null args ->+ prettyImportExpression_ e -- just a performance optimization+ | Just doc <- preserveSource e ->+ app doc args+ | otherwise ->+ app (prettyImportExpression_ e) args++ app f args =+ enclose'+ "" "" " " ""+ ( duplicate f+ : map (fmap (Pretty.indent 2) . duplicate . prettyImportExpression_) args+ )++ prettyImportExpression_ :: Pretty a => Expr Src a -> Doc Ann+ prettyImportExpression_ (Embed a) =+ Pretty.pretty a+ prettyImportExpression_ a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyImportExpression_ b+ | otherwise =+ prettyCompletionExpression a++ prettyCompletionExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyCompletionExpression (RecordCompletion a b) =+ case shallowDenote b of+ RecordLit kvs ->+ Pretty.align+ ( prettySelectorExpression a+ <> doubleColon+ <> prettyCompletionLit 0 kvs+ )+ _ -> prettySelectorExpression a+ <> doubleColon+ <> prettySelectorExpression b+ prettyCompletionExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyCompletionExpression b+ | otherwise =+ prettySelectorExpression a++ prettySelectorExpression :: Pretty a => Expr Src a -> Doc Ann+ prettySelectorExpression (Field a (Dhall.Syntax.fieldSelectionLabel -> b)) =+ prettySelectorExpression a <> dot <> prettyAnyLabel b+ prettySelectorExpression (Project a (Left b)) =+ prettySelectorExpression a <> dot <> prettyLabels b+ prettySelectorExpression (Project a (Right b)) =+ prettySelectorExpression a+ <> dot+ <> lparen+ <> prettyExpression b+ <> rparen+ prettySelectorExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettySelectorExpression b+ | otherwise =+ prettyPrimitiveExpression a++ prettyPrimitiveExpression :: Pretty a => Expr Src a -> Doc Ann+ prettyPrimitiveExpression (Var a) =+ prettyVar a+ prettyPrimitiveExpression (Const k) =+ prettyConst k+ prettyPrimitiveExpression Bool =+ builtin "Bool"+ prettyPrimitiveExpression Bytes =+ builtin "Bytes"+ prettyPrimitiveExpression Natural =+ builtin "Natural"+ prettyPrimitiveExpression NaturalFold =+ builtin "Natural/fold"+ prettyPrimitiveExpression NaturalBuild =+ builtin "Natural/build"+ prettyPrimitiveExpression NaturalIsZero =+ builtin "Natural/isZero"+ prettyPrimitiveExpression NaturalEven =+ builtin "Natural/even"+ prettyPrimitiveExpression NaturalOdd =+ builtin "Natural/odd"+ prettyPrimitiveExpression NaturalToInteger =+ builtin "Natural/toInteger"+ prettyPrimitiveExpression NaturalShow =+ builtin "Natural/show"+ prettyPrimitiveExpression NaturalSubtract =+ builtin "Natural/subtract"+ prettyPrimitiveExpression Integer =+ builtin "Integer"+ prettyPrimitiveExpression IntegerClamp =+ builtin "Integer/clamp"+ prettyPrimitiveExpression IntegerNegate =+ builtin "Integer/negate"+ prettyPrimitiveExpression IntegerShow =+ builtin "Integer/show"+ prettyPrimitiveExpression IntegerToDouble =+ builtin "Integer/toDouble"+ prettyPrimitiveExpression Double =+ builtin "Double"+ prettyPrimitiveExpression DoubleShow =+ builtin "Double/show"+ prettyPrimitiveExpression Text =+ builtin "Text"+ prettyPrimitiveExpression TextReplace =+ builtin "Text/replace"+ prettyPrimitiveExpression TextShow =+ builtin "Text/show"+ prettyPrimitiveExpression Date =+ builtin "Date"+ prettyPrimitiveExpression (DateLiteral day) =+ literal+ ( Pretty.pretty (Printf.printf "%04d" _HHHH :: String)+ <> "-"+ <> Pretty.pretty (Printf.printf "%02d" _MM :: String)+ <> "-"+ <> Pretty.pretty (Printf.printf "%02d" _DD :: String)+ )+ where+ (_HHHH, _MM, _DD) = Time.toGregorian day+ prettyPrimitiveExpression DateShow =+ builtin "Date/show"+ prettyPrimitiveExpression Time =+ builtin "Time"+ prettyPrimitiveExpression (TimeLiteral (Time.TimeOfDay hh mm seconds) precision) =+ literal+ ( Pretty.pretty (Printf.printf "%02d" hh :: String)+ <> ":"+ <> Pretty.pretty (Printf.printf "%02d" mm :: String)+ <> ":"+ <> Pretty.pretty (Printf.printf "%02d" ss :: String)+ <> suffix+ )+ where+ magnitude :: Integer+ magnitude = 10 ^ precision++ (ss, fraction) = truncate (seconds * fromInteger magnitude) `divMod` magnitude++ suffix+ | precision == 0 = ""+ | otherwise = "." <> Pretty.pretty (Printf.printf "%0*d" precision fraction :: String)+ prettyPrimitiveExpression TimeShow =+ builtin "Time/show"+ prettyPrimitiveExpression TimeZone =+ builtin "TimeZone"+ prettyPrimitiveExpression (TimeZoneLiteral (Time.TimeZone minutes _ _)) =+ literal+ ( sign+ <> Pretty.pretty (Printf.printf "%02d" _HH :: String)+ <> ":"+ <> Pretty.pretty (Printf.printf "%02d" _MM :: String)+ )+ where+ sign = if 0 <= minutes then "+" else "-"++ (_HH, _MM) = abs minutes `divMod` 60+ prettyPrimitiveExpression TimeZoneShow =+ builtin "TimeZone/show"+ prettyPrimitiveExpression List =+ builtin "List"+ prettyPrimitiveExpression ListBuild =+ builtin "List/build"+ prettyPrimitiveExpression ListFold =+ builtin "List/fold"+ prettyPrimitiveExpression ListLength =+ builtin "List/length"+ prettyPrimitiveExpression ListHead =+ builtin "List/head"+ prettyPrimitiveExpression ListLast =+ builtin "List/last"+ prettyPrimitiveExpression ListIndexed =+ builtin "List/indexed"+ prettyPrimitiveExpression ListReverse =+ builtin "List/reverse"+ prettyPrimitiveExpression Optional =+ builtin "Optional"+ prettyPrimitiveExpression None =+ builtin "None"+ prettyPrimitiveExpression (BoolLit True) =+ builtin "True"+ prettyPrimitiveExpression (BoolLit False) =+ builtin "False"+ prettyPrimitiveExpression (IntegerLit a)+ | 0 <= a = literal "+" <> prettyNumber a+ | otherwise = prettyNumber a+ prettyPrimitiveExpression (NaturalLit a) =+ prettyNatural a+ prettyPrimitiveExpression (DoubleLit (DhallDouble a)) =+ prettyDouble a+ prettyPrimitiveExpression (TextLit a) =+ prettyChunks a+ prettyPrimitiveExpression (BytesLit a) =+ prettyBytes a+ prettyPrimitiveExpression (Record a) =+ prettyRecord a+ prettyPrimitiveExpression (RecordLit a) =+ prettyRecordLit a+ prettyPrimitiveExpression (Union a) =+ prettyUnion a+ prettyPrimitiveExpression (ListLit Nothing b) =+ list (map prettyExpression (Data.Foldable.toList b))+ prettyPrimitiveExpression a+ | Just doc <- preserveSource a =+ doc+ | Note _ b <- a =+ prettyPrimitiveExpression b+ | otherwise =+ Pretty.group (Pretty.flatAlt long short)+ where+ long =+ Pretty.align+ (lparen <> space <> prettyExpression a <> Pretty.hardline <> rparen)++ short = lparen <> prettyExpression a <> rparen++ prettyKeyValue+ :: Pretty a+ => (key -> Doc Ann)+ -> (Expr Src a -> Doc Ann)+ -> Doc Ann+ -> KeyValue key Src a+ -> (Doc Ann, Doc Ann)+ prettyKeyValue prettyKey prettyValue separator (KeyValue key mSrc val) =+ duplicate (Pretty.group (Pretty.flatAlt long short))+ where+ completion _T r =+ prettySelectorExpression _T+ <> doubleColon+ <> case shallowDenote r of+ RecordLit kvs ->+ prettyCompletionLit 2 kvs+ _ ->+ prettySelectorExpression r++ short = prettyKeys prettyKey key+ <> " "+ <> separator+ <> " "+ <> case renderSrcMaybe mSrc of+ Nothing -> mempty+ Just doc -> doc <> Pretty.hardline+ <> prettyValue val++ long = Pretty.align+ ( prettyKeys prettyKey key+ <> preSeparator+ )+ <> separator+ <> case renderSrcMaybe mSrc of+ Just doc ->+ preComment+ <> Pretty.align+ ( doc+ <> Pretty.hardline+ <> prettyValue val+ )+ Nothing ->+ case shallowDenote val of+ Some val' ->+ " "+ <> builtin "Some"+ <> case shallowDenote val' of+ RecordCompletion _T r ->+ " "+ <> completion _T r++ RecordLit _ ->+ Pretty.hardline+ <> " "+ <> prettyImportExpression_ val'++ ListLit _ xs+ | not (null xs) ->+ Pretty.hardline+ <> " "+ <> prettyImportExpression_ val'++ _ -> Pretty.hardline+ <> " "+ <> prettyImportExpression_ val'++ ToMap val' Nothing ->+ " "+ <> keyword "toMap"+ <> case shallowDenote val' of+ RecordCompletion _T r ->+ " "+ <> completion _T r+ _ -> Pretty.hardline+ <> " "+ <> prettyImportExpression_ val'++ ShowConstructor val' ->+ " "+ <> keyword "showConstructor"+ <> case shallowDenote val' of+ RecordCompletion _T r ->+ " "+ <> completion _T r+ _ -> Pretty.hardline+ <> " "+ <> prettyImportExpression_ val'++ RecordCompletion _T r ->+ " " <> completion _T r++ RecordLit _ ->+ Pretty.hardline+ <> " "+ <> prettyValue val++ ListLit _ xs+ | not (null xs) ->+ Pretty.hardline+ <> " "+ <> prettyValue val++ _ ->+ Pretty.group+ ( Pretty.flatAlt (Pretty.hardline <> " ") " "+ <> prettyValue val+ )+ where+ (preSeparator, preComment) =+ case key of+ (_, _, mSrc2) :| [] | not (containsComment mSrc2) ->+ (" ", Pretty.hardline <> " ")+ _ ->+ (Pretty.hardline, " ")+++ prettyRecord :: Pretty a => Map Text (RecordField Src a) -> Doc Ann+ prettyRecord =+ ( braces+ . map (prettyKeyValue prettyAnyLabelOrSome prettyExpression colon . adapt)+ . Map.toList+ )+ where+ adapt (key, RecordField mSrc0 val mSrc1 mSrc2) = KeyValue (pure (mSrc0, key, mSrc1)) mSrc2 val++ prettyRecordLit :: Pretty a => Map Text (RecordField Src a) -> Doc Ann+ prettyRecordLit m+ | [ ("date" , field -> d@DateLiteral{})+ , ("time" , field -> t@TimeLiteral{})+ , ("timeZone", field -> z@TimeZoneLiteral{})+ ] <- List.sortOn fst (Map.toList m) =+ literal+ ( prettyPrimitiveExpression d+ <> "T"+ <> prettyPrimitiveExpression t+ <> prettyPrimitiveExpression z+ )+ | [ ("date" , field -> d@DateLiteral{})+ , ("time" , field -> t@TimeLiteral{})+ ] <- List.sortOn fst (Map.toList m) =+ literal+ ( prettyPrimitiveExpression d+ <> "T"+ <> prettyPrimitiveExpression t+ )+ | [ ("time" , field -> t@TimeLiteral{})+ , ("timeZone", field -> z@TimeZoneLiteral{})+ ] <- List.sortOn fst (Map.toList m) =+ literal+ ( prettyPrimitiveExpression t+ <> prettyPrimitiveExpression z+ )+ where+ field = Dhall.Syntax.shallowDenote . recordFieldValue+ prettyRecordLit m = prettyRecordLike braces m++ prettyCompletionLit :: Pretty a => Int -> Map Text (RecordField Src a) -> Doc Ann+ prettyCompletionLit = prettyRecordLike . hangingBraces++ prettyRecordLike+ :: Pretty a+ => ([(Doc Ann, Doc Ann)] -> Doc Ann)+ -> Map Text (RecordField Src a)+ -> Doc Ann+ prettyRecordLike braceStyle a+ | Data.Foldable.null a =+ lbrace <> equals <> rbrace+ | otherwise =+ braceStyle (map prettyRecordEntry (consolidateRecordLiteral a))+ where+ prettyRecordEntry kv@(KeyValue keys mSrc2 val) =+ case keys of+ (mSrc0, key, mSrc1) :| []+ | Var (V key' 0) <- Dhall.Syntax.shallowDenote val+ , key == key'+ , not (containsComment mSrc2) ->+ duplicate (prettyKeys prettyAnyLabelOrSome [(mSrc0, key, mSrc1)])+ _ ->+ prettyKeyValue prettyAnyLabelOrSome prettyExpression equals kv++ prettyAlternative (key, Just val) =+ prettyKeyValue prettyAnyLabelOrSome prettyExpression colon (makeKeyValue (pure key) val)+ prettyAlternative (key, Nothing) =+ duplicate (prettyAnyLabelOrSome key)++ prettyUnion :: Pretty a => Map Text (Maybe (Expr Src a)) -> Doc Ann+ prettyUnion =+ angles . map prettyAlternative . Map.toList++ prettyBytes :: ByteString -> Doc Ann+ prettyBytes bytes =+ literal (Pretty.pretty ("0x\"" <> prettyBase16 bytes <> "\""))++ prettyChunks :: Pretty a => Chunks Src a -> Doc Ann+ prettyChunks chunks@(Chunks a b)+ | anyText (== '\n') =+ if not (null a) || anyText (/= '\n')+ then long+ else Pretty.group (Pretty.flatAlt long short)+ | otherwise =+ short+ where+ long =+ Pretty.align+ ( literal "''" <> Pretty.hardline+ <> Pretty.align+ (foldMap prettyMultilineChunk a' <> prettyMultilineText b')+ <> literal "''"+ )+ where+ Chunks a' b' = multilineChunks chunks++ short =+ literal "\"" <> foldMap prettyChunk a <> literal (prettyText b <> "\"")++ anyText predicate = any (\(text, _) -> Text.any predicate text) a || Text.any predicate b++ prettyMultilineChunk (c, d) =+ prettyMultilineText c+ <> dollar+ <> lbrace+ <> prettyExpression d+ <> rbrace++ prettyMultilineText text = mconcat docs+ where+ lines_ = Text.splitOn "\n" text++ -- Annotate only non-empty lines so trailing whitespace can be+ -- removed on empty ones.+ prettyLine line =+ (if Text.null line then id else literal)+ (Pretty.pretty line)++ docs = List.intersperse Pretty.hardline (map prettyLine lines_)++ prettyChunk (c, d) =+ prettyText c+ <> syntax "${"+ <> prettyExpression d+ <> syntax rbrace++ prettyText t = literal (Pretty.pretty (escapeText_ t))+++-- | Prepare 'Chunks' for multi-line formatting by escaping problematic+-- character sequences via string interpolations+--+-- >>> multilineChunks (Chunks [] "\n \tx")+-- Chunks [("\n",TextLit (Chunks [] " \t"))] "x"+-- >>> multilineChunks (Chunks [] "\n\NUL\b\f\t")+-- Chunks [("\n",TextLit (Chunks [] "\NUL\b\f"))] "\t"+multilineChunks :: Chunks s a -> Chunks s a+multilineChunks =+ escapeSingleQuotedText+ . escapeTrailingSingleQuote+ . escapeControlCharacters+ . escapeSingleQuoteBeforeInterpolation+ . escapeSharedWhitespacePrefix++-- | Escape any leading whitespace shared by all lines+--+-- This ensures that significant shared leading whitespace is not stripped+--+-- >>> escapeSharedWhitespacePrefix (Chunks [] "\n \tx")+-- Chunks [("\n",TextLit (Chunks [] " \t"))] "x"+-- >>> escapeSharedWhitespacePrefix (Chunks [("\n",Var (V "x" 0))] " ")+-- Chunks [("\n",Var (V "x" 0))] " "+-- >>> escapeSharedWhitespacePrefix (Chunks [("\n ",Var (V "x" 0))] "")+-- Chunks [("\n",TextLit (Chunks [] " ")),("",Var (V "x" 0))] ""+-- >>> escapeSharedWhitespacePrefix (Chunks [("\n ",Var (V "x" 0))] "\n")+-- Chunks [("\n ",Var (V "x" 0))] "\n"+-- >>> escapeSharedWhitespacePrefix (Chunks [] " ")+-- Chunks [("",TextLit (Chunks [] " "))] ""+escapeSharedWhitespacePrefix :: Chunks s a -> Chunks s a+escapeSharedWhitespacePrefix literal_ = unlinesLiteral literals₁+ where+ literals₀ = linesLiteral literal_++ sharedPrefix = longestSharedWhitespacePrefix literals₀++ stripPrefix = Text.drop (Text.length sharedPrefix)++ escapeSharedPrefix (Chunks [] prefix₀)+ | Text.isPrefixOf sharedPrefix prefix₀ =+ Chunks [ ("", TextLit (Chunks [] sharedPrefix)) ] prefix₁+ where+ prefix₁ = stripPrefix prefix₀+ escapeSharedPrefix (Chunks ((prefix₀, y) : xys) z)+ | Text.isPrefixOf sharedPrefix prefix₀ =+ Chunks (("", TextLit (Chunks [] sharedPrefix)) : (prefix₁, y) : xys) z+ where+ prefix₁ = stripPrefix prefix₀+ escapeSharedPrefix line = line++ literals₁+ | not (Text.null sharedPrefix) = fmap escapeSharedPrefix literals₀+ | otherwise = literals₀++-- | Escape control characters by moving them into string interpolations+--+-- >>> escapeControlCharacters (Chunks [] "\n\NUL\b\f\t")+-- Chunks [("\n",TextLit (Chunks [] "\NUL\b\f"))] "\t"+escapeControlCharacters :: Chunks s a -> Chunks s a+escapeControlCharacters = splitWith (splitOnPredicate predicate)+ where+ predicate c = Data.Char.isControl c && c /= ' ' && c /= '\t' && c /= '\n'++-- | Escape @'${@ correctly+--+-- See: https://github.com/dhall-lang/dhall-haskell/issues/2078+escapeSingleQuoteBeforeInterpolation :: Chunks s a -> Chunks s a+escapeSingleQuoteBeforeInterpolation = splitWith f+ where+ f text =+ case Text.splitOn "'${" text of+ -- `splitOn` should never return an empty list, but just in case…+ [] -> mempty+ t : ts -> loop t ts++ loop head_ tail_ =+ case tail_ of+ [] ->+ Chunks [] head_+ newHead : newTail ->+ Chunks [ (head_, TextLit (Chunks [] "'")) ] "${"+ <> loop newHead newTail++{-| You can think of this as sort of like `concatMap` for `Chunks`++ Given a function that splits plain text into interpolated chunks, apply+ that function to each uninterpolated span to yield a new+ possibly-interpolated span, and flatten the results.+-}+splitWith :: (Text -> Chunks s a) -> Chunks s a -> Chunks s a+splitWith splitter (Chunks xys z) = mconcat (xys' ++ [ splitter z ])+ where+ xys' = do+ (x, y) <- xys++ [ splitter x, Chunks [ ("", y) ] "" ]++-- | Split `Data.Text.Text` into interpolated chunks, where all characters+-- matching the predicate are pushed into a string interpolation.+--+-- >>> splitOnPredicate (== 'x') ""+-- Chunks [] ""+-- >>> splitOnPredicate (== 'x') " xx "+-- Chunks [(" ",TextLit (Chunks [] "xx"))] " "+-- >>> splitOnPredicate (== 'x') "xx"+-- Chunks [("",TextLit (Chunks [] "xx"))] ""+--+-- prop> \(Fun _ p) s -> let {t = Text.pack s; Chunks xys z = splitOnPredicate p t} in foldMap (\(x, TextLit (Chunks [] y)) -> x <> y) xys <> z == t+splitOnPredicate :: (Char -> Bool) -> Text -> Chunks s a+splitOnPredicate predicate text+ | Text.null b =+ Chunks [] a+ | otherwise =+ Chunks ((a, TextLit (Chunks [] c)) : e) f+ where+ (a, b) = Text.break predicate text++ (c, d) = Text.span predicate b++ Chunks e f = splitOnPredicate predicate d++-- | Escape a trailing single quote by moving it into a string interpolation+--+-- Otherwise the multiline-string would end with @'''@, which would be parsed+-- as an escaped @''@.+--+-- >>> escapeTrailingSingleQuote (Chunks [] "\n'")+-- Chunks [("\n",TextLit (Chunks [] "'"))] ""+escapeTrailingSingleQuote :: Chunks s a -> Chunks s a+escapeTrailingSingleQuote chunks@(Chunks as b) =+ case Text.unsnoc b of+ Just (b', '\'') -> Chunks (as ++ [(b', TextLit (Chunks [] "'"))]) ""+ _ -> chunks++-- | Pretty-print a value+pretty_ :: Pretty a => a -> Text+pretty_ = prettyToStrictText++data KeyValue k s a = KeyValue+ { _keyValueKeys :: NonEmpty (Maybe s, k , Maybe s)+ , _keyValueSrc :: Maybe s+ , _keyValueValue :: Expr s a+ }++makeKeyValue :: NonEmpty key -> Expr s a -> KeyValue key s a+makeKeyValue keys expr = KeyValue (adapt <$> keys) Nothing expr+ where+ adapt key = (Nothing, key, Nothing)++{- This utility function converts+ `{ x = { y = { z = 1 } } }` to `{ x.y.z = 1 }`+-}+consolidateRecordLiteral+ :: Map Text (RecordField Src a) -> [KeyValue Text Src a]+consolidateRecordLiteral = concatMap adapt . Map.toList+ where+ adapt :: (Text, RecordField Src a) -> [KeyValue Text Src a]+ adapt (key, RecordField mSrc0 val mSrc1 mSrc2)+ | not (containsComment mSrc2)+ , RecordLit m <- e+ , [ KeyValue keys mSrc2' val' ] <- concatMap adapt (Map.toList m) =+ [ KeyValue (NonEmpty.cons (mSrc0, key, mSrc1) keys) mSrc2' val' ]++ | Combine _ (Just _) l r <- e =+ adapt (key, makeRecordField l) <> adapt (key, makeRecordField r)+ | otherwise =+ [ KeyValue (pure (mSrc0, key, mSrc1)) mSrc2 val ]+ where+ e = shallowDenote val++-- | Escape a `Data.Text.Text` literal using Dhall's escaping rules for+-- single-quoted @Text@+escapeSingleQuotedText :: Chunks s a -> Chunks s a+escapeSingleQuotedText = splitWith f+ where+ f inputText = Chunks [] outputText+ where+ outputText =+ Text.replace "${" "''${" (Text.replace "''" "'''" inputText)++{-| Escape a `Data.Text.Text` literal using Dhall's escaping rules++ Note that the result does not include surrounding quotes+-}+escapeText_ :: Text -> Text+escapeText_ text = Text.concatMap adapt text+ where+ adapt c+ | '\x20' <= c && c <= '\x21' = Text.singleton c+ -- '\x22' == '"'+ | '\x23' == c = Text.singleton c+ -- '\x24' == '$'+ | '\x25' <= c && c <= '\x5B' = Text.singleton c+ -- '\x5C' == '\\'+ | '\x5D' <= c && c <= '\x10FFFF' = Text.singleton c+ | c == '"' = "\\\""+ | c == '$' = "\\$"+ | c == '\\' = "\\\\"+ | c == '\b' = "\\b"+ | c == '\f' = "\\f"+ | c == '\n' = "\\n"+ | c == '\r' = "\\r"+ | c == '\t' = "\\t"+ | otherwise = "\\u" <> showDigits (Data.Char.ord c)++ showDigits r0 = Text.pack (map showDigit [q1, q2, q3, r3])+ where+ (q1, r1) = r0 `quotRem` 4096+ (q2, r2) = r1 `quotRem` 256+ (q3, r3) = r2 `quotRem` 16++ showDigit n+ | n < 10 = Data.Char.chr (Data.Char.ord '0' + n)+ | otherwise = Data.Char.chr (Data.Char.ord 'A' + n - 10)++prettyToString :: Pretty a => a -> String+prettyToString =+ Pretty.renderString . layout . Pretty.pretty++docToStrictText :: Doc ann -> Text.Text+docToStrictText = Pretty.renderStrict . layout++prettyToStrictText :: Pretty a => a -> Text.Text+prettyToStrictText = docToStrictText . Pretty.pretty++-- | Layout using 'layoutOpts'+--+-- Tries hard to fit the document into 80 columns.+--+-- This also removes trailing space characters (@' '@) /unless/+-- they are enclosed in an annotation.+layout :: Pretty.Doc ann -> Pretty.SimpleDocStream ann+layout = Pretty.removeTrailingWhitespace . Pretty.layoutSmart layoutOpts++-- | Default layout options+layoutOpts :: Pretty.LayoutOptions+layoutOpts =+ Pretty.defaultLayoutOptions+ { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }++{-| Convert an expression representing a temporal value to `Data.Text.Text`, if+ possible++ This is used by downstream integrations (e.g. `dhall-json` for treating+ temporal values as strings+-}+temporalToText :: Pretty a => Expr s a -> Maybe Text+temporalToText e = case e of+ RecordLit m+ | [ ("date" , field -> DateLiteral{})+ , ("time" , field -> TimeLiteral{})+ , ("timeZone", field -> TimeZoneLiteral{})+ ] <- List.sortOn fst (Map.toList m) -> rendered+ | [ ("date" , field -> DateLiteral{})+ , ("time" , field -> TimeLiteral{})+ ] <- List.sortOn fst (Map.toList m) -> rendered+ | [ ("time" , field -> TimeLiteral{})+ , ("timeZone", field -> TimeZoneLiteral{})+ ] <- List.sortOn fst (Map.toList m) -> rendered+ DateLiteral{} -> rendered+ TimeLiteral{} -> rendered+ TimeZoneLiteral{} -> rendered+ _ -> Nothing+ where+ field = Dhall.Syntax.shallowDenote . recordFieldValue++ rendered = Just (prettyToStrictText e)++prettyBase16 :: ByteString -> Text+prettyBase16 bytes =+ case Encoding.decodeUtf8' (Base16.encode bytes) of+ Left exception ->+ Operations.internalError+ ("prettyBase16: base16-encoded bytes could not be decoded as UTF-8 text: " <> Text.pack (Exception.displayException exception))+ Right text ->+ Text.toUpper text++{- $setup+>>> import Test.QuickCheck (Fun(..))+-}
@@ -1,18 +1,35 @@ module Dhall.Pretty.Internal where -import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Pretty, Doc)+import Control.DeepSeq (NFData)+import Data.Data (Data)+import Data.Text (Text)+import Dhall.Src (Src)+import Language.Haskell.TH.Syntax (Lift)+import Prettyprinter (Doc, Pretty) -import {-# SOURCE #-} Dhall.Core+import Dhall.Syntax.Const+import {-# SOURCE #-} Dhall.Syntax.Expr+import Dhall.Syntax.Var data Ann +data CharacterSet = ASCII | Unicode++instance Eq CharacterSet+instance Ord CharacterSet+instance Show CharacterSet+instance Data CharacterSet+instance Lift CharacterSet+instance NFData CharacterSet+instance Semigroup CharacterSet+instance Monoid CharacterSet+ prettyVar :: Var -> Doc Ann prettyConst :: Const -> Doc Ann prettyExpr :: Pretty a => Expr s a -> Doc Ann -pretty :: Pretty a => a -> Text+prettyEnvironmentVariable :: Text -> Doc ann -escapeText :: Text -> Text+prettyImportExpression :: Pretty a => Expr Src a -> Doc Ann
@@ -1,88 +1,122 @@ -- | This module contains the implementation of the @dhall repl@ subcommand -{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}-{-# language RecordWildCards #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-} module Dhall.Repl ( -- * Repl repl ) where -import Control.Exception ( SomeException(SomeException), displayException, throwIO )-import Control.Monad ( forM_ )-import Control.Monad.Fail ( MonadFail )-import Control.Monad.IO.Class ( MonadIO, liftIO )-import Control.Monad.State.Class ( MonadState, get, modify )-import Control.Monad.State.Strict ( evalStateT )--- For the MonadFail instance for StateT.-import Control.Monad.Trans.Instances ()-import Data.List ( isPrefixOf, nub )-import Data.List.NonEmpty (NonEmpty(..))-import Data.Maybe ( mapMaybe )-import Data.Semigroup ((<>))-import Data.Text ( Text )-import Dhall.Binary (StandardVersion(..))-import Dhall.Context (Context)-import Dhall.Import (hashExpressionToCode, standardVersion)-import Dhall.Pretty (CharacterSet(..))-import Lens.Family (set)-import System.Console.Haskeline (Interrupt(..))-import System.Console.Haskeline.Completion ( Completion, simpleCompletion )-import System.Directory ( getDirectoryContents )-import System.Environment ( getEnvironment )+import Control.Exception+ ( SomeException (SomeException)+ , displayException+ , throwIO+ )+import Control.Monad (forM_)+#if !(MIN_VERSION_base(4,13,0))+import Control.Monad.Fail (MonadFail)+#endif+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.State.Class (MonadState, get, modify)+import Control.Monad.State.Strict (evalStateT)+import Data.Char (isSpace)+import Data.List+ ( dropWhileEnd+ , groupBy+ , isPrefixOf+ , nub+ )+import Data.Maybe (mapMaybe)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Context (Context)+import Dhall.Import (hashExpressionToCode)+import Dhall.Parser (Parser (..))+import Dhall.Pretty (CharacterSet (..))+import Dhall.Src (Src)+import System.Console.Haskeline (Interrupt (..))+import System.Console.Haskeline.Completion (Completion, simpleCompletion)+import System.Directory (getDirectoryContents)+import System.Environment (getEnvironment) -import qualified Control.Monad.Fail as Fail-import qualified Control.Monad.Trans.State.Strict as State+import qualified Control.Monad.Fail as Fail+import qualified Control.Monad.Trans.State.Strict as State import qualified Data.HashSet-import qualified Data.Text as Text-import qualified Data.Text.IO as Text.IO-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty ( renderIO )+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO import qualified Dhall-import qualified Dhall.Binary import qualified Dhall.Context import qualified Dhall.Core-import qualified Dhall.Core as Dhall ( Var(V), Expr, normalize )+import qualified Dhall.Core as Dhall+ ( Expr+ , Var (V)+ , normalize+ )+import qualified Dhall.Core as Expr (Expr (..))+import qualified Dhall.Import as Dhall+import qualified Dhall.Map as Map+import qualified Dhall.Parser as Dhall+import qualified Dhall.Parser.Expression as Parser.Expression import qualified Dhall.Pretty-import qualified Dhall.Core as Expr ( Expr(..) )-import qualified Dhall.Import as Dhall-import qualified Dhall.Map as Map-import qualified Dhall.Parser as Dhall-import qualified Dhall.TypeCheck as Dhall+import qualified Dhall.Pretty.Internal+import qualified Dhall.Syntax as Syntax+import qualified Dhall.TypeCheck as Dhall+import qualified Dhall.Version as Meta+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty (renderIO) import qualified System.Console.ANSI import qualified System.Console.Haskeline.Completion as Haskeline-import qualified System.Console.Haskeline.MonadException as Haskeline-import qualified System.Console.Repline as Repline+import qualified System.Console.Repline as Repline import qualified System.IO+import qualified Text.Megaparsec as Megaparsec +#if MIN_VERSION_haskeline(0,8,0)+import qualified Control.Monad.Catch+#else+import qualified System.Console.Haskeline.MonadException+#endif+ type Repl = Repline.HaskelineT (State.StateT Env IO) -- | Implementation of the @dhall repl@ subcommand-repl :: CharacterSet -> Bool -> StandardVersion -> IO ()-repl characterSet explain _standardVersion =+repl :: CharacterSet -> Bool -> IO ()+repl characterSet explain = if explain then Dhall.detailed io else io where io = evalStateT ( Repline.evalRepl- ( pure "⊢ " )+ banner ( dontCrash . eval ) options ( Just optionsPrefix )+ ( Just "paste" ) completer greeter+ finaliser )- (emptyEnv { characterSet, explain, _standardVersion })+ (emptyEnv { characterSet, explain }) + banner = pure . \case+ Repline.SingleLine -> turnstile <> " "+ Repline.MultiLine -> "| " + turnstile =+ case characterSet of+ Unicode -> "⊢"+ ASCII -> "|-"+ data Env = Env { envBindings :: Dhall.Context.Context Binding , envIt :: Maybe Binding , explain :: Bool , characterSet :: CharacterSet- , _standardVersion :: StandardVersion , outputHandle :: Maybe System.IO.Handle } @@ -93,15 +127,14 @@ { envBindings = Dhall.Context.empty , envIt = Nothing , explain = False- , _standardVersion = Dhall.Binary.defaultStandardVersion , characterSet = Unicode , outputHandle = Just System.IO.stdout } data Binding = Binding- { bindingExpr :: Dhall.Expr Dhall.Src Dhall.X- , bindingType :: Dhall.Expr Dhall.Src Dhall.X+ { bindingExpr :: Dhall.Expr Dhall.Src Void+ , bindingType :: Dhall.Expr Dhall.Src Void } @@ -116,22 +149,17 @@ parseAndLoad- :: ( MonadIO m, MonadState Env m )- => String -> m ( Dhall.Expr Dhall.Src Dhall.X )+ :: MonadIO m => String -> m ( Dhall.Expr Dhall.Src Void) parseAndLoad src = do- env <-- get- parsed <-- case Dhall.exprFromText "(stdin)" ( Text.pack src ) of+ case Dhall.exprFromText "(input)" (Text.pack src <> "\n") of Left e -> liftIO ( throwIO e ) Right a -> return a - let status =- set standardVersion (_standardVersion env) (Dhall.emptyStatus ".")+ let status = Dhall.emptyStatus "." liftIO ( State.evalStateT (Dhall.loadWith parsed) status ) @@ -153,43 +181,34 @@ -typeOf :: ( MonadFail m, MonadIO m, MonadState Env m ) => [String] -> m ()-typeOf [] = Fail.fail ":type requires an argument to check the type of"--typeOf srcs = do+typeOf :: ( MonadFail m, MonadIO m, MonadState Env m ) => String -> m ()+typeOf src = do loaded <-- parseAndLoad ( unwords srcs )+ parseAndLoad src exprType <- typeCheck loaded - exprType' <-- normalize exprType-- output exprType'+ output exprType applyContext :: Context Binding- -> Dhall.Expr Dhall.Src Dhall.X- -> Dhall.Expr Dhall.Src Dhall.X+ -> Dhall.Expr Dhall.Src Void+ -> Dhall.Expr Dhall.Src Void applyContext context expression =- case bindings of- [] -> expression- b : bs -> Dhall.Core.Let (b :| bs) expression+ Dhall.Core.wrapInLets bindings expression where definitions = reverse $ Dhall.Context.toList context - convertBinding (variable, Binding {..}) = Dhall.Core.Binding {..}- where- annotation = Just bindingType- value = bindingExpr+ convertBinding (variable, Binding expr _) =+ Dhall.Core.Binding Nothing variable Nothing Nothing Nothing expr bindings = fmap convertBinding definitions normalize :: MonadState Env m- => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr t Dhall.X )+ => Dhall.Expr Dhall.Src Void -> m ( Dhall.Expr t Void ) normalize e = do env <- get @@ -198,7 +217,7 @@ typeCheck :: ( MonadIO m, MonadState Env m )- => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr Dhall.Src Dhall.X )+ => Dhall.Expr Dhall.Src Void -> m ( Dhall.Expr Dhall.Src Void ) typeCheck expression = do env <- get @@ -208,68 +227,75 @@ Left e -> liftIO ( wrap (throwIO e) ) Right a -> return a --- Separate the equal sign to be its own word in order to simplify parsing--- This is intended to be used with the options that require assignment-separateEqual :: [String] -> [String]-separateEqual [] =- []-separateEqual (str₀ : ('=' : str₁) : strs) =- str₀ : "=" : str₁ : strs-separateEqual (str : strs)- | (str₀, '=' : str₁) <- break (== '=') str =- str₀ : "=" : str₁ : strs- | otherwise =- str : strs+-- Split on the first '=' if there is any+parseAssignment :: String -> Either String (String, String)+parseAssignment str+ | (var, '=' : expr) <- break (== '=') str+ = Right (trim var, expr)+ | otherwise+ = Left (trim str) -addBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => [String] -> m ()-addBinding (k : "=" : srcs) = do- let- varName =- Text.pack k+addBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => String -> m ()+addBinding string = do+ let parseBinding =+ Parser.Expression.letBinding+ (Parser.Expression.parsers+ (Megaparsec.try Parser.Expression.import_)+ ) - loaded <-- parseAndLoad ( unwords srcs )+ let input = "let " <> Text.pack string - t <-- typeCheck loaded+ Syntax.Binding{ variable, annotation, value } <- case Megaparsec.parse (unParser parseBinding) "(input)" input of+ Left _ -> Fail.fail ":let should be of the form `:let x [: T] = y`"+ Right binding -> return binding - expr <-- normalize loaded+ (resolved, bindingType) <- case annotation of+ Just (_, unresolvedType) -> do+ let annotated = Syntax.Annot value unresolvedType + resolved <- liftIO (Dhall.load annotated)++ _ <- typeCheck resolved++ bindingType <- liftIO (Dhall.load unresolvedType)++ return (resolved, bindingType)+ _ -> do+ resolved <- liftIO (Dhall.load value)++ bindingType <- typeCheck resolved++ return (resolved, bindingType)++ bindingExpr <- normalize resolved+ modify ( \e ->- e- { envBindings =+ e { envBindings = Dhall.Context.insert- varName- Binding { bindingType = t, bindingExpr = expr }+ variable+ Binding{ bindingType, bindingExpr } ( envBindings e ) } ) - output ( Expr.Annot ( Expr.Var ( Dhall.V varName 0 ) ) t )--addBinding _ = Fail.fail ":let should be of the form `:let x = y`"+ output (Expr.Annot (Expr.Var (Dhall.V variable 0)) bindingType) -clearBindings :: (MonadFail m, MonadState Env m) => [String] -> m ()-clearBindings [] = modify adapt+clearBindings :: (MonadFail m, MonadState Env m) => String -> m ()+clearBindings _ = modify adapt where adapt (Env {..}) = Env { envBindings = Dhall.Context.empty, ..} -clearBindings _ = Fail.fail ":clear takes no arguments"--hashBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => [String] -> m ()-hashBinding [] = Fail.fail ":hash should be of the form `:hash expr"-hashBinding tokens = do- loadedExpression <- parseAndLoad (unwords tokens)+hashBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => String -> m ()+hashBinding src = do+ loadedExpression <- parseAndLoad src _ <- typeCheck loadedExpression normalizedExpression <- normalize loadedExpression - Env{_standardVersion} <- get-- writeOutputHandle $ hashExpressionToCode _standardVersion normalizedExpression+ writeOutputHandle+ (hashExpressionToCode (Dhall.Core.alphaNormalize normalizedExpression)) saveFilePrefix :: FilePath saveFilePrefix = ".dhall-repl"@@ -306,27 +332,33 @@ pure $ saveFilePrefix <> "-" <> show nextIndex -loadBinding- :: ( MonadFail m, MonadIO m, MonadState Env m, Haskeline.MonadException m )- => [String] -> m ()-loadBinding [] = do+loadBinding :: String -> Repl ()+loadBinding "" = do mFile <- currentSaveFile case mFile of- Just file -> loadBinding [file]+ Just file -> loadBinding file Nothing -> Fail.fail $ ":load couldn't find any `" <> saveFilePrefix <> "-*` files" -loadBinding [file] = do+loadBinding file = do -- Read commands from the save file- replLines <- map words . lines <$> liftIO (readFile file)+ -- Some commands can span multiple lines, only the first line will start with+ -- the optionsPrefix+ loadedLines <- lines <$> liftIO (readFile file) - let runCommand ((c:cmd):opts)+ let -- Group lines that belong to the same command+ commands = flip groupBy loadedLines $ \_prev next ->+ not $ [optionsPrefix] `isPrefixOf` next++ runCommand line@(words -> (c:cmd):_) | c == optionsPrefix- , Just action <- lookup cmd options- = action opts+ = case lookup cmd options of+ Just action -> action (drop (1 + length cmd + 1) line)+ Nothing -> Fail.fail $+ ":load unexpected command `" <> cmd <> "` in file `" <> file <> "`" runCommand _ = Fail.fail $- ":load expects `" <> file <> "` to contain one command per line"+ ":load expects `" <> file <> "` to contain a command" -- Keep current handle in scope Env { outputHandle } <- get@@ -335,24 +367,22 @@ modify (\e -> e { outputHandle = Nothing }) -- Run all the commands- forM_ replLines runCommand+ forM_ commands (runCommand . unlines) -- Restore the previous handle modify (\e -> e { outputHandle = outputHandle }) writeOutputHandle $ "Loaded `" <> Text.pack file <> "`\n" -loadBinding _ = Fail.fail ":load should be of the form `:load` or `:load file`"--saveBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => [String] -> m ()+saveBinding :: ( MonadFail m, MonadIO m, MonadState Env m ) => Either String (String, String) -> m () -- Save all the bindings into a context save file-saveBinding [] = do+saveBinding (Left "") = do file <- nextSaveFile - saveBinding [file]+ saveBinding (Left file) -- Save all the bindings into `file`-saveBinding [file] = do+saveBinding (Left file) = do env <- get let bindings@@ -364,7 +394,11 @@ handler handle = State.evalStateT (forM_ bindings $ \(name, expr) -> do- liftIO (System.IO.hPutStr handle $ ":let " <> Text.unpack name <> " = ")+ let doc = Dhall.Pretty.Internal.prettyLabel name++ let label = Dhall.Pretty.Internal.docToStrictText doc++ liftIO (System.IO.hPutStr handle $ ":let " <> Text.unpack label <> " = ") outputWithoutSpacing expr) (env { outputHandle = Just handle }) @@ -373,8 +407,8 @@ writeOutputHandle $ "Context saved to `" <> Text.pack file <> "`\n" -- Save a single expression to `file`-saveBinding (file : "=" : tokens) = do- loadedExpression <- parseAndLoad (unwords tokens)+saveBinding (Right (file, src)) = do+ loadedExpression <- parseAndLoad src _ <- typeCheck loadedExpression @@ -391,45 +425,114 @@ writeOutputHandle $ "Expression saved to `" <> Text.pack file <> "`\n" -saveBinding _ = Fail.fail ":save should be of the form `:save`, `:save file`, or `:save file = expr`"--setOption :: ( MonadIO m, MonadState Env m ) => [String] -> m ()-setOption [ "--explain" ] = do+setOption :: ( MonadIO m, MonadState Env m ) => String -> m ()+setOption "--explain" = modify (\e -> e { explain = True })-setOption _ = do+setOption _ = writeOutputHandle ":set should be of the form `:set <command line option>`" -unsetOption :: ( MonadIO m, MonadState Env m ) => [String] -> m ()-unsetOption [ "--explain" ] = do+unsetOption :: ( MonadIO m, MonadState Env m ) => String -> m ()+unsetOption "--explain" = modify (\e -> e { explain = False })-unsetOption _ = do+unsetOption _ = writeOutputHandle ":unset should be of the form `:unset <command line option>`" -cmdQuit :: ( MonadIO m, MonadState Env m ) => [String] -> m ()+quitMessage :: String+quitMessage = "Goodbye."++cmdQuit :: ( MonadIO m, MonadState Env m ) => String -> m () cmdQuit _ = do- liftIO (putStrLn "Goodbye.")+ liftIO (putStrLn quitMessage) liftIO (throwIO Interrupt) +help+ :: ( MonadFail m, MonadIO m, MonadState Env m )+ => HelpOptions m -> String -> m ()+help hs _ = do+ liftIO (putStrLn "Type any expression to normalize it or use one of the following commands:")+ forM_ hs $ \h -> do+ let name = helpOptionName h+ syntax = helpOptionSyntax h+ doc = helpOptionDoc h+ liftIO (putStrLn (":" <> name <> " " <> syntax))+ liftIO (putStrLn (" " <> doc)) optionsPrefix :: Char optionsPrefix = ':' +trim :: String -> String+trim = dropWhile isSpace . dropWhileEnd isSpace -options- :: ( Haskeline.MonadException m, MonadFail m, MonadIO m, MonadState Env m )- => Repline.Options m-options =- [ ( "type", dontCrash . typeOf )- , ( "hash", dontCrash . hashBinding )- , ( "let", dontCrash . addBinding . separateEqual )- , ( "clear", dontCrash . clearBindings)- , ( "load", dontCrash . loadBinding )- , ( "save", dontCrash . saveBinding . separateEqual )- , ( "set", dontCrash . setOption)- , ( "unset", dontCrash . unsetOption)- , ( "quit", cmdQuit )+data HelpOption m = HelpOption+ { helpOptionName :: String+ , helpOptionSyntax :: String+ , helpOptionDoc :: String+ , helpOptionFunction :: Repline.Cmd m+ }++type HelpOptions m = [HelpOption m]++helpOptions :: HelpOptions Repl+helpOptions =+ [ HelpOption+ "help"+ ""+ "Print help text and describe options"+ (dontCrash . help helpOptions)+ , HelpOption+ "paste"+ ""+ "Start a multi-line input. Submit with <Ctrl-D>"+ (error "Dhall.Repl.helpOptions: Unreachable")+ , HelpOption+ "type"+ "EXPRESSION"+ "Infer the type of an expression"+ (dontCrash . typeOf)+ , HelpOption+ "hash"+ "EXPRESSION"+ "Hash the normalized value of an expression"+ (dontCrash . hashBinding)+ , HelpOption+ "let"+ "IDENTIFIER = EXPRESSION"+ "Assign an expression to a variable"+ (dontCrash . addBinding)+ , HelpOption+ "clear"+ ""+ "Clear all bound variables"+ (dontCrash . clearBindings)+ , HelpOption+ "load"+ "[FILENAME]"+ "Load bound variables from a file"+ (dontCrash . loadBinding . trim)+ , HelpOption+ "save"+ "[FILENAME | FILENAME = EXPRESSION]"+ "Save bound variables or a given expression to a file"+ (dontCrash . saveBinding . parseAssignment)+ , HelpOption+ "set"+ "OPTION"+ "Set an option. Currently supported: --explain"+ (dontCrash . setOption . trim)+ , HelpOption+ "unset"+ "OPTION"+ "Unset an option"+ (dontCrash . unsetOption . trim)+ , HelpOption+ "quit"+ ""+ "Exit the REPL"+ cmdQuit ] +options :: Repline.Options Repl+options = (\h -> (helpOptionName h, helpOptionFunction h)) <$> helpOptions completer :: (Monad m, MonadFail m, MonadIO m, MonadState Env m)@@ -493,7 +596,7 @@ listCompletion = map simpleCompletion . filter (word `isPrefixOf`) algebraicComplete- :: [Text.Text] -> Dhall.Expr Dhall.Src Dhall.X -> [Text.Text]+ :: [Text.Text] -> Dhall.Expr Dhall.Src Void -> [Text.Text] algebraicComplete subFields expr = let keys = fmap ("." <>) . Map.keys @@ -512,19 +615,29 @@ fmap (("." <> f) <>) (algebraicComplete fs e) in case expr of- Dhall.Core.RecordLit m -> withMap (fmap Just m)+ Dhall.Core.RecordLit m -> withMap (fmap (Just . Dhall.Core.recordFieldValue) m) Dhall.Core.Union m -> withMap m _ -> [] greeter :: MonadIO m => m () greeter =- return ()+ let version = Meta.dhallVersionString+ message = "Welcome to the Dhall v" <> version <> " REPL! Type :help for more information."+ in liftIO (putStrLn message) +finaliser :: MonadIO m => m Repline.ExitDecision+finaliser = do+ liftIO (putStrLn quitMessage)+ pure Repline.Exit -dontCrash :: ( MonadIO m, Haskeline.MonadException m ) => m () -> m ()+dontCrash :: Repl () -> Repl () dontCrash m =- Haskeline.catch+#if MIN_VERSION_haskeline(0,8,0)+ Control.Monad.Catch.catch+#else+ System.Console.Haskeline.MonadException.catch+#endif m ( \ e@SomeException{} -> liftIO ( putStrLn ( displayException e ) ) ) @@ -538,7 +651,7 @@ output :: (Pretty.Pretty a, MonadState Env m, MonadIO m)- => Dhall.Expr s a -> m ()+ => Dhall.Expr Src a -> m () output expr = do writeOutputHandle "" -- Visual spacing @@ -548,16 +661,14 @@ outputWithoutSpacing :: (Pretty.Pretty a, MonadState Env m, MonadIO m)- => Dhall.Expr s a -> m ()+ => Dhall.Expr Src a -> m () outputWithoutSpacing expr = do Env { characterSet, outputHandle } <- get case outputHandle of Nothing -> pure () Just handle -> do- let stream =- Pretty.layoutSmart Dhall.Pretty.layoutOpts- (Dhall.Pretty.prettyCharacterSet characterSet expr)+ let stream = Dhall.Pretty.layout (Dhall.Pretty.prettyCharacterSet characterSet expr) supportsANSI <- liftIO (System.Console.ANSI.hSupportsANSI handle) let ansiStream =
@@ -0,0 +1,210 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{-| This module contains the implementation of the @dhall rewrite-with-schemas@+ subcommand+-}++module Dhall.Schemas+ ( -- | Schemas+ schemasCommand+ , Schemas(..)+ , rewriteWithSchemas+ , SchemasError(..)+ ) where++import Control.Applicative (empty)+import Control.Exception (Exception)+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Crypto (SHA256Digest)+import Dhall.Map (Map)+import Dhall.Pretty (CharacterSet (..), detectCharacterSet)+import Dhall.Src (Src)+import Dhall.Syntax (Expr (..), Import, Var (..))+import Dhall.Util+ ( Censor (..)+ , Header (..)+ , Input (..)+ , MultipleCheckFailed (..)+ , OutputMode (..)+ )++import qualified Control.Exception as Exception+import qualified Data.Map+import qualified Data.Maybe as Maybe+import qualified Data.Text.IO as Text.IO+import qualified Data.Void as Void+import qualified Dhall.Core as Core+import qualified Dhall.Import as Import+import qualified Dhall.Map as Map+import qualified Dhall.Normalize as Normalize+import qualified Dhall.Parser as Parser+import qualified Dhall.Pretty+import qualified Dhall.Substitution as Substitution+import qualified Dhall.Syntax as Syntax+import qualified Dhall.TypeCheck as TypeCheck+import qualified Dhall.Util as Util+import qualified Lens.Micro as Lens+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty.Terminal+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified System.AtomicWrite.Writer.LazyText as AtomicWrite+import qualified System.Console.ANSI as ANSI+import qualified System.IO as IO++-- | Arguments to the @rewrite-with-schemas@ subcommand+data Schemas = Schemas+ { chosenCharacterSet :: Maybe CharacterSet+ , censor :: Censor+ , input :: Input+ , outputMode :: OutputMode+ , schemas :: Text+ }++-- | Implementation of the @dhall rewrite-with-schemas@ subcommand+schemasCommand :: Schemas -> IO ()+schemasCommand Schemas{..} = do+ (inputName, originalText) <- case input of+ InputFile file -> (,) file <$> Text.IO.readFile file+ StandardInput -> (,) "(input)" <$> Text.IO.getContents++ (Header header, expression) <- Util.getExpressionAndHeaderFromStdinText censor inputName originalText++ let characterSet = fromMaybe (detectCharacterSet expression) chosenCharacterSet++ schemasRecord <- Core.throws (Parser.exprFromText "(schemas)" schemas)++ schemasExpression <- rewriteWithSchemas schemasRecord expression++ let docStream =+ Dhall.Pretty.layout+ ( Pretty.pretty header+ <> Dhall.Pretty.prettyCharacterSet characterSet schemasExpression+ <> "\n"+ )++ let schemasText = Pretty.Text.renderStrict docStream++ case outputMode of+ Write ->+ case input of+ InputFile file ->+ if originalText == schemasText+ then return ()+ else AtomicWrite.atomicWriteFile+ file+ (Pretty.Text.renderLazy docStream)+ StandardInput -> do+ supportsANSI <- ANSI.hSupportsANSI IO.stdout++ Pretty.Terminal.renderIO+ IO.stdout+ (if supportsANSI+ then fmap Dhall.Pretty.annToAnsiStyle docStream+ else Pretty.unAnnotateS docStream)++ Check ->+ if originalText == schemasText+ then return ()+ else do+ let command = "rewrite-with-schemas"++ let modified = "rewritten"++ let inputs = pure input++ Exception.throwIO MultipleCheckFailed{..}++decodeSchema :: Expr s Void -> Maybe (Expr s Void, Map Text (Expr s Void))+decodeSchema (RecordLit m)+ | Just _Type <- Core.recordFieldValue <$> Map.lookup "Type" m+ , Just (RecordLit _default) <- Core.recordFieldValue <$> Map.lookup "default" m =+ Just (_Type, Core.recordFieldValue <$> _default)+decodeSchema _ =+ Nothing++decodeSchemas+ :: Expr s Void+ -> Maybe (Data.Map.Map SHA256Digest (Text, Map Text (Expr s Void)))+decodeSchemas (RecordLit keyValues) = do+ m <- traverse (decodeSchema . Core.recordFieldValue) keyValues++ let typeMetadata = Data.Map.fromList $ do+ (name, (_Type, _default)) <- Map.toList m++ return (Import.hashExpression (Syntax.denote _Type), (name, _default))++ return typeMetadata+decodeSchemas _ =+ empty++-- | Simplify a Dhall expression using a record of schemas+rewriteWithSchemas+ :: Expr Src Import+ -- ^ Record of schemas+ -> Expr Src Import+ -- ^ Expression to simplify using the supplied schemas+ -> IO (Expr Src Import)+rewriteWithSchemas _schemas expression = do+ resolvedSchemas <- Import.load _schemas+ resolvedExpression <- Import.load expression++ _ <- Core.throws (TypeCheck.typeOf resolvedSchemas)+ _ <- Core.throws (TypeCheck.typeOf resolvedExpression)++ let normalizedSchemas = Normalize.normalize resolvedSchemas+ let normalizedExpression = Normalize.normalize resolvedExpression++ typeMetadata <- case decodeSchemas normalizedSchemas of+ Just typeMetadata -> return typeMetadata+ Nothing -> Exception.throwIO NotASchemaRecord++ let schemasRewrite subExpression@(RecordLit keyValues) =+ Maybe.fromMaybe subExpression $ do+ let substitutions = Map.singleton "schemas" normalizedSchemas++ let substitutedExpression =+ Substitution.substitute subExpression substitutions++ hash <- case TypeCheck.typeOf substitutedExpression of+ Left _ ->+ empty+ Right subExpressionType ->+ return (Import.hashExpression (Syntax.denote subExpressionType))++ (name, _default) <- Data.Map.lookup hash typeMetadata++ let diff a b | a == b = Nothing+ | otherwise = Just a++ let defaultedKeyValues =+ Core.makeRecordField <$>+ Map.fromMap (+ Data.Map.differenceWith diff+ (Map.toMap $ Core.recordFieldValue <$> keyValues)+ (Map.toMap _default))++ let defaultedRecord = RecordLit defaultedKeyValues++ return (RecordCompletion (Field "schemas" $ Core.makeFieldSelection name) defaultedRecord)+ schemasRewrite subExpression =+ subExpression++ let rewrittenExpression :: Expr Src Import+ rewrittenExpression =+ fmap Void.absurd (Lens.transformOf Syntax.subExpressions schemasRewrite normalizedExpression)++ if Normalize.freeIn (V "schemas" 0) rewrittenExpression+ then return (Let (Syntax.makeBinding "schemas" _schemas) rewrittenExpression)+ else return expression++-- | Errors that can be thrown by `rewriteWithSchemas`+data SchemasError = NotASchemaRecord+ deriving (Exception)++instance Show SchemasError where+ show NotASchemaRecord =+ Util._ERROR <> ": The --schemas argument is not a record of schemas"
@@ -1,5 +1,7 @@+{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveLift #-} -- | This module only exports ways of constructing a Set, -- retrieving List, Set, and Seq representations of the same data,@@ -9,51 +11,99 @@ module Dhall.Set ( Set(..) , toList+ , toAscList , toSet , toSeq , fromList+ , fromSet , append , empty , difference+ , sort+ , isSorted+ , null+ , size ) where -import Prelude-import Data.List (foldl')-import Data.Sequence (Seq, (|>))-import Data.Data (Data)-import GHC.Generics (Generic)+import Control.DeepSeq (NFData)+import Data.Data (Data)+import Data.List (foldl')+import Data.Sequence (Seq, (|>))+import GHC.Generics (Generic)+import Instances.TH.Lift ()+import Language.Haskell.TH.Syntax (Lift)+import Prelude hiding (null) -import qualified Data.Set-import qualified Data.Sequence import qualified Data.Foldable+import qualified Data.Sequence+import qualified Data.Set +{-| This is a variation on @"Data.Set".`Data.Set.Set`@ that remembers the+ original order of elements. This ensures that ordering is not lost when+ formatting Dhall code+-} data Set a = Set (Data.Set.Set a) (Seq a)- deriving (Eq, Generic, Ord, Show, Data)+ deriving (Generic, Show, Data, NFData, Lift)+-- Invariant: In @Set set seq@, @toAscList set == sort (toList seq)@. +instance Eq a => Eq (Set a) where+ (Set _ x) == (Set _ y) = x == y+ {-# INLINABLE (==) #-}++instance Ord a => Ord (Set a) where+ compare (Set _ x) (Set _ y) = compare x y+ {-# INLINABLE compare #-}+ instance Foldable Set where- foldMap f = foldMap f . toSeq+ foldMap f (Set _ x) = foldMap f x+ {-# INLINABLE foldMap #-} + toList = Dhall.Set.toList+ {-# INLINABLE toList #-}++ null = Dhall.Set.null+ {-# INLINABLE null #-}++ length = Dhall.Set.size+ {-# INLINABLE length #-}++-- | Convert to an unordered @"Data.Set".`Data.Set.Set`@ toSet :: Set a -> Data.Set.Set a toSet (Set s _) = s +-- | Convert to an ordered `Seq` toSeq :: Set a -> Seq a toSeq (Set _ xs) = xs +{-| Convert a `Dhall.Set.Set` to a list, preserving the original order of the+ elements+-} toList :: Set a -> [a]-toList = Data.Foldable.toList+toList (Set _ xs) = Data.Foldable.toList xs +-- | Convert a `Dhall.Set.Set` to a list of ascending elements+toAscList :: Set a -> [a]+toAscList (Set s _) = Data.Set.toAscList s++-- | Convert a list to a `Dhall.Set.Set`, remembering the element order+fromList :: Ord a => [a] -> Set a+fromList = foldl' (flip append) empty -- O(n log n) time complexity, O(n) space complexity. -- Implementing it this way is a little silly, but is faster than (nub xs). -- n.b. toList . fromList = id, only if the list elements are unique-fromList :: Ord a => [a] -> Set a-fromList = foldl' (flip append) empty --- O(log n) time complexity.+-- | Convert a @"Data.Set".`Data.Set.Set`@ to a sorted `Dhall.Set.Set`+fromSet :: Data.Set.Set a -> Set a+fromSet s = Set s (Data.Sequence.fromList (Data.Set.elems s))++-- | Append an element to the end of a `Dhall.Set.Set` append :: Ord a => a -> Set a -> Set a append x os@(Set s xs) | Data.Set.member x s = os | otherwise = Set (Data.Set.insert x s) (xs |> x)+-- O(log n) time complexity. +-- | The empty `Dhall.Set.Set` empty :: Set a empty = Set Data.Set.empty Data.Sequence.empty @@ -62,3 +112,36 @@ difference :: Ord a => Set a -> Set a -> [a] difference os (Set s _) = filter (\ x -> not (Data.Set.member x s)) (toList os)++{-| Sort the set elements, forgetting their original ordering.++>>> sort (fromList [2, 1]) == fromList [1, 2]+True+-}+sort :: Ord a => Set a -> Set a+sort (Set s _) = Set s (Data.Sequence.fromList (Data.Set.toList s))++{-|+>>> isSorted (fromList [2, 1])+False+>>> isSorted (fromList [1, 2])+True+-}+isSorted :: Ord a => Set a -> Bool+isSorted s = toList s == Data.Set.toList (toSet s)++{-|+>>> null (fromList [1])+False+>>> null (fromList [])+True+-}+null :: Set a -> Bool+null (Set s _) = Data.Set.null s++{-|+>>> size (fromList [1])+1+-}+size :: Set a -> Int+size (Set s _) = Data.Set.size s
@@ -1,6 +1,9 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-} -- | This module provides the `Src` type used for source spans in error messages @@ -9,12 +12,14 @@ Src(..) ) where -import Data.Data (Data)-import Data.Monoid ((<>))-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Pretty (..))-import GHC.Generics (Generic)-import Text.Megaparsec (SourcePos)+import Control.DeepSeq (NFData)+import Data.Data (Data)+import Data.Text (Text)+import GHC.Generics (Generic)+import Instances.TH.Lift ()+import Language.Haskell.TH.Syntax (Lift (..))+import Prettyprinter (Pretty (..))+import Text.Megaparsec (SourcePos (SourcePos), mkPos, unPos) import {-# SOURCE #-} qualified Dhall.Util @@ -23,10 +28,28 @@ import qualified Text.Printf as Printf -- | Source code extract-data Src = Src !SourcePos !SourcePos Text- -- Text field is intentionally lazy- deriving (Data, Eq, Generic, Ord, Show)+data Src = Src+ { srcStart :: !SourcePos+ , srcEnd :: !SourcePos+ , srcText :: Text -- Text field is intentionally lazy+ } deriving (Data, Eq, Generic, Ord, Show, NFData) ++instance Lift Src where+#if MIN_VERSION_template_haskell(2,16,0)+ liftTyped (Src (SourcePos a b c) (SourcePos d e f) g) =+ [|| Src (SourcePos a (mkPos b') (mkPos c')) (SourcePos d (mkPos e') (mkPos f')) g ||]+#else+ lift (Src (SourcePos a b c) (SourcePos d e f) g) =+ [| Src (SourcePos a (mkPos b') (mkPos c')) (SourcePos d (mkPos e') (mkPos f')) g |]+#endif+ where+ b' = unPos b+ c' = unPos c+ e' = unPos e+ f' = unPos f++ instance Pretty Src where pretty (Src begin _ text) = pretty (Dhall.Util.snip numberedLines)@@ -55,6 +78,6 @@ inputString = Text.unpack line outputString =- Printf.printf ("%" <> show numberWidth <> "d: %s") n inputString+ Printf.printf ("%" <> show numberWidth <> "d│ %s") n inputString numberedLines = Text.unlines (zipWith adapt [minimumNumber..] ls)
@@ -0,0 +1,34 @@+{- | This module provides types and functions used in the substitution step+ which is done before type checking and normalization.+-}++module Dhall.Substitution where++import Data.Text (Text)+import Dhall.Normalize (subst)+import Dhall.Syntax (Expr, Var (..))++import qualified Dhall.Map++{- | Substitutions map variables to arbitrary Dhall expressions.+ Note that we use "Dhall.Map.Map" as an underlying structure. Hence we respect insertion order.+-}+type Substitutions s a = Dhall.Map.Map Text (Expr s a)++{- | An empty substitution map.+-}+empty :: Substitutions s a+empty = Dhall.Map.empty++-- | @substitute expr s@ replaces all variables in @expr@ (or its subexpression) with their substitute.+-- For example, if the substitution map maps the variable @Foo@ to the text \"Foo\" all occurrences of @Foo@ with the text \"Foo\".+--+-- The substitutions will be done in the order they are inserted into the substitution map:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > substitute (Dhall.Core.Var "Foo") (Dhall.Map.fromList [("Foo", Dhall.Core.Var "Bar"), ("Bar", Dhall.Core.Var "Baz")])+--+-- results in @Dhall.Core.Var \"Baz\"@ since we first substitute \"Foo\" with \"Bar\" and then the resulting \"Bar\" with the final \"Baz\".+substitute :: Expr s a -> Substitutions s a -> Expr s a+substitute expr = foldl (\memo (k, v) -> subst (V k 0) v memo) expr . Dhall.Map.toList
@@ -0,0 +1,31 @@+module Dhall.Syntax+ ( module Export+ ) where++import {-# SOURCE #-} Dhall.Pretty.Internal as Export+ ( CharacterSet (..)+ )+import Dhall.Syntax.Binding as Export+import Dhall.Syntax.Chunks as Export+import Dhall.Syntax.Const as Export+import Dhall.Syntax.Expr as Export+import Dhall.Syntax.FunctionBinding as Export+import Dhall.Syntax.Import as Export+import Dhall.Syntax.Instances.Applicative as Export ()+import Dhall.Syntax.Instances.Bifunctor as Export ()+import Dhall.Syntax.Instances.Data as Export ()+import Dhall.Syntax.Instances.Eq as Export ()+import Dhall.Syntax.Instances.Foldable as Export ()+import Dhall.Syntax.Instances.Functor as Export ()+import Dhall.Syntax.Instances.Lift as Export ()+import Dhall.Syntax.Instances.Monad as Export ()+import Dhall.Syntax.Instances.NFData as Export ()+import Dhall.Syntax.Instances.Ord as Export ()+import Dhall.Syntax.Instances.Pretty as Export+import Dhall.Syntax.Instances.Show as Export ()+import Dhall.Syntax.Instances.Traversable as Export ()+import Dhall.Syntax.MultiLet as Export+import Dhall.Syntax.Operations as Export+import Dhall.Syntax.RecordField as Export+import Dhall.Syntax.Types as Export+import Dhall.Syntax.Var as Export
@@ -0,0 +1,57 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.Binding+ ( Binding(..)+ , makeBinding++ -- * Optics+ , bindingExprs+ ) where++import Data.Text (Text)+import {-# SOURCE #-} Dhall.Syntax.Expr (Expr)+import GHC.Generics (Generic)++-- | Record the binding part of a @let@ expression.+--+-- For example,+--+-- > let {- A -} x {- B -} : {- C -} Bool = {- D -} True in x+--+-- … will be instantiated as follows:+--+-- * @bindingSrc0@ corresponds to the @A@ comment.+-- * @variable@ is @"x"@+-- * @bindingSrc1@ corresponds to the @B@ comment.+-- * @annotation@ is 'Just' a pair, corresponding to the @C@ comment and @Bool@.+-- * @bindingSrc2@ corresponds to the @D@ comment.+-- * @value@ corresponds to @True@.+data Binding s a = Binding+ { bindingSrc0 :: Maybe s+ , variable :: Text+ , bindingSrc1 :: Maybe s+ , annotation :: Maybe (Maybe s, Expr s a)+ , bindingSrc2 :: Maybe s+ , value :: Expr s a+ } deriving Generic++{-| Construct a 'Binding' with no source information and no type annotation.+-}+makeBinding :: Text -> Expr s a -> Binding s a+makeBinding name = Binding Nothing name Nothing Nothing Nothing++{-| Traverse over the immediate 'Expr' children in a 'Binding'.+-}+bindingExprs+ :: (Applicative f)+ => (Expr s a -> f (Expr s b))+ -> Binding s a -> f (Binding s b)+bindingExprs f (Binding s0 n s1 t s2 v) =+ Binding+ <$> pure s0+ <*> pure n+ <*> pure s1+ <*> traverse (traverse f) t+ <*> pure s2+ <*> f v+{-# INLINABLE bindingExprs #-}
@@ -0,0 +1,141 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Syntax.Chunks+ ( Chunks(..)++ -- * Optics+ , chunkExprs++ -- * `Data.Text.Text` manipulation+ , toDoubleQuoted+ , longestSharedWhitespacePrefix+ , linesLiteral+ , unlinesLiteral+ ) where++import Data.List.NonEmpty (NonEmpty (..))+import Data.String (IsString (..))+import Data.Text (Text)+import Dhall.Src (Src)+import {-# SOURCE #-} Dhall.Syntax.Expr (Expr)+import GHC.Generics (Generic)++import qualified Data.Foldable+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Text++-- | The body of an interpolated @Text@ literal+data Chunks s a = Chunks [(Text, Expr s a)] Text+ deriving Generic++instance IsString (Chunks s a) where+ fromString str = Chunks [] (fromString str)++instance Semigroup (Chunks s a) where+ Chunks xysL zL <> Chunks [] zR =+ Chunks xysL (zL <> zR)+ Chunks xysL zL <> Chunks ((x, y):xysR) zR =+ Chunks (xysL ++ (zL <> x, y):xysR) zR++instance Monoid (Chunks s a) where+ mempty = Chunks [] mempty++-- | A traversal over the immediate sub-expressions in 'Chunks'.+chunkExprs+ :: Applicative f+ => (Expr s a -> f (Expr t b))+ -> Chunks s a -> f (Chunks t b)+chunkExprs f (Chunks chunks final) =+ flip Chunks final <$> traverse (traverse f) chunks+{-# INLINABLE chunkExprs #-}++-- | Same as @Data.Text.splitOn@, except always returning a `NonEmpty` result+splitOn :: Text -> Text -> NonEmpty Text+splitOn needle haystack =+ case Data.Text.splitOn needle haystack of+ [] -> "" :| []+ t : ts -> t :| ts++-- | Split `Chunks` by lines+linesLiteral :: Chunks s a -> NonEmpty (Chunks s a)+linesLiteral (Chunks [] suffix) =+ fmap (Chunks []) (splitOn "\n" suffix)+linesLiteral (Chunks ((prefix, interpolation) : pairs₀) suffix₀) =+ foldr+ NonEmpty.cons+ (Chunks ((lastLine, interpolation) : pairs₁) suffix₁ :| chunks)+ (fmap (Chunks []) initLines)+ where+ splitLines = splitOn "\n" prefix++ initLines = NonEmpty.init splitLines+ lastLine = NonEmpty.last splitLines++ Chunks pairs₁ suffix₁ :| chunks = linesLiteral (Chunks pairs₀ suffix₀)++-- | Flatten several `Chunks` back into a single `Chunks` by inserting newlines+unlinesLiteral :: NonEmpty (Chunks s a) -> Chunks s a+unlinesLiteral chunks =+ Data.Foldable.fold (NonEmpty.intersperse "\n" chunks)++-- | Returns `True` if the `Chunks` represents a blank line+emptyLine :: Chunks s a -> Bool+emptyLine (Chunks [] "" ) = True+emptyLine (Chunks [] "\r") = True -- So that `\r\n` is treated as a blank line+emptyLine _ = False++-- | Return the leading whitespace for a `Chunks` literal+leadingSpaces :: Chunks s a -> Text+leadingSpaces chunks = Data.Text.takeWhile isSpace firstText+ where+ isSpace c = c == ' ' || c == '\t'++ firstText =+ case chunks of+ Chunks [] suffix -> suffix+ Chunks ((prefix, _) : _ ) _ -> prefix++{-| Compute the longest shared whitespace prefix for the purposes of stripping+ leading indentation+-}+longestSharedWhitespacePrefix :: NonEmpty (Chunks s a) -> Text+longestSharedWhitespacePrefix literals =+ case fmap leadingSpaces filteredLines of+ l : ls -> Data.Foldable.foldl' sharedPrefix l ls+ [] -> ""+ where+ sharedPrefix ab ac =+ case Data.Text.commonPrefixes ab ac of+ Just (a, _b, _c) -> a+ Nothing -> ""++ -- The standard specifies to filter out blank lines for all lines *except*+ -- for the last line+ filteredLines = newInit <> pure oldLast+ where+ oldInit = NonEmpty.init literals++ oldLast = NonEmpty.last literals++ newInit = filter (not . emptyLine) oldInit++-- | Drop the first @n@ characters for a `Chunks` literal+dropLiteral :: Int -> Chunks s a -> Chunks s a+dropLiteral n (Chunks [] suffix) =+ Chunks [] (Data.Text.drop n suffix)+dropLiteral n (Chunks ((prefix, interpolation) : rest) suffix) =+ Chunks ((Data.Text.drop n prefix, interpolation) : rest) suffix++{-| Convert a single-quoted `Chunks` literal to the equivalent double-quoted+ `Chunks` literal+-}+toDoubleQuoted :: Chunks Src a -> Chunks Src a+toDoubleQuoted literal =+ unlinesLiteral (fmap (dropLiteral indent) literals)+ where+ literals = linesLiteral literal++ longestSharedPrefix = longestSharedWhitespacePrefix literals++ indent = Data.Text.length longestSharedPrefix
@@ -0,0 +1,8 @@+{-# LANGUAGE StandaloneKindSignatures #-}++module Dhall.Syntax.Chunks where++import Data.Kind (Type)++type Chunks :: Type -> Type -> Type+data Chunks s a
@@ -0,0 +1,29 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.Const+ ( Const(..)+ ) where++import GHC.Generics (Generic)++{-| Constants for a pure type system++ The axioms are:++> ⊦ Type : Kind+> ⊦ Kind : Sort++ ... and the valid rule pairs are:++> ⊦ Type ↝ Type : Type -- Functions from terms to terms (ordinary functions)+> ⊦ Kind ↝ Type : Type -- Functions from types to terms (type-polymorphic functions)+> ⊦ Sort ↝ Type : Type -- Functions from kinds to terms+> ⊦ Kind ↝ Kind : Kind -- Functions from types to types (type-level functions)+> ⊦ Sort ↝ Kind : Sort -- Functions from kinds to types (kind-polymorphic functions)+> ⊦ Sort ↝ Sort : Sort -- Functions from kinds to kinds (kind-level functions)++ Note that Dhall does not support functions from terms to types and therefore+ Dhall is not a dependently typed language+-}+data Const = Type | Kind | Sort+ deriving (Bounded, Enum, Generic)
@@ -0,0 +1,267 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE StandaloneKindSignatures #-}++module Dhall.Syntax.Expr+ ( Expr(..)+ ) where++import Data.ByteString (ByteString)+import Data.Kind (Type)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Sequence (Seq)+import Data.String (IsString (..))+import Data.Text (Text)+import Data.Traversable ()+import Dhall.Map (Map)+import {-# SOURCE #-} Dhall.Pretty.Internal (CharacterSet (..))+import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var+import GHC.Generics (Generic)+import Numeric.Natural (Natural)++import qualified Data.Time as Time++{-| Syntax tree for expressions++ The @s@ type parameter is used to track the presence or absence of+ `Dhall.Src.Src` spans:++ * If @s = `Dhall.Src.Src`@ then the code may contains `Dhall.Src.Src` spans+ (either in a `Note` constructor or inline within another constructor, like+ `Let`)+ * If @s = `Data.Void.Void`@ then the code has no `Dhall.Src.Src` spans++ The @a@ type parameter is used to track the presence or absence of imports++ * If @a = `Dhall.Syntax.Import.Import`@ then the code may contain unresolved+ `Dhall.Syntax.Import.Import`s+ * If @a = `Data.Void.Void`@ then the code has no+ `Dhall.Syntax.Import.Import`s+-}+type Expr :: Type -> Type -> Type+data Expr s a+ -- | > Const c ~ c+ = Const Const+ -- | > Var (V x 0) ~ x+ -- > Var (V x n) ~ x@n+ | Var Var+ -- | > Lam _ (FunctionBinding _ "x" _ _ A) b ~ λ(x : A) -> b+ | Lam (Maybe CharacterSet) (FunctionBinding s a) (Expr s a)+ -- | > Pi _ "_" A B ~ A -> B+ -- > Pi _ x A B ~ ∀(x : A) -> B+ | Pi (Maybe CharacterSet) Text (Expr s a) (Expr s a)+ -- | > App f a ~ f a+ | App (Expr s a) (Expr s a)+ -- | > Let (Binding _ x _ Nothing _ r) e ~ let x = r in e+ -- > Let (Binding _ x _ (Just t ) _ r) e ~ let x : t = r in e+ --+ -- The difference between+ --+ -- > let x = a let y = b in e+ --+ -- and+ --+ -- > let x = a in let y = b in e+ --+ -- is only an additional 'Note' around @'Let' "y" …@ in the second+ -- example.+ --+ -- See `Dhall.Syntax.MultiLet.MultiLet` for a representation of let-blocks+ -- that mirrors the source code more closely.+ | Let (Binding s a) (Expr s a)+ -- | > Annot x t ~ x : t+ | Annot (Expr s a) (Expr s a)+ -- | > Bool ~ Bool+ | Bool+ -- | > BoolLit b ~ b+ | BoolLit Bool+ -- | > BoolAnd x y ~ x && y+ | BoolAnd (Expr s a) (Expr s a)+ -- | > BoolOr x y ~ x || y+ | BoolOr (Expr s a) (Expr s a)+ -- | > BoolEQ x y ~ x == y+ | BoolEQ (Expr s a) (Expr s a)+ -- | > BoolNE x y ~ x != y+ | BoolNE (Expr s a) (Expr s a)+ -- | > BoolIf x y z ~ if x then y else z+ | BoolIf (Expr s a) (Expr s a) (Expr s a)+ -- | > Bytes ~ Bytes+ | Bytes+ -- | > BytesLit "\x00\xFF" ~ 0x"00FF"+ | BytesLit ByteString+ -- | > Natural ~ Natural+ | Natural+ -- | > NaturalLit n ~ n+ | NaturalLit Natural+ -- | > NaturalFold ~ Natural/fold+ | NaturalFold+ -- | > NaturalBuild ~ Natural/build+ | NaturalBuild+ -- | > NaturalIsZero ~ Natural/isZero+ | NaturalIsZero+ -- | > NaturalEven ~ Natural/even+ | NaturalEven+ -- | > NaturalOdd ~ Natural/odd+ | NaturalOdd+ -- | > NaturalToInteger ~ Natural/toInteger+ | NaturalToInteger+ -- | > NaturalShow ~ Natural/show+ | NaturalShow+ -- | > NaturalSubtract ~ Natural/subtract+ | NaturalSubtract+ -- | > NaturalPlus x y ~ x + y+ | NaturalPlus (Expr s a) (Expr s a)+ -- | > NaturalTimes x y ~ x * y+ | NaturalTimes (Expr s a) (Expr s a)+ -- | > Integer ~ Integer+ | Integer+ -- | > IntegerLit n ~ ±n+ | IntegerLit Integer+ -- | > IntegerClamp ~ Integer/clamp+ | IntegerClamp+ -- | > IntegerNegate ~ Integer/negate+ | IntegerNegate+ -- | > IntegerShow ~ Integer/show+ | IntegerShow+ -- | > IntegerToDouble ~ Integer/toDouble+ | IntegerToDouble+ -- | > Double ~ Double+ | Double+ -- | > DoubleLit n ~ n+ | DoubleLit DhallDouble+ -- | > DoubleShow ~ Double/show+ | DoubleShow+ -- | > Text ~ Text+ | Text+ -- | > TextLit (Chunks [(t1, e1), (t2, e2)] t3) ~ "t1${e1}t2${e2}t3"+ | TextLit (Chunks s a)+ -- | > TextAppend x y ~ x ++ y+ | TextAppend (Expr s a) (Expr s a)+ -- | > TextReplace ~ Text/replace+ | TextReplace+ -- | > TextShow ~ Text/show+ | TextShow+ -- | > Date ~ Date+ | Date+ -- | > DateLiteral (fromGregorian _YYYY _MM _DD) ~ YYYY-MM-DD+ | DateLiteral Time.Day+ -- | > DateShow ~ Date/show+ | DateShow+ -- | > Time ~ Time+ | Time+ -- | > TimeLiteral (TimeOfDay hh mm ss) _ ~ hh:mm:ss+ | TimeLiteral+ Time.TimeOfDay+ Word+ -- ^ Precision+ -- | > TimeShow ~ Time/show+ | TimeShow+ -- | > TimeZone ~ TimeZone+ | TimeZone+ -- | > TimeZoneLiteral (TimeZone ( 60 * _HH + _MM) _ _) ~ +HH:MM+ -- | > TimeZoneLiteral (TimeZone (-60 * _HH + _MM) _ _) ~ -HH:MM+ | TimeZoneLiteral Time.TimeZone+ -- | > TimeZoneShow ~ TimeZone/Show+ | TimeZoneShow+ -- | > List ~ List+ | List+ -- | > ListLit (Just t ) [] ~ [] : t+ -- > ListLit Nothing [x, y, z] ~ [x, y, z]+ --+ -- Invariant: A non-empty list literal is always represented as+ -- @ListLit Nothing xs@.+ --+ -- When an annotated, non-empty list literal is parsed, it is represented+ -- as+ --+ -- > Annot (ListLit Nothing [x, y, z]) t ~ [x, y, z] : t++ -- Eventually we should have separate constructors for empty and non-empty+ -- list literals. For now it's easier to check the invariant in @infer@.+ -- See https://github.com/dhall-lang/dhall-haskell/issues/1359#issuecomment-537087234.+ | ListLit (Maybe (Expr s a)) (Seq (Expr s a))+ -- | > ListAppend x y ~ x # y+ | ListAppend (Expr s a) (Expr s a)+ -- | > ListBuild ~ List/build+ | ListBuild+ -- | > ListFold ~ List/fold+ | ListFold+ -- | > ListLength ~ List/length+ | ListLength+ -- | > ListHead ~ List/head+ | ListHead+ -- | > ListLast ~ List/last+ | ListLast+ -- | > ListIndexed ~ List/indexed+ | ListIndexed+ -- | > ListReverse ~ List/reverse+ | ListReverse+ -- | > Optional ~ Optional+ | Optional+ -- | > Some e ~ Some e+ | Some (Expr s a)+ -- | > None ~ None+ | None+ -- | > Record [ (k1, RecordField _ t1) ~ { k1 : t1, k2 : t1 }+ -- > , (k2, RecordField _ t2)+ -- > ]+ | Record (Map Text (RecordField s a))+ -- | > RecordLit [ (k1, RecordField _ v1) ~ { k1 = v1, k2 = v2 }+ -- > , (k2, RecordField _ v2)+ -- > ]+ | RecordLit (Map Text (RecordField s a))+ -- | > Union [(k1, Just t1), (k2, Nothing)] ~ < k1 : t1 | k2 >+ | Union (Map Text (Maybe (Expr s a)))+ -- | > Combine _ Nothing x y ~ x ∧ y+ --+ -- The first field is a `Just` when the `Combine` operator is introduced+ -- as a result of desugaring duplicate record fields:+ --+ -- > RecordLit [ ( k ~ { k = x, k = y }+ -- > , RecordField+ -- > _+ -- > (Combine (Just k) x y)+ -- > )]+ | Combine (Maybe CharacterSet) (Maybe Text) (Expr s a) (Expr s a)+ -- | > CombineTypes _ x y ~ x ⩓ y+ | CombineTypes (Maybe CharacterSet) (Expr s a) (Expr s a)+ -- | > Prefer _ _ x y ~ x ⫽ y+ | Prefer (Maybe CharacterSet) PreferAnnotation (Expr s a) (Expr s a)+ -- | > RecordCompletion x y ~ x::y+ | RecordCompletion (Expr s a) (Expr s a)+ -- | > Merge x y (Just t ) ~ merge x y : t+ -- > Merge x y Nothing ~ merge x y+ | Merge (Expr s a) (Expr s a) (Maybe (Expr s a))+ -- | > ToMap x (Just t) ~ toMap x : t+ -- > ToMap x Nothing ~ toMap x+ | ToMap (Expr s a) (Maybe (Expr s a))+ -- | > ShowConstructor x ~ showConstructor x+ | ShowConstructor (Expr s a)+ -- | > Field e (FieldSelection _ x _) ~ e.x+ | Field (Expr s a) (FieldSelection s)+ -- | > Project e (Left xs) ~ e.{ xs }+ -- > Project e (Right t) ~ e.(t)+ | Project (Expr s a) (Either [Text] (Expr s a))+ -- | > Assert e ~ assert : e+ | Assert (Expr s a)+ -- | > Equivalent _ x y ~ x ≡ y+ | Equivalent (Maybe CharacterSet) (Expr s a) (Expr s a)+ -- | > With x y e ~ x with y = e+ | With (Expr s a) (NonEmpty WithComponent) (Expr s a)+ -- | > Note s x ~ e+ | Note s (Expr s a)+ -- | > ImportAlt ~ e1 ? e2+ | ImportAlt (Expr s a) (Expr s a)+ -- | > Embed import ~ import+ | Embed a+ deriving (Generic)+-- NB: If you add a constructor to Expr, please also update the Arbitrary+-- instance in Dhall.Test.QuickCheck.++instance IsString (Expr s a) where+ fromString str = Var (fromString str)
@@ -0,0 +1,8 @@+{-# LANGUAGE StandaloneKindSignatures #-}++module Dhall.Syntax.Expr where++import Data.Kind (Type)++type Expr :: Type -> Type -> Type+data Expr s a
@@ -0,0 +1,53 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.FunctionBinding+ ( FunctionBinding(..)+ , makeFunctionBinding++ -- * Optics+ , functionBindingExprs+ ) where++import Data.Text (Text)+import {-# SOURCE #-} Dhall.Syntax.Expr (Expr)+import GHC.Generics (Generic)++-- | Record the label of a function or a function-type expression+--+-- For example,+--+-- > λ({- A -} a {- B -} : {- C -} T) -> e+--+-- … will be instantiated as follows:+--+-- * @functionBindingSrc0@ corresponds to the @A@ comment+-- * @functionBindingVariable@ is @a@+-- * @functionBindingSrc1@ corresponds to the @B@ comment+-- * @functionBindingSrc2@ corresponds to the @C@ comment+-- * @functionBindingAnnotation@ is @T@+data FunctionBinding s a = FunctionBinding+ { functionBindingSrc0 :: Maybe s+ , functionBindingVariable :: Text+ , functionBindingSrc1 :: Maybe s+ , functionBindingSrc2 :: Maybe s+ , functionBindingAnnotation :: Expr s a+ } deriving Generic++-- | Smart constructor for 'FunctionBinding' with no src information+makeFunctionBinding :: Text -> Expr s a -> FunctionBinding s a+makeFunctionBinding l t = FunctionBinding Nothing l Nothing Nothing t++{-| Traverse over the immediate 'Expr' children in a 'FunctionBinding'.+-}+functionBindingExprs+ :: Applicative f+ => (Expr s a -> f (Expr s b))+ -> FunctionBinding s a -> f (FunctionBinding s b)+functionBindingExprs f (FunctionBinding s0 label s1 s2 type_) =+ FunctionBinding+ <$> pure s0+ <*> pure label+ <*> pure s1+ <*> pure s2+ <*> f type_+{-# INLINABLE functionBindingExprs #-}
@@ -0,0 +1,139 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Dhall.Syntax.Import+ ( Directory(..)+ , File(..)+ , FilePrefix(..)+ , Import(..)+ , ImportHashed(..)+ , ImportMode(..)+ , ImportType(..)+ , URL(..)+ , Scheme(..)+ ) where++import Data.Data (Data)+import Data.Text (Text)+import Dhall.Src (Src (..))+import Dhall.Syntax.Expr (Expr (..))+import Dhall.Syntax.Instances.Data ()+import Dhall.Syntax.Instances.Functor ()+import GHC.Generics (Generic)++import qualified Dhall.Crypto++{-| Internal representation of a directory that stores the path components in+ reverse order++ In other words, the directory @\/foo\/bar\/baz@ is encoded as+ @Directory { components = [ "baz", "bar", "foo" ] }@+-}+newtype Directory = Directory { components :: [Text] }+ deriving (Data, Generic)++{-| A `File` is a `directory` followed by one additional path component+ representing the `file` name+-}+data File = File+ { directory :: Directory+ , file :: Text+ } deriving (Data, Generic)++-- | The beginning of a file path which anchors subsequent path components+data FilePrefix+ = Absolute+ -- ^ Absolute path+ | Here+ -- ^ Path relative to @.@+ | Parent+ -- ^ Path relative to @..@+ | Home+ -- ^ Path relative to @~@+ deriving (Data, Generic)++-- | The URI scheme+data Scheme = HTTP | HTTPS+ deriving (Data, Generic)++-- | This type stores all of the components of a remote import+data URL = URL+ { scheme :: Scheme+ , authority :: Text+ , path :: File+ , query :: Maybe Text+ , headers :: Maybe (Expr Src Import)+ } deriving (Data, Generic)++-- | The type of import (i.e. local vs. remote vs. environment)+data ImportType+ = Local FilePrefix File+ -- ^ Local path+ | Remote URL+ -- ^ URL of remote resource and optional headers stored in an import+ | Env Text+ -- ^ Environment variable+ | Missing+ deriving (Data, Generic)++-- | How to interpret the import's contents (i.e. as Dhall code or raw text)+data ImportMode = Code | RawText | Location | RawBytes+ deriving (Data, Generic)++-- | A `ImportType` extended with an optional hash for semantic integrity checks+data ImportHashed = ImportHashed+ { hash :: Maybe Dhall.Crypto.SHA256Digest+ , importType :: ImportType+ } deriving (Data, Generic)++-- | Reference to an external resource+data Import = Import+ { importHashed :: ImportHashed+ , importMode :: ImportMode+ } deriving (Data, Generic)+++++instance Semigroup Directory where+ Directory components0 <> Directory components1 =+ Directory (components1 <> components0)++instance Semigroup File where+ File directory0 _ <> File directory1 file =+ File (directory0 <> directory1) file++instance Semigroup ImportType where+ Local prefix file0 <> Local Here file1 = Local prefix (file0 <> file1)++ Remote (URL { path = path0, ..}) <> Local Here path1 =+ Remote (URL { path = path0 <> path1, ..})++ Local prefix file0 <> Local Parent file1 =+ Local prefix (file0 <> parent <> file1)++ Remote (URL { path = path0, .. }) <> Local Parent path1 =+ Remote (URL { path = path0 <> parent <> path1, .. })++ import0 <> Remote (URL { headers = headers0, .. }) =+ Remote (URL { headers = headers1, .. })+ where+ importHashed0 = Import (ImportHashed Nothing import0) Code++ headers1 = fmap (fmap (importHashed0 <>)) headers0++ _ <> import1 =+ import1++instance Semigroup ImportHashed where+ ImportHashed _ importType0 <> ImportHashed hash importType1 =+ ImportHashed hash (importType0 <> importType1)++instance Semigroup Import where+ Import importHashed0 _ <> Import importHashed1 code =+ Import (importHashed0 <> importHashed1) code++parent :: File+parent = File { directory = Directory { components = [ ".." ] }, file = "" }
@@ -0,0 +1,36 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Applicative () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Instances.Functor ()+import Dhall.Syntax.Operations+import Dhall.Syntax.RecordField++import qualified Lens.Micro as Lens++instance Applicative (Expr s) where+ pure = Embed++ expression <*> k = case expression of+ Embed a -> a <$> k+ Let a b -> Let (adaptBinding a) (b <*> k)+ Note a b -> Note a (b <*> k)+ Record a -> Record $ adaptRecordField <$> a+ RecordLit a -> RecordLit $ adaptRecordField <$> a+ Lam cs a b -> Lam cs (adaptFunctionBinding a) (b <*> k)+ Field a b -> Field (a <*> k) b+ _ -> Lens.over unsafeSubExpressions (<*> k) expression+ where+ adaptRecordField (RecordField s0 e s1 s2) =+ RecordField s0 (e <*> k) s1 s2++ adaptBinding (Binding src0 c src1 d src2 e) =+ Binding src0 c src1 (fmap adaptBindingAnnotation d) src2 (e <*> k)++ adaptFunctionBinding (FunctionBinding src0 label src1 src2 type_) =+ FunctionBinding src0 label src1 src2 (type_ <*> k)++ adaptBindingAnnotation (src3, f) = (src3, f <*> k)
@@ -0,0 +1,44 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Bifunctor () where++import Data.Bifunctor (Bifunctor (..))+import Dhall.Syntax.Binding+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Instances.Functor ()+import Dhall.Syntax.Operations+import Dhall.Syntax.RecordField++import qualified Lens.Micro as Lens++instance Bifunctor Binding where+ first k (Binding src0 a src1 b src2 c) =+ Binding (fmap k src0) a (fmap k src1) (fmap adapt0 b) (fmap k src2) (first k c)+ where+ adapt0 (src3, d) = (fmap k src3, first k d)++ second = fmap++instance Bifunctor RecordField where+ first k (RecordField s0 value' s1 s2) =+ RecordField (k <$> s0) (first k value') (k <$> s1) (k <$> s2)+ second = fmap++instance Bifunctor FunctionBinding where+ first k (FunctionBinding src0 label src1 src2 type_) =+ FunctionBinding (k <$> src0) label (k <$> src1) (k <$> src2) (first k type_)++ second = fmap++instance Bifunctor Expr where+ first k (Note a b ) = Note (k a) (first k b)+ first _ (Embed a ) = Embed a+ first k (Let a b ) = Let (first k a) (first k b)+ first k (Record a ) = Record $ first k <$> a+ first k (RecordLit a) = RecordLit $ first k <$> a+ first k (Lam cs a b ) = Lam cs (first k a) (first k b)+ first k (Field a b ) = Field (first k a) (k <$> b)+ first k expression = Lens.over unsafeSubExpressions (first k) expression++ second = fmap
@@ -0,0 +1,28 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Data () where++import Data.Data (Data)+import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var++deriving instance Data Const+deriving instance Data Var+deriving instance (Data a, Data s) => Data (Binding s a)+deriving instance Data DhallDouble+deriving instance (Data a, Data s) => Data (Chunks s a)+deriving instance Data PreferAnnotation+deriving instance (Data a, Data s) => Data (RecordField s a)+deriving instance (Data a, Data s) => Data (FunctionBinding s a)+deriving instance Data s => Data (FieldSelection s)+deriving instance Data WithComponent+deriving instance (Data a, Data s) => Data (Expr s a)
@@ -0,0 +1,67 @@+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Eq () where++import Data.Bits (xor)+import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Import+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var++-- $setup+-- >>> import Data.Void (Void)+-- >>> import Dhall.Binary () -- For the orphan instance for `Serialise (Expr Void Import)`++deriving instance Eq Const+deriving instance Eq Var+deriving instance (Eq s, Eq a) => Eq (Binding s a)+deriving instance (Eq s, Eq a) => Eq (Chunks s a)+deriving instance Eq PreferAnnotation+deriving instance (Eq s, Eq a) => Eq (RecordField s a)+deriving instance (Eq s, Eq a) => Eq (FunctionBinding s a)+deriving instance Eq s => Eq (FieldSelection s)+deriving instance Eq WithComponent+-- | This instance encodes what the Dhall standard calls an \"exact match\"+-- between two expressions.+--+-- Note that+--+-- >>> nan = DhallDouble (0/0)+-- >>> DoubleLit nan == DoubleLit nan+-- True+deriving instance (Eq s, Eq a) => Eq (Expr s a)+deriving instance Eq Directory+deriving instance Eq File+deriving instance Eq FilePrefix+deriving instance Eq Scheme+deriving instance Eq URL+deriving instance Eq ImportType+deriving instance Eq ImportMode+deriving instance Eq ImportHashed+deriving instance Eq Import++-- | This instance satisfies all the customary 'Eq' laws except substitutivity.+--+-- In particular:+--+-- >>> nan = DhallDouble (0/0)+-- >>> nan == nan+-- True+--+-- This instance is also consistent with with the binary encoding of Dhall @Double@s:+--+-- >>> toBytes n = Dhall.Binary.encodeExpression (DoubleLit n :: Expr Void Import)+--+-- prop> \a b -> (a == b) == (toBytes a == toBytes b)+instance Eq DhallDouble where+ DhallDouble a == DhallDouble b+ | isNaN a && isNaN b = True+ | isNegativeZero a `xor` isNegativeZero b = False+ | otherwise = a == b
@@ -0,0 +1,20 @@+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Foldable () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types++deriving instance Foldable (Binding s)+deriving instance Foldable (Chunks s)+deriving instance Foldable (RecordField s)+deriving instance Foldable (FunctionBinding s)+deriving instance Foldable FieldSelection+deriving instance Foldable (Expr s)
@@ -0,0 +1,37 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Functor () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import {-# SOURCE #-} Dhall.Syntax.Operations (unsafeSubExpressions)+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types++import qualified Lens.Micro as Lens++deriving instance Functor (Binding s)+deriving instance Functor (Chunks s)+deriving instance Functor (RecordField s)+deriving instance Functor (FunctionBinding s)+deriving instance Functor FieldSelection++-- This instance is hand-written due to the fact that deriving+-- it does not give us an INLINABLE pragma. We annotate this fmap+-- implementation with this pragma below to allow GHC to, possibly,+-- inline the implementation for performance improvements.+instance Functor (Expr s) where+ fmap f (Embed a) = Embed (f a)+ fmap f (Let b e2) = Let (fmap f b) (fmap f e2)+ fmap f (Note s e1) = Note s (fmap f e1)+ fmap f (Record a) = Record $ fmap f <$> a+ fmap f (RecordLit a) = RecordLit $ fmap f <$> a+ fmap f (Lam cs fb e) = Lam cs (f <$> fb) (f <$> e)+ fmap f (Field a b) = Field (f <$> a) b+ fmap f expression = Lens.over unsafeSubExpressions (fmap f) expression+ {-# INLINABLE fmap #-}
@@ -0,0 +1,42 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Lift () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var+import Language.Haskell.TH.Syntax (Lift)++#if !MIN_VERSION_template_haskell(2,21,0)+import qualified Data.Fixed as Fixed+#endif+import qualified Data.Time as Time++#if !MIN_VERSION_time(1,14,0)+deriving instance Lift Time.Day+#endif+deriving instance Lift Time.TimeOfDay+deriving instance Lift Time.TimeZone+#if !MIN_VERSION_template_haskell(2,21,0)+deriving instance Lift (Fixed.Fixed a)+#endif+deriving instance Lift Const+deriving instance Lift Var+deriving instance (Lift s, Lift a) => Lift (Binding s a)+deriving instance Lift DhallDouble+deriving instance (Lift s, Lift a) => Lift (Chunks s a)+deriving instance Lift PreferAnnotation+deriving instance (Lift s, Lift a) => Lift (RecordField s a)+deriving instance (Lift s, Lift a) => Lift (FunctionBinding s a)+deriving instance Lift s => Lift (FieldSelection s)+deriving instance Lift WithComponent+deriving instance (Lift s, Lift a) => Lift (Expr s a)
@@ -0,0 +1,36 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Monad () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Instances.Applicative ()+import Dhall.Syntax.Operations+import Dhall.Syntax.RecordField++import qualified Lens.Micro as Lens++instance Monad (Expr s) where+ return = pure++ expression >>= k = case expression of+ Embed a -> k a+ Let a b -> Let (adaptBinding a) (b >>= k)+ Note a b -> Note a (b >>= k)+ Record a -> Record $ bindRecordKeyValues <$> a+ RecordLit a -> RecordLit $ bindRecordKeyValues <$> a+ Lam cs a b -> Lam cs (adaptFunctionBinding a) (b >>= k)+ Field a b -> Field (a >>= k) b+ _ -> Lens.over unsafeSubExpressions (>>= k) expression+ where+ bindRecordKeyValues (RecordField s0 e s1 s2) =+ RecordField s0 (e >>= k) s1 s2++ adaptBinding (Binding src0 c src1 d src2 e) =+ Binding src0 c src1 (fmap adaptBindingAnnotation d) src2 (e >>= k)++ adaptFunctionBinding (FunctionBinding src0 label src1 src2 type_) =+ FunctionBinding src0 label src1 src2 (type_ >>= k)++ adaptBindingAnnotation (src3, f) = (src3, f >>= k)
@@ -0,0 +1,35 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.NFData () where++import Control.DeepSeq (NFData)+import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Import+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var++instance NFData Const+instance NFData Var+instance (NFData s, NFData a) => NFData (Binding s a)+instance NFData DhallDouble+instance (NFData s, NFData a) => NFData (Chunks s a)+instance NFData PreferAnnotation+instance (NFData s, NFData a) => NFData (RecordField s a)+instance (NFData s, NFData a) => NFData (FunctionBinding s a)+instance NFData s => NFData (FieldSelection s)+instance NFData WithComponent+instance (NFData s, NFData a) => NFData (Expr s a)+instance NFData Directory+instance NFData File+instance NFData FilePrefix+instance NFData Scheme+instance NFData URL+instance NFData ImportType+instance NFData ImportMode+instance NFData ImportHashed+instance NFData Import
@@ -0,0 +1,45 @@+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Ord () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Import+import Dhall.Syntax.Instances.Eq ()+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var++deriving instance Ord Const+deriving instance Ord Var+deriving instance (Ord s, Ord a) => Ord (Binding s a)+deriving instance (Ord s, Ord a) => Ord (Chunks s a)+deriving instance Ord PreferAnnotation+deriving instance (Ord s, Ord a) => Ord (RecordField s a)+deriving instance (Ord s, Ord a) => Ord (FunctionBinding s a)+deriving instance Ord s => Ord (FieldSelection s)+deriving instance Ord WithComponent+-- | Note that this 'Ord' instance inherits `DhallDouble`'s defects.+deriving instance (Ord s, Ord a) => Ord (Expr s a)+deriving instance Ord Directory+deriving instance Ord File+deriving instance Ord FilePrefix+deriving instance Ord Scheme+deriving instance Ord URL+deriving instance Ord ImportType+deriving instance Ord ImportMode+deriving instance Ord ImportHashed+deriving instance Ord Import++-- | This instance relies on the 'Eq' instance for 'DhallDouble' but cannot+-- satisfy the customary 'Ord' laws when @NaN@ is involved.+instance Ord DhallDouble where+ compare a@(DhallDouble a') b@(DhallDouble b') =+ if a == b+ then EQ+ else compare a' b'
@@ -0,0 +1,135 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Pretty+ ( pathCharacter+ ) where++import Data.Text (Text)+import {-# SOURCE #-} Dhall.Pretty.Internal+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.Import+import Dhall.Syntax.Var+import Prettyprinter (Doc, Pretty)++import qualified Data.Text+import qualified Network.URI as URI+import qualified Prettyprinter as Pretty++instance Pretty Const where+ pretty = Pretty.unAnnotate . prettyConst++instance Pretty Var where+ pretty = Pretty.unAnnotate . prettyVar++-- | Generates a syntactically valid Dhall program+instance Pretty a => Pretty (Expr s a) where+ pretty = Pretty.unAnnotate . prettyExpr++instance Pretty Directory where+ pretty (Directory {..}) = foldMap prettyPathComponent (reverse components)++prettyPathComponent :: Text -> Doc ann+prettyPathComponent text+ | Data.Text.all pathCharacter text =+ "/" <> Pretty.pretty text+ | otherwise =+ "/\"" <> Pretty.pretty text <> "\""++instance Pretty File where+ pretty (File {..}) =+ Pretty.pretty directory+ <> prettyPathComponent file++instance Pretty FilePrefix where+ pretty Absolute = ""+ pretty Here = "."+ pretty Parent = ".."+ pretty Home = "~"++instance Pretty URL where+ pretty (URL {..}) =+ schemeDoc+ <> "://"+ <> Pretty.pretty authority+ <> pathDoc+ <> queryDoc+ <> foldMap prettyHeaders headers+ where+ prettyHeaders h =+ " using (" <> Pretty.unAnnotate (Pretty.pretty h) <> ")"++ File {..} = path++ Directory {..} = directory++ pathDoc =+ foldMap prettyURIComponent (reverse components)+ <> prettyURIComponent file++ schemeDoc = case scheme of+ HTTP -> "http"+ HTTPS -> "https"++ queryDoc = case query of+ Nothing -> ""+ Just q -> "?" <> Pretty.pretty q++prettyURIComponent :: Text -> Doc ann+prettyURIComponent text =+ Pretty.pretty $ URI.normalizeCase $ URI.normalizeEscape $ "/" <> Data.Text.unpack text++instance Pretty ImportType where+ pretty (Local prefix file) =+ Pretty.pretty prefix <> Pretty.pretty file++ pretty (Remote url) = Pretty.pretty url++ pretty (Env env) = "env:" <> prettyEnvironmentVariable env++ pretty Missing = "missing"++instance Pretty ImportHashed where+ pretty (ImportHashed Nothing p) =+ Pretty.pretty p+ pretty (ImportHashed (Just h) p) =+ Pretty.group (Pretty.flatAlt long short)+ where+ long =+ Pretty.align+ ( Pretty.pretty p <> Pretty.hardline+ <> " sha256:" <> Pretty.pretty (show h)+ )++ short = Pretty.pretty p <> " sha256:" <> Pretty.pretty (show h)++instance Pretty Import where+ pretty (Import {..}) = Pretty.pretty importHashed <> Pretty.pretty suffix+ where+ suffix :: Text+ suffix = case importMode of+ RawText -> " as Text"+ Location -> " as Location"+ Code -> ""+ RawBytes -> " as Bytes"++{-| Returns `True` if the given `Char` is valid within an unquoted path+ component++ This is exported for reuse within the @"Dhall.Parser.Token"@ module+-}+pathCharacter :: Char -> Bool+pathCharacter c =+ '\x21' == c+ || ('\x24' <= c && c <= '\x27')+ || ('\x2A' <= c && c <= '\x2B')+ || ('\x2D' <= c && c <= '\x2E')+ || ('\x30' <= c && c <= '\x3B')+ || c == '\x3D'+ || ('\x40' <= c && c <= '\x5A')+ || ('\x5E' <= c && c <= '\x7A')+ || c == '\x7C'+ || c == '\x7E'
@@ -0,0 +1,8 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Pretty where++import Dhall.Syntax.Expr (Expr)+import Prettyprinter (Pretty)++instance Pretty a => Pretty (Expr s a)
@@ -0,0 +1,36 @@+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Show () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Const+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Import+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types+import Dhall.Syntax.Var++deriving instance Show Const+deriving instance Show Var+deriving instance (Show s, Show a) => Show (Binding s a)+deriving instance Show DhallDouble+deriving instance (Show s, Show a) => Show (Chunks s a)+deriving instance Show PreferAnnotation+deriving instance (Show s, Show a) => Show (RecordField s a)+deriving instance (Show s, Show a) => Show (FunctionBinding s a)+deriving instance Show s => Show (FieldSelection s)+deriving instance Show WithComponent+deriving instance (Show s, Show a) => Show (Expr s a)+deriving instance Show Directory+deriving instance Show File+deriving instance Show FilePrefix+deriving instance Show Scheme+deriving instance Show URL+deriving instance Show ImportType+deriving instance Show ImportMode+deriving instance Show ImportHashed+deriving instance Show Import
@@ -0,0 +1,22 @@+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Dhall.Syntax.Instances.Traversable () where++import Dhall.Syntax.Binding+import Dhall.Syntax.Chunks+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.Instances.Foldable ()+import Dhall.Syntax.Instances.Functor ()+import Dhall.Syntax.RecordField+import Dhall.Syntax.Types++deriving instance Traversable (Binding s)+deriving instance Traversable (Chunks s)+deriving instance Traversable (RecordField s)+deriving instance Traversable (FunctionBinding s)+deriving instance Traversable FieldSelection+deriving instance Traversable (Expr s)
@@ -0,0 +1,62 @@+{-# LANGUAGE LambdaCase #-}++{- | Instead of converting explicitly between 'Expr's and 'MultiLet', it might+be nicer to use a pattern synonym:++> pattern MultiLet' :: NonEmpty (Binding s a) -> Expr s a -> Expr s a+> pattern MultiLet' as b <- (multiLetFromExpr -> Just (MultiLet as b)) where+> MultiLet' as b = wrapInLets as b+>+> multiLetFromExpr :: Expr s a -> Maybe (MultiLet s a)+> multiLetFromExpr = \case+> Let x mA a b -> Just (multiLet x mA a b)+> _ -> Nothing++This works in principle, but GHC as of v8.8.1 doesn't handle it well:+https://gitlab.haskell.org/ghc/ghc/issues/17096++This should be fixed by GHC-8.10, so it might be worth revisiting then.+-}++module Dhall.Syntax.MultiLet+ ( MultiLet(..)+ , multiLet+ , wrapInLets+ ) where++import Data.List.NonEmpty (NonEmpty (..))+import Dhall.Syntax.Binding (Binding)+import Dhall.Syntax.Expr (Expr (..))++import qualified Data.List.NonEmpty as NonEmpty++{-| Generate a 'MultiLet' from the contents of a 'Let'.++ In the resulting @'MultiLet' bs e@, @e@ is guaranteed not to be a 'Let',+ but it might be a @('Note' … ('Let' …))@.++ Given parser output, 'multiLet' consolidates @let@s that formed a+ let-block in the original source.+-}+multiLet :: Binding s a -> Expr s a -> MultiLet s a+multiLet b0 = \case+ Let b1 e1 ->+ let MultiLet bs e = multiLet b1 e1+ in MultiLet (NonEmpty.cons b0 bs) e+ e -> MultiLet (b0 :| []) e++{-| Wrap let-'Binding's around an 'Expr'.++'wrapInLets' can be understood as an inverse for 'multiLet':++> let MultiLet bs e1 = multiLet b e0+>+> wrapInLets bs e1 == Let b e0+-}+wrapInLets :: Foldable f => f (Binding s a) -> Expr s a -> Expr s a+wrapInLets bs e = foldr Let e bs++{-| This type represents 1 or more nested `Let` bindings that have been+ coalesced together for ease of manipulation+-}+data MultiLet s a = MultiLet (NonEmpty (Binding s a)) (Expr s a)
@@ -0,0 +1,394 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}++module Dhall.Syntax.Operations+ ( -- * Optics+ subExpressions+ , subExpressionsWith+ , unsafeSubExpressions++ -- * Handling 'Note's+ , denote+ , renote+ , shallowDenote++ -- * Reserved identifiers+ , reservedIdentifiers+ , reservedKeywords++ -- * Utilities+ , internalError+ -- `shift` should really be in `Dhall.Normalize`, but it's here to avoid a+ -- module cycle+ , shift+ ) where++import Data.HashSet (HashSet)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Syntax.Binding (Binding (..), bindingExprs)+import Dhall.Syntax.Chunks (chunkExprs)+import Dhall.Syntax.Expr+import Dhall.Syntax.FunctionBinding+import Dhall.Syntax.RecordField (RecordField (..), recordFieldExprs)+import Dhall.Syntax.Types+import Dhall.Syntax.Var+import Unsafe.Coerce (unsafeCoerce)++import qualified Data.HashSet+import qualified Data.Text+import qualified Lens.Micro as Lens+++-- | A traversal over the immediate sub-expressions of an expression.+subExpressions+ :: Applicative f => (Expr s a -> f (Expr s a)) -> Expr s a -> f (Expr s a)+subExpressions = subExpressionsWith (pure . Embed)+{-# INLINABLE subExpressions #-}++{-| A traversal over the immediate sub-expressions of an expression which+ allows mapping embedded values+-}+subExpressionsWith+ :: Applicative f => (a -> f (Expr s b)) -> (Expr s a -> f (Expr s b)) -> Expr s a -> f (Expr s b)+subExpressionsWith h _ (Embed a) = h a+subExpressionsWith _ f (Note a b) = Note a <$> f b+subExpressionsWith _ f (Let a b) = Let <$> bindingExprs f a <*> f b+subExpressionsWith _ f (Record a) = Record <$> traverse (recordFieldExprs f) a+subExpressionsWith _ f (RecordLit a) = RecordLit <$> traverse (recordFieldExprs f) a+subExpressionsWith _ f (Lam cs fb e) = Lam cs <$> functionBindingExprs f fb <*> f e+subExpressionsWith _ f (Field a b) = Field <$> f a <*> pure b+subExpressionsWith _ f expression = unsafeSubExpressions f expression+{-# INLINABLE subExpressionsWith #-}++{-| An internal utility used to implement transformations that require changing+ one of the type variables of the `Expr` type++ This utility only works because the implementation is partial, not+ handling the `Let`, `Note`, or `Embed` cases, which need to be handled by+ the caller.+-}+unsafeSubExpressions+ :: Applicative f => (Expr s a -> f (Expr t b)) -> Expr s a -> f (Expr t b)+unsafeSubExpressions _ (Const c) = pure (Const c)+unsafeSubExpressions _ (Var v) = pure (Var v)+unsafeSubExpressions f (Pi cs a b c) = Pi cs a <$> f b <*> f c+unsafeSubExpressions f (App a b) = App <$> f a <*> f b+unsafeSubExpressions f (Annot a b) = Annot <$> f a <*> f b+unsafeSubExpressions _ Bool = pure Bool+unsafeSubExpressions _ (BoolLit b) = pure (BoolLit b)+unsafeSubExpressions f (BoolAnd a b) = BoolAnd <$> f a <*> f b+unsafeSubExpressions f (BoolOr a b) = BoolOr <$> f a <*> f b+unsafeSubExpressions f (BoolEQ a b) = BoolEQ <$> f a <*> f b+unsafeSubExpressions f (BoolNE a b) = BoolNE <$> f a <*> f b+unsafeSubExpressions f (BoolIf a b c) = BoolIf <$> f a <*> f b <*> f c+unsafeSubExpressions _ Bytes = pure Bytes+unsafeSubExpressions _ (BytesLit a) = pure (BytesLit a)+unsafeSubExpressions _ Natural = pure Natural+unsafeSubExpressions _ (NaturalLit n) = pure (NaturalLit n)+unsafeSubExpressions _ NaturalFold = pure NaturalFold+unsafeSubExpressions _ NaturalBuild = pure NaturalBuild+unsafeSubExpressions _ NaturalIsZero = pure NaturalIsZero+unsafeSubExpressions _ NaturalEven = pure NaturalEven+unsafeSubExpressions _ NaturalOdd = pure NaturalOdd+unsafeSubExpressions _ NaturalToInteger = pure NaturalToInteger+unsafeSubExpressions _ NaturalShow = pure NaturalShow+unsafeSubExpressions _ NaturalSubtract = pure NaturalSubtract+unsafeSubExpressions f (NaturalPlus a b) = NaturalPlus <$> f a <*> f b+unsafeSubExpressions f (NaturalTimes a b) = NaturalTimes <$> f a <*> f b+unsafeSubExpressions _ Integer = pure Integer+unsafeSubExpressions _ (IntegerLit n) = pure (IntegerLit n)+unsafeSubExpressions _ IntegerClamp = pure IntegerClamp+unsafeSubExpressions _ IntegerNegate = pure IntegerNegate+unsafeSubExpressions _ IntegerShow = pure IntegerShow+unsafeSubExpressions _ IntegerToDouble = pure IntegerToDouble+unsafeSubExpressions _ Double = pure Double+unsafeSubExpressions _ (DoubleLit n) = pure (DoubleLit n)+unsafeSubExpressions _ DoubleShow = pure DoubleShow+unsafeSubExpressions _ Text = pure Text+unsafeSubExpressions f (TextLit chunks) = TextLit <$> chunkExprs f chunks+unsafeSubExpressions f (TextAppend a b) = TextAppend <$> f a <*> f b+unsafeSubExpressions _ TextReplace = pure TextReplace+unsafeSubExpressions _ TextShow = pure TextShow+unsafeSubExpressions _ Date = pure Date+unsafeSubExpressions _ (DateLiteral a) = pure (DateLiteral a)+unsafeSubExpressions _ DateShow = pure DateShow+unsafeSubExpressions _ Time = pure Time+unsafeSubExpressions _ (TimeLiteral a b) = pure (TimeLiteral a b)+unsafeSubExpressions _ TimeShow = pure TimeShow+unsafeSubExpressions _ TimeZone = pure TimeZone+unsafeSubExpressions _ (TimeZoneLiteral a) = pure (TimeZoneLiteral a)+unsafeSubExpressions _ TimeZoneShow = pure TimeZoneShow+unsafeSubExpressions _ List = pure List+unsafeSubExpressions f (ListLit a b) = ListLit <$> traverse f a <*> traverse f b+unsafeSubExpressions f (ListAppend a b) = ListAppend <$> f a <*> f b+unsafeSubExpressions _ ListBuild = pure ListBuild+unsafeSubExpressions _ ListFold = pure ListFold+unsafeSubExpressions _ ListLength = pure ListLength+unsafeSubExpressions _ ListHead = pure ListHead+unsafeSubExpressions _ ListLast = pure ListLast+unsafeSubExpressions _ ListIndexed = pure ListIndexed+unsafeSubExpressions _ ListReverse = pure ListReverse+unsafeSubExpressions _ Optional = pure Optional+unsafeSubExpressions f (Some a) = Some <$> f a+unsafeSubExpressions _ None = pure None+unsafeSubExpressions f (Union a) = Union <$> traverse (traverse f) a+unsafeSubExpressions f (Combine cs a b c) = Combine cs a <$> f b <*> f c+unsafeSubExpressions f (CombineTypes cs a b) = CombineTypes cs <$> f a <*> f b+unsafeSubExpressions f (Prefer cs a b c) = Prefer cs <$> pure a <*> f b <*> f c+unsafeSubExpressions f (RecordCompletion a b) = RecordCompletion <$> f a <*> f b+unsafeSubExpressions f (Merge a b t) = Merge <$> f a <*> f b <*> traverse f t+unsafeSubExpressions f (ToMap a t) = ToMap <$> f a <*> traverse f t+unsafeSubExpressions f (ShowConstructor a) = ShowConstructor <$> f a+unsafeSubExpressions f (Project a b) = Project <$> f a <*> traverse f b+unsafeSubExpressions f (Assert a) = Assert <$> f a+unsafeSubExpressions f (Equivalent cs a b) = Equivalent cs <$> f a <*> f b+unsafeSubExpressions f (With a b c) = With <$> f a <*> pure b <*> f c+unsafeSubExpressions f (ImportAlt l r) = ImportAlt <$> f l <*> f r+unsafeSubExpressions _ (Let {}) = unhandledConstructor "Let"+unsafeSubExpressions _ (Note {}) = unhandledConstructor "Note"+unsafeSubExpressions _ (Embed {}) = unhandledConstructor "Embed"+unsafeSubExpressions _ (Record {}) = unhandledConstructor "Record"+unsafeSubExpressions _ (RecordLit {}) = unhandledConstructor "RecordLit"+unsafeSubExpressions _ (Lam {}) = unhandledConstructor "Lam"+unsafeSubExpressions _ (Field {}) = unhandledConstructor "Field"+{-# INLINABLE unsafeSubExpressions #-}++unhandledConstructor :: Text -> a+unhandledConstructor constructor =+ internalError+ ( "Dhall.Syntax.unsafeSubExpressions: Unhandled "+ <> constructor+ <> " construtor"+ )++-- | Remove all `Note` constructors from an `Expr` (i.e. de-`Note`)+--+-- This also remove CharacterSet annotations.+denote :: Expr s a -> Expr t a+denote = \case+ Note _ b -> denote b+ Let a b -> Let (denoteBinding a) (denote b)+ Embed a -> Embed a+ Combine _ _ b c -> Combine Nothing Nothing (denote b) (denote c)+ CombineTypes _ b c -> CombineTypes Nothing (denote b) (denote c)+ Prefer _ a b c -> Lens.over unsafeSubExpressions denote $ Prefer Nothing a b c+ Record a -> Record $ denoteRecordField <$> a+ RecordLit a -> RecordLit $ denoteRecordField <$> a+ Lam _ a b -> Lam Nothing (denoteFunctionBinding a) (denote b)+ Pi _ t a b -> Pi Nothing t (denote a) (denote b)+ Field a (FieldSelection _ b _) -> Field (denote a) (FieldSelection Nothing b Nothing)+ Equivalent _ a b -> Equivalent Nothing (denote a) (denote b)+ expression -> Lens.over unsafeSubExpressions denote expression+ where+ denoteRecordField (RecordField _ e _ _) = RecordField Nothing (denote e) Nothing Nothing++ denoteBinding (Binding _ c _ d _ e) =+ Binding Nothing c Nothing (fmap denoteBindingAnnotation d) Nothing (denote e)++ denoteBindingAnnotation (_, f) = (Nothing, denote f)++ denoteFunctionBinding (FunctionBinding _ l _ _ t) =+ FunctionBinding Nothing l Nothing Nothing (denote t)++-- | The \"opposite\" of `denote`, like @first absurd@ but faster+renote :: Expr Void a -> Expr s a+renote = unsafeCoerce+{-# INLINE renote #-}++{-| Remove any outermost `Note` constructors++ This is typically used when you want to get the outermost non-`Note`+ constructor without removing internal `Note` constructors+-}+shallowDenote :: Expr s a -> Expr s a+shallowDenote (Note _ e) = shallowDenote e+shallowDenote e = e++-- | The set of reserved keywords according to the @keyword@ rule in the grammar+reservedKeywords :: HashSet Text+reservedKeywords =+ Data.HashSet.fromList+ [ "if"+ , "then"+ , "else"+ , "let"+ , "in"+ , "using"+ , "missing"+ , "as"+ , "Infinity"+ , "NaN"+ , "merge"+ , "Some"+ , "toMap"+ , "assert"+ , "forall"+ , "with"+ ]++-- | The set of reserved identifiers for the Dhall language+-- | Contains also all keywords from "reservedKeywords"+reservedIdentifiers :: HashSet Text+reservedIdentifiers = reservedKeywords <>+ Data.HashSet.fromList+ [ -- Builtins according to the `builtin` rule in the grammar+ "Natural/fold"+ , "Natural/build"+ , "Natural/isZero"+ , "Natural/even"+ , "Natural/odd"+ , "Natural/toInteger"+ , "Natural/show"+ , "Natural/subtract"+ , "Integer"+ , "Integer/clamp"+ , "Integer/negate"+ , "Integer/show"+ , "Integer/toDouble"+ , "Integer/show"+ , "Natural/subtract"+ , "Double/show"+ , "List/build"+ , "List/fold"+ , "List/length"+ , "List/head"+ , "List/last"+ , "List/indexed"+ , "List/reverse"+ , "Text/replace"+ , "Text/show"+ , "Date/show"+ , "Time/show"+ , "TimeZone/show"+ , "Bool"+ , "Bytes"+ , "True"+ , "False"+ , "Optional"+ , "None"+ , "Natural"+ , "Integer"+ , "Double"+ , "Text"+ , "Date"+ , "Time"+ , "TimeZone"+ , "List"+ , "Type"+ , "Kind"+ , "Sort"+ ]++{-| `shift` is used by both normalization and type-checking to avoid variable+ capture by shifting variable indices++ For example, suppose that you were to normalize the following expression:++> λ(a : Type) → λ(x : a) → (λ(y : a) → λ(x : a) → y) x++ If you were to substitute @y@ with @x@ without shifting any variable+ indices, then you would get the following incorrect result:++> λ(a : Type) → λ(x : a) → λ(x : a) → x -- Incorrect normalized form++ In order to substitute @x@ in place of @y@ we need to `shift` @x@ by @1@ in+ order to avoid being misinterpreted as the @x@ bound by the innermost+ lambda. If we perform that `shift` then we get the correct result:++> λ(a : Type) → λ(x : a) → λ(x : a) → x@1++ As a more worked example, suppose that you were to normalize the following+ expression:++> λ(a : Type)+> → λ(f : a → a → a)+> → λ(x : a)+> → λ(x : a)+> → (λ(x : a) → f x x@1) x@1++ The correct normalized result would be:++> λ(a : Type)+> → λ(f : a → a → a)+> → λ(x : a)+> → λ(x : a)+> → f x@1 x++ The above example illustrates how we need to both increase and decrease+ variable indices as part of substitution:++ * We need to increase the index of the outer @x\@1@ to @x\@2@ before we+ substitute it into the body of the innermost lambda expression in order+ to avoid variable capture. This substitution changes the body of the+ lambda expression to @(f x\@2 x\@1)@++ * We then remove the innermost lambda and therefore decrease the indices of+ both @x@s in @(f x\@2 x\@1)@ to @(f x\@1 x)@ in order to reflect that one+ less @x@ variable is now bound within that scope++ Formally, @(shift d (V x n) e)@ modifies the expression @e@ by adding @d@ to+ the indices of all variables named @x@ whose indices are greater than+ @(n + m)@, where @m@ is the number of bound variables of the same name+ within that scope++ In practice, @d@ is always @1@ or @-1@ because we either:++ * increment variables by @1@ to avoid variable capture during substitution+ * decrement variables by @1@ when deleting lambdas after substitution++ @n@ starts off at @0@ when substitution begins and increments every time we+ descend into a lambda or let expression that binds a variable of the same+ name in order to avoid shifting the bound variables by mistake.+-}+shift :: Int -> Var -> Expr s a -> Expr s a+shift d (V x n) (Var (V x' n')) = Var (V x' n'')+ where+ n'' = if x == x' && n <= n' then n' + d else n'+shift d (V x n) (Lam cs (FunctionBinding src0 x' src1 src2 _A) b) =+ Lam cs (FunctionBinding src0 x' src1 src2 _A') b'+ where+ _A' = shift d (V x n ) _A+ b' = shift d (V x n') b+ where+ n' = if x == x' then n + 1 else n+shift d (V x n) (Pi cs x' _A _B) = Pi cs x' _A' _B'+ where+ _A' = shift d (V x n ) _A+ _B' = shift d (V x n') _B+ where+ n' = if x == x' then n + 1 else n+shift d (V x n) (Let (Binding src0 f src1 mt src2 r) e) =+ Let (Binding src0 f src1 mt' src2 r') e'+ where+ e' = shift d (V x n') e+ where+ n' = if x == f then n + 1 else n++ mt' = fmap (fmap (shift d (V x n))) mt+ r' = shift d (V x n) r+shift d v expression = Lens.over subExpressions (shift d v) expression++_ERROR :: String+_ERROR = "\ESC[1;31mError\ESC[0m"++{-| Utility function used to throw internal errors that should never happen+ (in theory) but that are not enforced by the type system+-}+internalError :: Data.Text.Text -> forall b . b+internalError text = error (unlines+ [ _ERROR <> ": Compiler bug "+ , " "+ , "Explanation: This error message means that there is a bug in the Dhall compiler."+ , "You didn't do anything wrong, but if you would like to see this problem fixed "+ , "then you should report the bug at: "+ , " "+ , "https://github.com/dhall-lang/dhall-haskell/issues "+ , " "+ , "Please include the following text in your bug report: "+ , " "+ , "``` "+ , Data.Text.unpack text <> " "+ , "``` "+ ] )
@@ -0,0 +1,5 @@+module Dhall.Syntax.Operations where++import Dhall.Syntax.Expr (Expr)++unsafeSubExpressions :: Applicative f => (Expr s a -> f (Expr t b)) -> Expr s a -> f (Expr t b)
@@ -0,0 +1,93 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.RecordField+ ( RecordField(..)+ , makeRecordField++ -- * Optics+ , recordFieldExprs+ ) where++import {-# SOURCE #-} Dhall.Syntax.Expr (Expr)+import GHC.Generics (Generic)++-- | Record the field of a record-type and record-literal expression.+-- The reason why we use the same ADT for both of them is because they store+-- the same information.+--+-- For example,+--+-- > { {- A -} x {- B -} : {- C -} T }+--+-- ... or+--+-- > { {- A -} x {- B -} = {- C -} T }+--+-- will be instantiated as follows:+--+-- * @recordFieldSrc0@ corresponds to the @A@ comment.+-- * @recordFieldValue@ is @"T"@+-- * @recordFieldSrc1@ corresponds to the @B@ comment.+-- * @recordFieldSrc2@ corresponds to the @C@ comment.+--+-- Although the @A@ comment isn't annotating the @"T"@ Record Field,+-- this is the best place to keep these comments.+--+-- Note that @recordFieldSrc2@ is always 'Nothing' when the 'RecordField' is for+-- a punned entry, because there is no @=@ sign. For example,+--+-- > { {- A -} x {- B -} }+--+-- will be instantiated as follows:+--+-- * @recordFieldSrc0@ corresponds to the @A@ comment.+-- * @recordFieldValue@ corresponds to @(Var "x")@+-- * @recordFieldSrc1@ corresponds to the @B@ comment.+-- * @recordFieldSrc2@ will be 'Nothing'+--+-- The labels involved in a record using dot-syntax like in this example:+--+-- > { {- A -} a {- B -} . {- C -} b {- D -} . {- E -} c {- F -} = {- G -} e }+--+-- will be instantiated as follows:+--+-- * For both the @a@ and @b@ field, @recordfieldSrc2@ is 'Nothing'+-- * For the @a@ field:+-- * @recordFieldSrc0@ corresponds to the @A@ comment+-- * @recordFieldSrc1@ corresponds to the @B@ comment+-- * For the @b@ field:+-- * @recordFieldSrc0@ corresponds to the @C@ comment+-- * @recordFieldSrc1@ corresponds to the @D@ comment+-- * For the @c@ field:+-- * @recordFieldSrc0@ corresponds to the @E@ comment+-- * @recordFieldSrc1@ corresponds to the @F@ comment+-- * @recordFieldSrc2@ corresponds to the @G@ comment+--+-- That is, for every label except the last one the semantics of+-- @recordFieldSrc0@ and @recordFieldSrc1@ are the same from a regular record+-- label but @recordFieldSrc2@ is always 'Nothing'. For the last keyword, all+-- srcs are 'Just'+data RecordField s a = RecordField+ { recordFieldSrc0 :: Maybe s+ , recordFieldValue :: Expr s a+ , recordFieldSrc1 :: Maybe s+ , recordFieldSrc2 :: Maybe s+ } deriving Generic++-- | Construct a 'RecordField' with no src information+makeRecordField :: Expr s a -> RecordField s a+makeRecordField e = RecordField Nothing e Nothing Nothing++{-| Traverse over the immediate 'Expr' children in a 'RecordField'.+-}+recordFieldExprs+ :: Applicative f+ => (Expr s a -> f (Expr s b))+ -> RecordField s a -> f (RecordField s b)+recordFieldExprs f (RecordField s0 e s1 s2) =+ RecordField+ <$> pure s0+ <*> f e+ <*> pure s1+ <*> pure s2+{-# INLINABLE recordFieldExprs #-}
@@ -0,0 +1,55 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.Types+ ( DhallDouble(..)+ , PreferAnnotation(..)+ , FieldSelection(..)+ , makeFieldSelection+ , WithComponent(..)+ ) where++import Data.Text (Text)+import GHC.Generics (Generic)++-- | This wrapper around 'Prelude.Double' exists for its 'Eq' instance which is+-- defined via the binary encoding of Dhall @Double@s.+newtype DhallDouble = DhallDouble { getDhallDouble :: Double }+ deriving Generic++-- | Used to record the origin of a @//@ operator (i.e. from source code or a+-- product of desugaring)+data PreferAnnotation+ = PreferFromSource+ | PreferFromCompletion+ deriving Generic++-- | Record the field on a selector-expression+--+-- For example,+--+-- > e . {- A -} x {- B -}+--+-- … will be instantiated as follows:+--+-- * @fieldSelectionSrc0@ corresponds to the @A@ comment+-- * @fieldSelectionLabel@ corresponds to @x@+-- * @fieldSelectionSrc1@ corresponds to the @B@ comment+--+-- Given our limitation that not all expressions recover their whitespaces, the+-- purpose of @fieldSelectionSrc1@ is to save the 'Text.Megaparsec.SourcePos'+-- where the @fieldSelectionLabel@ ends, but we /still/ use a+-- 'Maybe Dhall.Src.Src' (@s = 'Dhall.Src.Src'@) to be consistent with similar+-- data types such as 'Dhall.Syntax.Binding.Binding', for example.+data FieldSelection s = FieldSelection+ { fieldSelectionSrc0 :: Maybe s+ , fieldSelectionLabel :: !Text+ , fieldSelectionSrc1 :: Maybe s+ } deriving Generic++-- | Smart constructor for 'FieldSelection' with no src information+makeFieldSelection :: Text -> FieldSelection s+makeFieldSelection t = FieldSelection Nothing t Nothing++-- | A path component for a @with@ expression+data WithComponent = WithLabel Text | WithQuestion+ deriving Generic
@@ -0,0 +1,14 @@+{-# LANGUAGE StandaloneKindSignatures #-}++module Dhall.Syntax.Types where++import Data.Kind (Type)++data DhallDouble++data PreferAnnotation++type FieldSelection :: Type -> Type+data FieldSelection s++data WithComponent
@@ -0,0 +1,47 @@+{-# LANGUAGE DeriveGeneric #-}++module Dhall.Syntax.Var+ ( Var(..)+ ) where++import Data.String (IsString (..))+import Data.Text (Text)+import GHC.Generics (Generic)++{-| Label for a bound variable++ The `Data.Text.Text` field is the variable's name (i.e. \"@x@\").++ The `Int` field disambiguates variables with the same name if there are+ multiple bound variables of the same name in scope. Zero refers to the+ nearest bound variable and the index increases by one for each bound+ variable of the same name going outward. The following diagram may help:++> ┌──refers to──┐+> │ │+> v │+> λ(x : Type) → λ(y : Type) → λ(x : Type) → x@0+>+> ┌─────────────────refers to─────────────────┐+> │ │+> v │+> λ(x : Type) → λ(y : Type) → λ(x : Type) → x@1++ This `Int` behaves like a De Bruijn index in the special case where all+ variables have the same name.++ You can optionally omit the index if it is @0@:++> ┌─refers to─┐+> │ │+> v │+> λ(x : Type) → λ(y : Type) → λ(x : Type) → x++ Zero indices are omitted when pretty-printing @Var@s and non-zero indices+ appear as a numeric suffix.+-}+data Var = V Text !Int+ deriving Generic++instance IsString Var where+ fromString str = V (fromString str) 0
@@ -1,16 +1,83 @@-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-} -{-| This module provides `staticDhallExpression` which can be used to resolve- all of an expression’s imports at compile time, allowing one to reference- Dhall expressions from Haskell without having a runtime dependency on the- location of Dhall files.+-- | Template Haskell utilities+module Dhall.TH+ ( -- * Embedding Dhall in Haskell+ staticDhallExpression+ , dhall+ -- * Generating Haskell from Dhall expressions+ , makeHaskellTypeFromUnion+ , makeHaskellTypes+ , makeHaskellTypesWith+ , HaskellType(..)+ , GenerateOptions(..)+ , defaultGenerateOptions+ ) where +import Control.Monad (forM_)+import Data.Bifunctor (first)+import Data.Text (Text)+import Dhall (FromDhall, ToDhall)+import Dhall.Syntax (Expr (..), FunctionBinding (..), Var (..))+import GHC.Generics (Generic)+import Language.Haskell.TH.Quote (QuasiQuoter (..), dataToExpQ)+import Lens.Micro.Extras (view)+import Prettyprinter (Pretty)++import Language.Haskell.TH.Syntax+ ( Bang (..)+ , Body (..)+ , Con (..)+ , Dec (..)+ , Exp (..)+ , Match (..)+ , Pat (..)+ , Q+ , SourceStrictness (..)+ , SourceUnpackedness (..)+ , Type (..)+ )++import Language.Haskell.TH.Syntax (DerivClause (..), DerivStrategy (..))++import qualified Data.List as List+import qualified Data.Map as Map+import qualified Data.Set as Set+import qualified Data.Text as Text+import qualified Data.Time as Time+import qualified Data.Typeable as Typeable+import qualified Dhall+import qualified Dhall.Core as Core+import qualified Dhall.Import+import qualified Dhall.Map+import qualified Dhall.Pretty+import qualified Dhall.Util+import qualified GHC.IO.Encoding+import qualified Language.Haskell.TH.Syntax as TH+import qualified Numeric.Natural+import qualified Prettyprinter.Render.String as Pretty+import qualified System.IO+++{-| This fully resolves, type checks, and normalizes the expression, so the+ resulting AST is self-contained.++ This can be used to resolve all of an expression’s imports at compile time,+ allowing one to reference Dhall expressions from Haskell without having a+ runtime dependency on the location of Dhall files.+ For example, given a file @".\/Some\/Type.dhall"@ containing > < This : Natural | Other : ../Other/Type.dhall > - ... rather than duplicating the AST manually in a Haskell `Type`, you can- do:+ ... rather than duplicating the AST manually in a Haskell `Dhall.Type`, you+ can do: > Dhall.Type > (\case@@ -22,28 +89,547 @@ at compile time with all imports resolved, making it easy to keep your Dhall configs and Haskell interpreters in sync. -}-module Dhall.TH- ( -- * Template Haskell- staticDhallExpression- ) where+staticDhallExpression :: Text -> Q Exp+staticDhallExpression text = do+ TH.runIO (GHC.IO.Encoding.setLocaleEncoding System.IO.utf8) -import Data.Typeable-import Language.Haskell.TH.Quote (dataToExpQ) -- 7.10 compatibility.-import Language.Haskell.TH.Syntax+ (expression, status) <- TH.runIO $ do+ parsed <- Dhall.parseWithSettings Dhall.defaultInputSettings text -import qualified Data.Text as Text-import qualified Dhall-import qualified GHC.IO.Encoding-import qualified System.IO+ (resolved, status) <- Dhall.resolveAndStatusWithSettings Dhall.defaultInputSettings parsed --- | This fully resolves, type checks, and normalizes the expression, so the--- resulting AST is self-contained.-staticDhallExpression :: Text.Text -> Q Exp-staticDhallExpression text = do- runIO (GHC.IO.Encoding.setLocaleEncoding System.IO.utf8)- expression <- runIO (Dhall.inputExpr text)- dataToExpQ (\a -> liftText <$> cast a) expression+ _ <- Dhall.typecheckWithSettings Dhall.defaultInputSettings resolved++ let normalized = Dhall.normalizeWithSettings Dhall.defaultInputSettings resolved++ pure (normalized, status)++ forM_ (Dhall.Map.keys (view Dhall.Import.cache status)) $ \chained ->+ case Dhall.Import.chainedImport chained of+ Core.Import+ { importHashed = Core.ImportHashed+ { importType = Core.Local prefix file+ }+ } -> do+ fp <- Dhall.Import.localToPath prefix file+ TH.addDependentFile fp+ _ -> return ()++ dataToExpQ (fmap liftText . Typeable.cast) expression where -- A workaround for a problem in TemplateHaskell (see -- https://stackoverflow.com/questions/38143464/cant-find-inerface-file-declaration-for-variable)- liftText = fmap (AppE (VarE 'Text.pack)) . lift . Text.unpack+ liftText = fmap (AppE (VarE 'Text.pack)) . TH.lift . Text.unpack++{-| A quasi-quoter for Dhall expressions.++ This quoter is build on top of 'staticDhallExpression'. Therefore consult the+ documentation of that function for further information.++ This quoter is meant to be used in expression context only; Other contexts+ like pattern contexts or declaration contexts are not supported and will+ result in an error.+-}+dhall :: QuasiQuoter+dhall = QuasiQuoter+ { quoteExp = staticDhallExpression . Text.pack+ , quotePat = const $ error "dhall quasi-quoter: Quoting patterns is not supported!"+ , quoteType = const $ error "dhall quasi-quoter: Quoting types is not supported!"+ , quoteDec = const $ error "dhall quasi-quoter: Quoting declarations is not supported!"+ }++{-| Convert a Dhall type to a Haskell type that does not require any new+ data declarations beyond the data declarations supplied as the first+ argument+-}+toNestedHaskellType+ :: (Eq a, Pretty a)+ => [Var]+ -> [HaskellType (Expr s a)]+ -- ^ All Dhall-derived data declarations+ --+ -- Used to replace complex types with references to one of these+ -- data declarations when the types match+ -> Expr s a+ -- ^ Dhall expression to convert to a simple Haskell type+ -> Q Type+toNestedHaskellType typeParams haskellTypes = loop+ where+ predicate dhallType haskellType = Core.judgmentallyEqual (code haskellType) dhallType++ document dhallType =+ mconcat+ [ "Unsupported nested type\n"+ , " \n"+ , "Explanation: Not all Dhall types can be nested within Haskell datatype \n"+ , "declarations. Specifically, only the following simple Dhall types are supported\n"+ , "as a nested type inside of a data declaration: \n"+ , " \n"+ , "• ❰Bool❱ \n"+ , "• ❰Double❱ \n"+ , "• ❰Integer❱ \n"+ , "• ❰Natural❱ \n"+ , "• ❰Text❱ \n"+ , "• ❰Date❱ \n"+ , "• ❰TimeOfDay❱ \n"+ , "• ❰TimeZone❱ \n"+ , "• ❰List a❱ (where ❰a❱ is also a valid nested type) \n"+ , "• ❰Optional a❱ (where ❰a❱ is also a valid nested type) \n"+ , "• Another matching datatype declaration \n"+ , "• A bound type variable \n"+ , " \n"+ , "The Haskell datatype generation logic encountered the following Dhall type: \n"+ , " \n"+ , " " <> Dhall.Util.insert dhallType <> "\n"+ , " \n"+ , "... which did not fit any of the above criteria."+ ]++ message dhallType = Pretty.renderString (Dhall.Pretty.layout (document dhallType))++ loop dhallType = case dhallType of+ Bool ->+ return (ConT ''Bool)++ Double ->+ return (ConT ''Double)++ Integer ->+ return (ConT ''Integer)++ Natural ->+ return (ConT ''Numeric.Natural.Natural)++ Text ->+ return (ConT ''Text)++ Date ->+ return (ConT ''Time.Day)++ Time ->+ return (ConT ''Time.TimeOfDay)++ TimeZone ->+ return (ConT ''Time.TimeZone)++ App List dhallElementType -> do+ haskellElementType <- loop dhallElementType++ return (AppT (ConT ''[]) haskellElementType)++ App Optional dhallElementType -> do+ haskellElementType <- loop dhallElementType++ return (AppT (ConT ''Maybe) haskellElementType)++ App dhallAppType dhallElementType -> do+ haskellAppType <- loop dhallAppType+ haskellElementType <- loop dhallElementType++ return (AppT haskellAppType haskellElementType)++ Var v+ | Just (V param index) <- List.find (v ==) typeParams -> do+ let name = TH.mkName $ (Text.unpack param) ++ (show index)++ return (VarT name)++ | otherwise -> fail $ message v++ _ | Just haskellType <- List.find (predicate dhallType) haskellTypes -> do+ let name = TH.mkName (Text.unpack (typeName haskellType))++ return (ConT name)+ | otherwise -> fail $ message dhallType++-- | A deriving clause for `Generic`.+derivingGenericClause :: DerivClause+derivingGenericClause = DerivClause (Just StockStrategy) [ ConT ''Generic ]++-- | Generates a `FromDhall` instances.+fromDhallInstance+ :: TH.Name -- ^ The name of the type the instances is for+ -> Q Exp -- ^ A TH splice generating some `Dhall.InterpretOptions`+ -> Q [Dec]+fromDhallInstance n interpretOptions = [d|+ instance FromDhall $(pure $ ConT n) where+ autoWith = Dhall.genericAutoWithInputNormalizer $(interpretOptions)+ |]++-- | Generates a `ToDhall` instances.+toDhallInstance+ :: TH.Name -- ^ The name of the type the instances is for+ -> Q Exp -- ^ A TH splice generating some `Dhall.InterpretOptions`+ -> Q [Dec]+toDhallInstance n interpretOptions = [d|+ instance ToDhall $(pure $ ConT n) where+ injectWith = Dhall.genericToDhallWithInputNormalizer $(interpretOptions)+ |]++-- | Convert a Dhall type to the corresponding Haskell datatype declaration+toDeclaration+ :: (Eq a, Pretty a)+ => GenerateOptions+ -> [HaskellType (Expr s a)]+ -> HaskellType (Expr s a)+ -> Q [Dec]+toDeclaration generateOptions@GenerateOptions{..} haskellTypes typ =+ case typ of+ SingleConstructor{..} -> uncurry (fromSingle typeName constructorName) $ getTypeParams code+ MultipleConstructors{..} -> uncurry (fromMulti typeName) $ getTypeParams code+ where+ getTypeParams = first numberConsecutive . getTypeParams_ []++ getTypeParams_ acc (Lam _ (FunctionBinding _ v _ _ _) rest) = getTypeParams_ (v:acc) rest+ getTypeParams_ acc rest = (acc, rest)++ derivingClauses = [ derivingGenericClause | generateFromDhallInstance || generateToDhallInstance ]++ interpretOptions = generateToInterpretOptions generateOptions typ++#if MIN_VERSION_template_haskell(2,21,0)+ toTypeVar (V n i) = TH.PlainTV (TH.mkName (Text.unpack n ++ show i)) TH.BndrReq+#elif MIN_VERSION_template_haskell(2,17,0)+ toTypeVar (V n i) = TH.PlainTV (TH.mkName (Text.unpack n ++ show i)) ()+#else+ toTypeVar (V n i) = TH.PlainTV (TH.mkName (Text.unpack n ++ show i))+#endif++ toDataD typeName typeParams constructors = do+ let name = TH.mkName (Text.unpack typeName)++ let params = fmap toTypeVar typeParams++ fmap concat . sequence $+ [pure [DataD [] name params Nothing constructors derivingClauses]] <>+ [ fromDhallInstance name interpretOptions | generateFromDhallInstance ] <>+ [ toDhallInstance name interpretOptions | generateToDhallInstance ]++ fromSingle typeName constructorName typeParams dhallType = do+ constructor <- toConstructor typeParams generateOptions haskellTypes typeName (constructorName, Just dhallType)++ toDataD typeName typeParams [constructor]++ fromMulti typeName typeParams dhallType = case dhallType of+ Union kts -> do+ constructors <- traverse (toConstructor typeParams generateOptions haskellTypes typeName) (Dhall.Map.toList kts)++ toDataD typeName typeParams constructors++ _ -> fail $ message dhallType++ message dhallType = Pretty.renderString (Dhall.Pretty.layout $ document dhallType)++ document dhallType =+ mconcat+ [ "Dhall.TH.makeHaskellTypes: Not a union type\n"+ , " \n"+ , "Explanation: This function expects the ❰code❱ field of ❰MultipleConstructors❱ to\n"+ , "evaluate to a union type. \n"+ , " \n"+ , "For example, this is a valid Dhall union type that this function would accept: \n"+ , " \n"+ , " \n"+ , " ┌──────────────────────────────────────────────────────────────────┐ \n"+ , " │ Dhall.TH.makeHaskellTypes (MultipleConstructors \"T\" \"< A | B >\") │ \n"+ , " └──────────────────────────────────────────────────────────────────┘ \n"+ , " \n"+ , " \n"+ , "... which corresponds to this Haskell type declaration: \n"+ , " \n"+ , " \n"+ , " ┌────────────────┐ \n"+ , " │ data T = A | B │ \n"+ , " └────────────────┘ \n"+ , " \n"+ , " \n"+ , "... but the following Dhall type is rejected due to being a bare record type: \n"+ , " \n"+ , " \n"+ , " ┌──────────────────────────────────────────────┐ \n"+ , " │ Dhall.TH.makeHaskellTypes \"T\" \"{ x : Bool }\" │ Not valid \n"+ , " └──────────────────────────────────────────────┘ \n"+ , " \n"+ , " \n"+ , "The Haskell datatype generation logic encountered the following Dhall type: \n"+ , " \n"+ , " " <> Dhall.Util.insert dhallType <> "\n"+ , " \n"+ , "... which is not a union type."+ ]++-- | Number each variable, starting at 0+numberConsecutive :: [Text.Text] -> [Var]+numberConsecutive = snd . List.mapAccumR go Map.empty . reverse+ where+ go m k =+ let (i, m') = Map.updateLookupWithKey (\_ j -> Just $ j + 1) k m+ in maybe ((Map.insert k 0 m'), (V k 0)) (\i' -> (m', (V k i'))) i++-- | Convert a Dhall type to the corresponding Haskell constructor+toConstructor+ :: (Eq a, Pretty a)+ => [Var]+ -> GenerateOptions+ -> [HaskellType (Expr s a)]+ -> Text+ -- ^ typeName+ -> (Text, Maybe (Expr s a))+ -- ^ @(constructorName, fieldType)@+ -> Q Con+toConstructor typeParams GenerateOptions{..} haskellTypes outerTypeName (constructorName, maybeAlternativeType) = do+ let name = TH.mkName (Text.unpack $ constructorModifier constructorName)++ let strictness = if makeStrict then SourceStrict else NoSourceStrictness++ let bang = Bang NoSourceUnpackedness strictness++ case maybeAlternativeType of+ Just dhallType+ | let predicate haskellType =+ Core.judgmentallyEqual (code haskellType) dhallType+ && typeName haskellType /= outerTypeName+ , Just haskellType <- List.find predicate haskellTypes -> do+ let innerName =+ TH.mkName (Text.unpack (typeName haskellType))++ return (NormalC name [ (bang, ConT innerName) ])++ Just (Record kts) -> do+ let process (key, dhallFieldType) = do+ haskellFieldType <- toNestedHaskellType typeParams haskellTypes dhallFieldType++ return (TH.mkName (Text.unpack $ fieldModifier key), bang, haskellFieldType)++ varBangTypes <- traverse process (Dhall.Map.toList $ Core.recordFieldValue <$> kts)++ return (RecC name varBangTypes)++ Just dhallAlternativeType -> do+ haskellAlternativeType <- toNestedHaskellType typeParams haskellTypes dhallAlternativeType++ return (NormalC name [ (bang, haskellAlternativeType) ])++ Nothing ->+ return (NormalC name [])++-- | Generate a Haskell datatype declaration from a Dhall union type where+-- each union alternative corresponds to a Haskell constructor+--+-- For example, this Template Haskell splice:+--+-- > Dhall.TH.makeHaskellTypeFromUnion "T" "< A : { x : Bool } | B >"+--+-- ... generates this Haskell code:+--+-- > data T = A {x :: GHC.Types.Bool} | B+--+-- This is a special case of `Dhall.TH.makeHaskellTypes`:+--+-- > makeHaskellTypeFromUnion typeName code =+-- > makeHaskellTypes [ MultipleConstructors{..} ]+makeHaskellTypeFromUnion+ :: Text+ -- ^ Name of the generated Haskell type+ -> Text+ -- ^ Dhall code that evaluates to a union type+ -> Q [Dec]+makeHaskellTypeFromUnion typeName code =+ makeHaskellTypes [ MultipleConstructors{..} ]++-- | Used by `makeHaskellTypes` and `makeHaskellTypesWith` to specify how to+-- generate Haskell types.+data HaskellType code+ -- | Generate a Haskell type with more than one constructor from a Dhall+ -- union type.+ = MultipleConstructors+ { typeName :: Text+ -- ^ Name of the generated Haskell type+ , code :: code+ -- ^ Dhall code that evaluates to a union type+ }+ -- | Generate a Haskell type with one constructor from any Dhall type.+ --+ -- To generate a constructor with multiple named fields, supply a Dhall+ -- record type. This does not support more than one anonymous field.+ | SingleConstructor+ { typeName :: Text+ -- ^ Name of the generated Haskell type+ , constructorName :: Text+ -- ^ Name of the constructor+ , code :: code+ -- ^ Dhall code that evaluates to a type+ }+ deriving (Functor, Foldable, Traversable)++-- | This data type holds various options that let you control several aspects+-- how Haskell code is generated. In particular you can+--+-- * disable the generation of `FromDhall`/`ToDhall` instances.+-- * modify how a Dhall union field translates to a Haskell data constructor.+data GenerateOptions = GenerateOptions+ { constructorModifier :: Text -> Text+ -- ^ How to map a Dhall union field name to a Haskell constructor.+ -- Note: The `constructorName` of `SingleConstructor` will be passed to this function, too.+ , fieldModifier :: Text -> Text+ -- ^ How to map a Dhall record field names to a Haskell record field names.+ , generateFromDhallInstance :: Bool+ -- ^ Generate a `FromDhall` instance for the Haskell type+ , generateToDhallInstance :: Bool+ -- ^ Generate a `ToDhall` instance for the Haskell type+ , makeStrict :: Bool+ -- ^ Make all fields strict.+ }++-- | A default set of options used by `makeHaskellTypes`. That means:+--+-- * Constructors and fields are passed unmodified.+-- * Both `FromDhall` and `ToDhall` instances are generated.+--+-- Note: `From/ToDhall` should be `False` if importing higher-kinded types.+-- In these cases one should use a standalone declaration.+defaultGenerateOptions :: GenerateOptions+defaultGenerateOptions = GenerateOptions+ { constructorModifier = id+ , fieldModifier = id+ , generateFromDhallInstance = True+ , generateToDhallInstance = True+ , makeStrict = False+ }++-- | This function generates `Dhall.InterpretOptions` that can be used for the+-- marshalling of the Haskell type generated according to the `GenerateOptions`.+-- I.e. those `Dhall.InterpretOptions` reflect the mapping done by+-- `constructorModifier` and `fieldModifier` on the value level.+generateToInterpretOptions :: GenerateOptions -> HaskellType (Expr s a) -> Q Exp+generateToInterpretOptions GenerateOptions{..} haskellType = [| Dhall.InterpretOptions+ { Dhall.fieldModifier = \ $(pure nameP) ->+ $(toCases fieldModifier $ fields haskellType)+ , Dhall.constructorModifier = \ $(pure nameP) ->+ $(toCases constructorModifier $ constructors haskellType)+ , Dhall.singletonConstructors = Dhall.singletonConstructors Dhall.defaultInterpretOptions+ }|]+ where+ constructors :: HaskellType (Expr s a) -> [Text]+ constructors SingleConstructor{..} = [constructorName]+ constructors MultipleConstructors{..} | Union kts <- code = Dhall.Map.keys kts+ constructors _ = []++ fields :: HaskellType (Expr s a) -> [Text]+ fields SingleConstructor{..} | Record kts <- code = Dhall.Map.keys kts+ fields MultipleConstructors{..} | Union kts <- code = Set.toList $ mconcat+ [ Dhall.Map.keysSet kts'+ | (_, Just (Record kts')) <- Dhall.Map.toList kts+ ]+ fields _ = []++ toCases :: (Text -> Text) -> [Text] -> Q Exp+ toCases f xs = do+ err <- [| Core.internalError $ "Unmatched " <> Text.pack (show $(pure nameE)) |]+ pure $ CaseE nameE $ map mkMatch xs <> [Match WildP (NormalB err) []]+ where+ mkMatch n = Match (textToPat $ f n) (NormalB $ textToExp n) []++ nameE :: Exp+ nameE = TH.VarE $ TH.mkName "n"++ nameP :: Pat+ nameP = TH.VarP $ TH.mkName "n"++ textToExp :: Text -> Exp+ textToExp = TH.LitE . TH.StringL . Text.unpack++ textToPat :: Text -> Pat+ textToPat = TH.LitP . TH.StringL . Text.unpack++-- | Generate a Haskell datatype declaration with one constructor from a Dhall+-- type.+--+-- This comes in handy if you need to keep Dhall types and Haskell types in+-- sync. You make the Dhall types the source of truth and use Template Haskell+-- to generate the matching Haskell type declarations from the Dhall types.+--+-- For example, given this Dhall code:+--+-- > -- ./Department.dhall+-- > < Sales | Engineering | Marketing >+--+-- > -- ./Employee.dhall+-- > { name : Text, department : ./Department.dhall }+--+-- ... this Template Haskell splice:+--+-- > {-# LANGUAGE DeriveAnyClass #-}+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE DerivingStrategies #-}+-- > {-# LANGUAGE OverloadedStrings #-}+-- > {-# LANGUAGE TemplateHaskell #-}+-- >+-- > Dhall.TH.makeHaskellTypes+-- > [ MultipleConstructors "Department" "./tests/th/Department.dhall"+-- > , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+-- > ]+--+-- ... generates this Haskell code:+--+-- > data Department = Engineering | Marketing | Sales+-- > deriving stock (GHC.Generics.Generic)+-- > deriving anyclass (Dhall.FromDhall, Dhall.ToDhall)+-- >+-- > data Employee+-- > = MakeEmployee {department :: Department,+-- > name :: Data.Text.Internal.Text}+-- > deriving stock (GHC.Generics.Generic)+-- > deriving anyclass (Dhall.FromDhall, Dhall.ToDhall)+--+-- Carefully note that the conversion makes a best-effort attempt to+-- auto-detect when a Dhall type (like @./Employee.dhall@) refers to another+-- Dhall type (like @./Department.dhall@) and replaces that reference with the+-- corresponding Haskell type.+--+-- This Template Haskell splice requires you to enable the following extensions:+--+-- * @DeriveGeneric@+-- * @DerivingAnyClass@+-- * @DerivingStrategies@+--+-- By default, the generated types only derive `GHC.Generics.Generic`,+-- `Dhall.FromDhall`, and `Dhall.ToDhall`. To add any desired instances (such+-- as `Eq`\/`Ord`\/`Show`), you can use the @StandaloneDeriving@ language+-- extension, like this:+--+-- > {-# LANGUAGE DeriveAnyClass #-}+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE DerivingStrategies #-}+-- > {-# LANGUAGE OverloadedStrings #-}+-- > {-# LANGUAGE StandaloneDeriving #-}+-- > {-# LANGUAGE TemplateHaskell #-}+-- >+-- > Dhall.TH.makeHaskellTypes+-- > [ MultipleConstructors "Department" "./tests/th/Department.dhall"+-- > , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+-- > ]+-- >+-- > deriving instance Eq Department+-- > deriving instance Ord Department+-- > deriving instance Show Department+-- >+-- > deriving instance Eq Employee+-- > deriving instance Ord Employee+-- > deriving instance Show Employee+makeHaskellTypes :: [HaskellType Text] -> Q [Dec]+makeHaskellTypes = makeHaskellTypesWith defaultGenerateOptions++-- | Like `makeHaskellTypes`, but with the ability to customize the generated+-- Haskell code by passing `GenerateOptions`.+--+-- For instance, `makeHaskellTypes` is implemented using this function:+--+-- > makeHaskellTypes = makeHaskellTypesWith defaultGenerateOptions+makeHaskellTypesWith :: GenerateOptions -> [HaskellType Text] -> Q [Dec]+makeHaskellTypesWith generateOptions haskellTypes = do+ TH.runIO (GHC.IO.Encoding.setLocaleEncoding System.IO.utf8)++ haskellTypes' <- traverse (traverse (TH.runIO . Dhall.inputExpr)) haskellTypes++ concat <$> traverse (toDeclaration generateOptions haskellTypes') haskellTypes'
@@ -0,0 +1,269 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module contains the implementation of the @dhall tags@ command++module Dhall.Tags+ ( generate+ ) where++import Control.Exception (SomeException (..), handle)+import Data.List (foldl', isSuffixOf)+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import Data.Text.Encoding (encodeUtf8)+import Dhall.Map (foldMapWithKey)+import Dhall.Parser (exprFromText)+import Dhall.Src (Src (srcStart))+import Dhall.Syntax (Binding (..), Expr (..), RecordField (..))+import Dhall.Util (Input (..))+import System.FilePath (takeFileName, (</>))+import Text.Megaparsec (sourceColumn, sourceLine, unPos)++import qualified Data.ByteString as BS (length)+import qualified Data.Map as M+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import qualified System.Directory as SD++{-+ Documentation for the etags format is not very informative and not very correct.+ You can find some documentation here:+ https://en.wikipedia.org/wiki/Ctags#Etags_2+ and you can also check the source code here:+ http://cvs.savannah.gnu.org/viewvc/vtags/vtags/vtags.el?view=markup+-}++data LineColumn = LC+ { _lcLine :: Int+ -- ^ line number, starting from 1, where to find the tag+ , _lcColumn :: Int+ -- ^ column of line where tag is+ } deriving (Eq, Ord, Show)++data LineOffset = LO+ { loLine :: Int+ -- ^ line number, starting from 1, where to find the tag+ , loOffset :: Int+ -- ^ byte offset from start of file. Not sure if any editor uses it+ } deriving (Eq, Ord, Show)++newtype Tags = Tags (M.Map FilePath [(LineOffset, Tag)])++instance Semigroup Tags where+ (Tags ts1) <> (Tags ts2) = Tags (M.unionWith (<>) ts1 ts2)++instance Monoid Tags where+ mempty = Tags M.empty++{-| For example, for the line: @let foo = \"foo\"@ the tag is:+ > Tag "let " "foo"+-}+data Tag = Tag+ { tagPattern :: Text+ -- ^ In vtags source code this field is named \"pattern\" and EMacs used it as+ -- a regex pattern to locate line with tag. It's looking for ^<tag pattern>.+ -- Looks like vi is not using it.+ , tagName :: Text+ -- ^ text, that editor compare with selected text. So it's really name of entity+ } deriving (Show)++type LineNumber = Int++type ByteOffset = Int++{-| Generate etags for Dhall expressions+-}+generate+ :: Input+ -- ^ Where to look for files. This can be a directory name (@.@ for example),+ -- a file name or `StandardInput`. If `StandardInput`, then this will wait for+ -- file names from @STDIN@.+ -- This way someone can combine tools in @bash@ to send, for example, output from+ -- @find@ to the input of @dhall tags@.+ -> Maybe [Text]+ -- ^ List of suffixes for dhall files or Nothing to check all files+ -> Bool+ -- ^ Flag if `generate` should follow symlinks+ -> IO Text+ -- ^ Content for tags file+generate inp sxs followSyms = do+ files <- inputToFiles followSyms (map T.unpack <$> sxs) inp+ tags <- traverse (\f -> handle (\(SomeException _) -> return mempty)+ (fileTags f <$> TIO.readFile f)) files+ return (showTags . mconcat $ tags)++{-| Find tags in Text (second argument) and generates a list of them+ To make tags for filenames that works in both emacs and vi, add two initial tags.+ First for @filename@ for vi and second with @/filename@ for emacs.+ Other tags are working for both.+-}+fileTags :: FilePath -> Text -> Tags+fileTags f t = Tags (M.singleton f+ (initialMap <> getTagsFromText t))+ where initialViTag = (LO 1 1, Tag "" (T.pack . takeFileName $ f))+ initialEmacsTag = (LO 1 1, Tag "" ("/" <> (T.pack . takeFileName) f))+ initialMap = [initialViTag, initialEmacsTag]++getTagsFromText :: Text -> [(LineOffset, Tag)]+getTagsFromText t = case exprFromText "" t of+ Right expr -> fixPosAndDefinition t (getTagsFromExpr expr)+ _ -> mempty++{-| Used to update tag position and to build tag from term.+ After getTagsFromExpr line and column in line are in @LineColumn@ for each tag.+ And tagPattern is not added.+ Emacs use tag pattern to check if tag is on line. It compares line from start+ with tag pattern and in case they are the same, relocate user.+ fixPosAndDefinition change position to line and byte offset (@LineOffset@) and+ add tag pattern. For example, for Dhall string:++ >>> let dhallSource = "let foo = \"bar\"\nlet baz = \"qux\""++ Input for this function is:++ >>> foundTerms = [(LC 1 4, "foo"), (LC 2 4, "baz")]++ And:++ >>> fixPosAndDefinition dhallSource foundTerms+ [(LO {loLine = 1, loOffset = 5},Tag {tagPattern = "let foo ", tagName = "foo"}),(LO {loLine = 2, loOffset = 21},Tag {tagPattern = "let baz ", tagName = "baz"})]++ where 21 is byte offset from file start.+-}+fixPosAndDefinition :: Text -> [(LineColumn, Text)] -> [(LineOffset, Tag)]+fixPosAndDefinition t = foldMap (\(LC ln c, term) ->+ let (ln', offset, tPattern) = fromMaybe (fallbackInfoForText ln c)+ (infoForText term ln)+ in [(LO ln' offset, Tag tPattern term)])+ where mls :: M.Map Int (Text, Int)+ -- ^ mls is map that for each line has length of file before this map and line content.+ -- In example above, first line is 15 bytes long and '\n', mls contain:+ -- (1, (16, "let foo = "bar"")+ -- That allow us to get byte offset easier.+ mls = M.fromList . fst . foldl' processLine ([], 0) . zip [1..] $ T.lines t++ {-| processLine is a worker for `foldl` that generates the list of lines with+ byte offsets from the start of the first line from a list of lines+ -}+ processLine+ :: ([(LineNumber, (Text, ByteOffset))], ByteOffset)+ -- ^ previous result and byte offset for the start of current line+ -> (LineNumber, Text)+ -> ([(LineNumber, (Text, ByteOffset))], ByteOffset)+ -- ^ next result, where new line was added and byte offset for next line+ processLine (numberedLinesWithSizes, bytesBeforeLine) (n, line) =+ ((n, (line, bytesBeforeLine)): numberedLinesWithSizes, bytesBeforeNextLine)+ where bytesBeforeNextLine = bytesBeforeLine + lengthInBytes line + 1++ lineFromMap ln = fromMaybe ("", 0) (ln `M.lookup` mls)++ lengthInBytes = BS.length . encodeUtf8++ {-| get information about term from map of lines+ In most cases, @LineColumn@ after `getTagsFromExpr` points to byte before term.+ It's better to have term in term pattern, so this function finds and updates+ line number and byte offset and generate pattern.+ -}+ infoForText+ :: Text+ -- ^ term to find+ -> Int+ -- ^ line where to start+ -> Maybe (Int, Int, Text)+ -- ^ (Line number, byte offset, pattern to find term in file)+ infoForText term ln+ | ln <= 0 = Nothing+ | T.null part2 = infoForText term (ln - 1)+ | otherwise = Just (ln, lsl + 1 + lengthInBytes part1, part1 <> termAndNext)+ where (l, lsl) = lineFromMap ln+ (part1, part2) = T.breakOn term l+ termAndNext = T.take (T.length term + 1) part2++ fallbackInfoForText ln c = (ln, lsl + 1 + lengthInBytes pat, pat)+ where (l, lsl) = lineFromMap ln+ pat = T.take c l++getTagsFromExpr :: Expr Src a -> [(LineColumn, Text)]+getTagsFromExpr = go (LC 0 0) []+ where go lpos mts = \case+ (Let b e) -> go lpos (mts <> parseBinding lpos b) e+ (Annot e1 e2) -> go lpos (go lpos mts e1) e2+ (Record mr) -> mts <> tagsFromDhallMap lpos (recordFieldValue <$> mr)+ (RecordLit mr) -> mts <> tagsFromDhallMap lpos (recordFieldValue <$> mr)+ (Union mmr) -> mts <> tagsFromDhallMapMaybe lpos mmr+ (Note s e) -> go (srcToLineColumn s) mts e+ _ -> mts++ tagsFromDhallMap lpos = foldMapWithKey (tagsFromDhallMapElement lpos)++ tagsFromDhallMapMaybe lpos = foldMapWithKey (\k -> \case+ Just e -> tagsFromDhallMapElement lpos k e+ _ -> [(lpos, k)])++ tagsFromDhallMapElement lpos k e = go pos [(pos, k)] e+ where pos = firstPosFromExpr lpos e++ parseBinding :: LineColumn -> Binding Src a -> [(LineColumn, Text)]+ parseBinding lpos b = go p2 [(p0, variable b)] (value b)+ where p0 = posFromBinding (bindingSrc0 b) lpos+ p1 = posFromBinding (bindingSrc1 b) p0+ p2 = posFromBinding (bindingSrc2 b) p1+ posFromBinding src startPos = maybe startPos srcToLineColumn src++srcToLineColumn :: Src -> LineColumn+srcToLineColumn s = LC line column+ where ssp = srcStart s+ line = unPos . sourceLine $ ssp+ column = unPos . sourceColumn $ ssp++firstPosFromExpr :: LineColumn -> Expr Src a -> LineColumn+firstPosFromExpr lpos = \case+ (Note s _) -> srcToLineColumn s+ _ -> lpos++showTags :: Tags -> Text+showTags (Tags ts) = T.concat . map (uncurry showFileTags) . M.toList $ ts++showFileTags :: FilePath -> [(LineOffset, Tag)] -> T.Text+showFileTags f ts = "\x0c\n" <> T.pack f <> "," <> (showInt . T.length) cs <> "\n" <> cs+ where cs = T.concat . map (uncurry showPosTag) $ ts++showPosTag :: LineOffset -> Tag -> Text+showPosTag lo tag = def <>"\x7f" <> name <> "\x01" <> showInt line <>+ "," <> showInt offset <> "\n"+ where line = loLine lo+ offset = loOffset lo+ def = tagPattern tag+ name = tagName tag++showInt :: Int -> Text+showInt = T.pack . show++{-| Generate list of files for a given `Input`+-}+inputToFiles+ :: Bool+ -- ^ If `True`, this function will follow symbolic links+ -> Maybe [String]+ -- ^ List of suffixes. If `Nothing`, all files will be returned.+ -- This parameter only works when the `Input` is an `InputFile` and point to a directory.+ -> Input+ -> IO [ FilePath ]+ -- List of files.+inputToFiles _ _ StandardInput = lines <$> getContents+inputToFiles followSyms suffixes (InputFile path) = go path+ where go p = do+ isD <- SD.doesDirectoryExist p+ isSL <- isSymLink+ if isD+ then if isSL && not followSyms+ then return []+ else do+ -- filter . .. and hidden files .*+ contents <- fmap (filter ((/=) '.' . head))+ (SD.getDirectoryContents p)+ concat <$> mapM (go . (</>) p) contents+ else return [p | matchingSuffix || p == path]+ where matchingSuffix = maybe True (any (`isSuffixOf` p)) suffixes+ isSymLink = SD.pathIsSymbolicLink p
@@ -1,2869 +1,2319 @@ {-# OPTIONS_GHC -fno-warn-unused-imports #-}--{-| Dhall is a programming language specialized for configuration files. This- module contains a tutorial explaning how to author configuration files using- this language--}-module Dhall.Tutorial (- -- * Introduction- -- $introduction-- -- * Types- -- $types-- -- * Imports- -- $imports-- -- * Lists- -- $lists-- -- * Optional values- -- $optional0-- -- * Records- -- $records-- -- * Functions- -- $functions-- -- * Compiler- -- $compiler-- -- * Strings- -- $strings-- -- * Combine- -- $combine-- -- * Let expressions- -- $let-- -- * Unions- -- $unions-- -- * Polymorphic functions- -- $polymorphic-- -- * Total- -- $total-- -- * Headers- -- $headers-- -- * Import integrity- -- $integrity-- -- * Raw text- -- $rawText-- -- * Formatting code- -- $format-- -- * Built-in functions- -- $builtins-- -- ** Caveats- -- $caveats-- -- ** Extending the language- -- $extending-- -- ** Overview- -- $builtinOverview-- -- ** @Bool@- -- $bool-- -- *** @(||)@- -- $or-- -- *** @(&&)@- -- $and-- -- *** @(==)@- -- $equal-- -- *** @(!=)@- -- $unequal-- -- *** @if@\/@then@\/@else@- -- $ifthenelse-- -- ** @Natural@- -- $natural-- -- *** @(+)@- -- $plus-- -- *** @(*)@- -- $times-- -- *** @Natural/even@- -- $even-- -- *** @Natural/odd@- -- $odd-- -- *** @Natural/isZero@- -- $isZero-- -- *** @Natural/fold@- -- $naturalFold-- -- *** @Natural/build@- -- $naturalBuild-- -- ** @Integer@- -- $integer-- -- ** @Double@- -- $double-- -- ** @Text@- -- $text-- -- *** @(++)@- -- $textAppend-- -- ** @List@- -- $list-- -- *** @(#)@- -- $listAppend-- -- *** @List/fold@- -- $listFold-- -- *** @List/build@- -- $listBuild-- -- *** @List/length@- -- $listLength-- -- *** @List/head@- -- $listHead-- -- *** @List/last@- -- $listLast-- -- *** @List/indexed@- -- $listIndexed-- -- *** @List/reverse@- -- $listReverse-- -- ** @Optional@- -- $optional1-- -- *** @Optional/fold@- -- $optionalFold-- -- * Prelude- -- $prelude-- -- * Conclusion- -- $conclusion-- -- * Frequently Asked Questions (FAQ)- -- $faq- ) where--import Data.Vector (Vector)-import Dhall---- $setup------ >>> :set -XOverloadedStrings---- $introduction------ The simplest way to use Dhall is to ignore the programming language features--- and use it as a strongly typed configuration format. For example, suppose--- that you create the following configuration file:--- --- > $ cat ./config--- > { foo = 1--- > , bar = [3.0, 4.0, 5.0]--- > }--- --- You can read the above configuration file into Haskell using the following--- code:--- --- > -- example.hs--- > --- > {-# LANGUAGE DeriveGeneric #-}--- > {-# LANGUAGE OverloadedStrings #-}--- > --- > import Dhall--- > --- > data Example = Example { foo :: Natural, bar :: Vector Double }--- > deriving (Generic, Show)--- > --- > instance Interpret Example--- > --- > main :: IO ()--- > main = do--- > x <- input auto "./config"--- > print (x :: Example)--- --- If you compile and run the above example, the program prints the corresponding--- Haskell record:--- --- > $ ./example--- > Example {foo = 1, bar = [3.0,4.0,5.0]}------ You can also load some types directly into Haskell without having to define a--- record, like this:------ >>> :set -XOverloadedStrings--- >>> input auto "True" :: IO Bool--- True------ The `input` function can decode any value if we specify the value's expected--- `Type`:------ > input--- > :: Type a -- Expected type--- > -> Text -- Dhall program--- > -> IO a -- Decoded expression------ ... and we can either specify an explicit type like `bool`:------ > bool :: Type Bool--- > --- > input bool :: Text -> IO Bool--- >--- > input bool "True" :: IO Bool------ >>> input bool "True"--- True------ ... or we can use `auto` to let the compiler infer what type to decode from--- the expected return type:------ > auto :: Interpret a => Type a--- >--- > input auto :: Interpret a => Text -> IO a------ >>> input auto "True" :: IO Bool--- True------ You can see what types `auto` supports \"out-of-the-box\" by browsing the--- instances for the `Interpret` class. For example, the following instance--- says that we can directly decode any Dhall expression that evaluates to a--- @Bool@ into a Haskell `Bool`:------ > instance Interpret Bool------ ... which is why we could directly decode the string @\"True\"@ into the--- value `True`.------ There is also another instance that says that if we can decode a value of--- type @a@, then we can also decode a @List@ of values as a `Vector` of @a@s:------ > instance Interpret a => Interpret (Vector a)------ Therefore, since we can decode a @Bool@, we must also be able to decode a--- @List@ of @Bool@s, like this:------ >>> input auto "[True, False]" :: IO (Vector Bool)--- [True,False]------ We could also specify what type to decode by providing an explicit `Type`--- instead of using `auto` with a type annotation:------ >>> input (vector bool) "[True, False]"--- [True,False]------ __Exercise:__ Create a @./config@ file that the following program can decode:------ > {-# LANGUAGE DeriveGeneric #-}--- > {-# LANGUAGE OverloadedStrings #-}--- > --- > import Dhall--- > --- > data Person = Person { age :: Natural, name :: Text }--- > deriving (Generic, Show)--- > --- > instance Interpret Person--- > --- > main :: IO ()--- > main = do--- > x <- input auto "./config"--- > print (x :: Person)------ __Exercise:__ Create a @./config@ file that the following program can decode:------ > {-# LANGUAGE OverloadedStrings #-}--- > --- > import Data.Functor.Identity--- > import Dhall--- > --- > instance Interpret a => Interpret (Identity a)--- > --- > main :: IO ()--- > main = do--- > x <- input auto "./config"--- > print (x :: Identity Double)---- $types------ Suppose that we try to decode a value of the wrong type, like this:------ >>> input auto "1" :: IO Bool--- *** Exception:--- ...Error...: Expression doesn't match annotation--- ...--- - Bool--- + Natural--- ...--- 1: 1 : Bool--- ...--- (input):1:1--- ...------ The interpreter complains because the string @\"1\"@ cannot be decoded into a--- Haskell value of type `Bool`. This part of the type error:------ > - Bool--- > + Natural------ ... means that the expected type was @Bool@ but the inferred type of the--- expression @1@ was @Natural@.------ The code excerpt from the above error message has two components:------ * the expression being type checked (i.e. @1@)--- * the expression's expected type (i.e. @Bool@)------ > Expression--- > ⇩--- > 1 : Bool--- > ⇧--- > Expected type------ The @(:)@ symbol is how Dhall annotates values with their expected types.--- This notation is equivalent to type annotations in Haskell using the @(::)@--- symbol. Whenever you see:------ > x : t------ ... you should read that as \"we expect the expression @x@ to have type--- @t@\". However, we might be wrong and if our expected type does not match the--- expression's actual type then the type checker will complain.------ In this case, the expression @1@ does not have type @Bool@ so type checking--- fails with an exception.------ __Exercise:__ Load the Dhall library into @ghci@ and run these commands to get--- get a more detailed error message:------ > >>> import Dhall--- > >>> :set -XOverloadedStrings--- > >>> detailed (input auto "1") :: IO Bool--- > ...------ ... then read the entire error message------ __Exercise:__ Fix the type error, either by changing the value to decode or--- changing the expected type---- $imports------ You might wonder why in some cases we can decode a configuration file:------ >>> writeFile "bool" "True"--- >>> input auto "./bool" :: IO Bool--- True------ ... and in other cases we can decode a value directly:------ >>> input auto "True" :: IO Bool--- True------ This is because importing a configuration from a file is a special case of a--- more general language feature: Dhall expressions can reference other--- expressions by their file path.------ To illustrate this, let's create three files:--- --- > $ echo "True" > bool1--- > $ echo "False" > bool2--- > $ echo "./bool1 && ./bool2" > both------ ... and read in all three files in a single expression:--- --- >>> input auto "[ ./bool1 , ./bool2 , ./both ]" :: IO (Vector Bool)--- [True,False,False]------ Each file path is replaced with the Dhall expression contained within that--- file. If that file contains references to other files then those references--- are transitively resolved.------ In other words: configuration files can reference other configuration files,--- either by their relative or absolute paths. This means that we can split a--- configuration file into multiple files, like this:------ > $ cat > ./config <<EOF--- > { foo = 1--- > , bar = ./bar--- > }--- > EOF------ > $ echo "[3.0, 4.0, 5.0]" > ./bar------ > $ ./example--- > Example {foo = 1, bar = [3.0,4.0,5.0]}------ However, the Dhall language will forbid cycles in these file references. For--- example, if we create the following cycle:------ > $ echo './file1' > file2--- > $ echo './file2' > file1------ ... then the interpreter will reject the import:------ >>> input auto "./file1" :: IO Natural--- *** Exception: --- ↳ ./file1--- ↳ ./file2--- ...--- Cyclic import: ./file1--- ...------ You can also import expressions by URL. For example, you can find a Dhall--- expression hosted at this GitHub URL:------ <https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True>------ > $ curl https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True--- > True------ ... and you can reference that expression either directly:------ >>> input auto "https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool--- True--- --- ... or inside of a larger expression:------ >>> input auto "False == https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool--- False------ You're not limited to hosting Dhall expressions on GitHub. You can host a--- Dhall expression anywhere that you can host UTF8-encoded text on the web,--- as a pastebin, or your own web server.------ You can also import Dhall expressions from environment variables, too:------ >>> System.Environment.setEnv "FOO" "1"--- >>> input auto "env:FOO" :: IO Natural--- 1------ You can import types, too. For example, we can change our @./bar@ file to:------ > $ echo "[3.0, 4.0, 5.0] : List ./type" > ./bar------ ... then specify the @./type@ in a separate file:------ > $ echo "Double" > ./type------ ... and everything still type checks:------ > $ ./example--- > Example {foo = 1, bar = [3.0,4.0,5.0]}------ Note that all imports must be terminated by whitespace or you will get either--- an import error or a parse error, like this:------ >>> writeFile "baz" "2.0"--- >>> input auto "./baz: Double" :: IO Double--- *** Exception: --- ↳ ./baz: --- ...--- ...Error...: Missing file ...baz:--- ...------ This is because the parser thinks that @./baz:@ is a single token due to--- the missing whitespace before the colon and tries to import a file named--- @./baz:@, which does not exist. To fix the problem we have to add a space--- after @./baz@:------ >>> input auto "./baz : Double" :: IO Double--- 2.0------ __Exercise:__ There is a @not@ function hosted online here:------ <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not>------ Visit that link and read the documentation. Then try to guess what this--- code returns:------ > >>> input auto "https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool--- > ???------ Run the code to test your guess---- $lists------ You can store 0 or more values of the same type in a list, like this:------ > [1, 2, 3]------ Every list can be followed by the type of the list. The type annotation is--- required for empty lists but optional for non-empty lists. You will get a--- type error if you provide an empty list without a type annotation:------ >>> input auto "[]" :: IO (Vector Natural)--- *** Exception:--- ...Error...: An empty list requires a type annotation--- ...--- 1: []--- ...--- (input):1:1------ Also, list elements must all have the same type. You will get an error if--- you try to store elements of different types in a list:------ >>> input auto "[1, True, 3]" :: IO (Vector Natural)--- *** Exception:--- ...Error...: List elements should all have the same type--- ...--- - Natural--- + Bool--- ...--- 1: True--- ...--- (input):1:5--- ...------ __Exercise:__ What is the shortest @./config@ file that you can decode using--- this command:------ > >>> input auto "./config" :: IO (Vector (Vector Natural))---- $optional0------ @Optional@ values are either of the form @Some aValue@ or @None aType@.------ For example, these are valid @Optional@ values:------ > Some 1--- >--- > None Natural------ ... which both have type @Optional Natural@------ An @Optional@ corresponds to Haskell's `Maybe` type for decoding purposes:------ >>> input auto "Some 1" :: IO (Maybe Natural)--- Just 1--- >>> input auto "None Natural" :: IO (Maybe Natural)--- Nothing------ __Exercise:__ Author a @./config@ file that you can decode like this:------ > >>> input auto "./config" :: IO (Maybe (Maybe (Maybe Natural)))--- > ???---- $records------ Record literals are delimited by curly braces and their fields are separated--- by commas. For example, this is a valid record literal:------ > { foo = True--- > , bar = 2--- > , baz = 4.2--- > }------ A record type is like a record literal except instead of specifying each--- field's value we specify each field's type. For example, the preceding--- record literal has the following record type:------ > { foo : Bool--- > , bar : Natural--- > , baz : Double--- > }------ If you want to specify an empty record literal, you must use @{=}@, which is--- special syntax reserved for empty records. If you want to specify the empty--- record type, then you use @{}@. If you forget which is which you can always--- ask the @dhall@ compiler to remind you of the type for each one:------ > $ dhall--- > {=}--- > <Ctrl-D>--- > {}--- > --- > {=}------ > $ dhall--- > {}--- > <Ctrl-D>--- > Type--- > --- > {}------ You can access a field of a record using the following syntax:------ > record.fieldName------ ... which means to access the value of the field named @fieldName@ from the--- @record@. For example:------ >>> input auto "{ foo = True, bar = 2, baz = 4.2 }.baz" :: IO Double--- 4.2------ ... and you can project out multiple fields into a new record using this--- syntax:------ > someRecord.{ field₀, field₁, … }------ For example:------ > $ dhall--- > { x = 1, y = True, z = "ABC" }.{ x, y }--- > <Ctrl-D>--- > { x : Natural, y : Bool }--- > --- > { x = 1, y = True }------ __Exercise__: What is the type of this record:------ > { foo = 1--- > , bar =--- > { baz = 2.0--- > , qux = True--- > }--- > }------ __Exercise__: Save the above code to a file named @./record@ and then try to--- access the value of the @baz@ field---- $functions------ The Dhall programming language also supports user-defined anonymous--- functions. For example, we can save the following anonymous function to a--- file:------ > $ cat > makeBools--- > \(n : Bool) ->--- > [ n && True, n && False, n || True, n || False ]--- > <Ctrl-D>------ ... or we can use Dhall's support for Unicode characters to use @λ@ (U+03BB)--- instead of @\\@ and @→@ (U+2192) instead of @->@ (for people who are into that--- sort of thing):------ > $ cat > makeBools--- > λ(n : Bool) →--- > [ n && True, n && False, n || True, n || False ]--- > <Ctrl-D>------ You can read this as a function of one argument named @n@ that has type--- @Bool@. This function returns a @List@ of @Bool@s. Each element of the--- @List@ depends on the input argument named @n@.------ The (ASCII) syntax for anonymous functions resembles the syntax for anonymous--- functions in Haskell. The only difference is that Dhall requires you to--- annotate the type of the function's input.------ You can import this function into Haskell, too:------ >>> makeBools <- input auto "./makeBools" :: IO (Bool -> Vector Bool)--- >>> makeBools True--- [True,False,True,True]------ The reason this works is that there is an `Interpret` instance for simple--- functions:------ > instance (Inject a, Interpret b) => Interpret (a -> b)------ Thanks to currying, this instance works for functions of multiple simple--- arguments:------ >>> dhallAnd <- input auto "λ(x : Bool) → λ(y : Bool) → x && y" :: IO (Bool -> Bool -> Bool)--- >>> dhallAnd True False--- False------ However, you can't convert anything more complex than that (like a polymorphic--- or higher-order function). You will need to apply those functions to their--- arguments within Dhall before converting their result to a Haskell value.------ Just like `Interpret`, you can derive `Inject` for user-defined data types:------ > {-# LANGUAGE DeriveAnyClass #-}--- > {-# LANGUAGE DeriveGeneric #-}--- > {-# LANGUAGE OverloadedStrings #-}--- > --- > module Main where--- > --- > import Dhall--- > --- > data Example0 = Example0 { foo :: Bool, bar :: Bool }--- > deriving (Generic, Inject)--- > --- > main = do--- > f <- input auto "λ(r : { foo : Bool, bar : Bool }) → r.foo && r.bar"--- > print (f (Example0 { foo = True, bar = False }) :: Bool)--- > print (f (Example0 { foo = True, bar = True }) :: Bool)------ The above program prints:------ > False--- > True---- $compiler------ We can also test our @makeBools@ function directly from the command line.--- This library comes with a command-line executable program named @dhall@ that--- you can use to both type-check files and convert them to a normal form. Our--- compiler takes a program on standard input and then prints the program's type--- to standard error followed by the program's normal form to standard output:------ > $ dhall--- > ./makeBools--- > <Ctrl-D>--- > ∀(n : Bool) → List Bool--- > --- > λ(n : Bool) → [ n, False, True, n ]------ The first line says that @makeBools@ is a function of one argument named @n@--- that has type @Bool@ and the function returns a @List@ of @Bool@s. The @∀@--- (U+2200) symbol is shorthand for the ASCII @forall@ keyword:------ > ∀(x : a) → b -- This type ...--- > --- > forall (x : a) → b -- ... is the same as this type------ ... and Dhall's @forall@ keyword behaves the same way as Haskell's @forall@--- keyword for input values that are @Type@s:------ > forall (x : Type) → b -- This Dhall type ...--- --- > forall x . b -- ... is the same as this Haskell type------ The part where Dhall differs from Haskell is that you can also use--- @∀@/@forall@ to give names to non-@Type@ arguments (such as the first--- argument to @makeBools@).------ The second line of Dhall's output is our program's normal form:------ > λ(n : Bool) → [ n, False, True, n ]------ ... and the interpreter was able to simplify our expression by noting that:------ * @n && True = n@--- * @n && False = False@--- * @n || True = True@--- * @n || False = n@------ To apply a function to an argument you separate the function and argument by--- whitespace (just like Haskell):------ @f x@------ You can read the above as \"apply the function @f@ to the argument @x@\". This--- means that we can \"apply\" our @./makeBools@ function to a @Bool@ argument--- like this:------ > $ dhall--- > ./makeBools True--- > <Ctrl-D>--- > List Bool--- > --- > [True, False, True, True]------ Remember that file paths are synonymous with their contents, so the above--- code is exactly equivalent to:--- --- > $ dhall--- > (λ(n : Bool) → [n && True, n && False, n || True, n || False]) True--- > <Ctrl-D>--- > List Bool--- > --- > [True, False, True, True]------ When you apply an anonymous function to an argument, you substitute the--- \"bound variable" with the function's argument:------ > Bound variable--- > ⇩--- > (λ(n : Bool) → ...) True--- > ⇧--- > Function argument------ So in our above example, we would replace all occurrences of @n@ with @True@,--- like this:------ > -- If we replace all of these `n`s with `True` ...--- > [n && True, n && False, n || True, n || False]--- >--- > -- ... then we get this:--- > [True && True, True && False, True || True, True || False]--- >--- > -- ... which reduces to the following normal form:--- > [True, False, True, True]------ Now that we've verified that our function type checks and works, we can use--- the same function within Haskell:------ >>> input auto "./makeBools True" :: IO (Vector Bool)--- [True,False,True,True]------ __Exercise__: Create a file named @getFoo@ that is a function of the following--- type:------ > ∀(r : { foo : Bool, bar : Text }) → Bool------ This function should take a single input argument named @r@ that is a record--- with two fields. The function should return the value of the @foo@ field.------ __Exercise__: Use the @dhall@ compiler to infer the type of the function you--- just created and verify that your function has the correct type------ __Exercise__: Use the @dhall@ compiler to apply your function to a sample--- record---- $strings--- Dhall supports ordinary string literals with Haskell-style escaping rules:------ > dhall--- > "Hello, \"world\"!"--- > <Ctrl-D>--- > Text--- >--- > "Hello, \"world\"!"------ ... and Dhall also supports Nix-style multi-line string literals:------ > dhall--- > ''--- > #!/bin/bash--- > --- > echo "Hi!"--- > ''--- > <Ctrl-D>--- > Text--- >--- > "\n#!/bin/bash\n\necho \"Hi!\"\n"------ These \"double single quote strings\" ignore all special characters, with one--- exception: if you want to include a @''@ in the string, you will need to--- escape it with a preceding @'@ (i.e. use @'''@ to insert @''@ into the final--- string).------ These strings also strip leading whitespace using the same rules as Nix.--- Specifically: \"it strips from each line a number of spaces equal to the--- minimal indentation of the string as a whole (disregarding the indentation--- of empty lines).\"------ You can also interpolate expressions into strings using @${...}@ syntax. For--- example:------ > $ dhall--- > let name = "John Doe"--- > in let age = 21--- > in "My name is ${name} and my age is ${Natural/show age}"--- > <Ctrl-D>--- > Text--- >--- > "My name is John Doe and my age is 21"------ Note that you can only interpolate expressions of type @Text@------ If you need to insert a @"${"@ into a string without interpolation then use--- @"''${"@ (same as Nix)------ > ''--- > for file in *; do--- > echo "Found ''${file}"--- > done--- > ''---- $combine------ You can combine two records, using either the @(//)@ operator or the--- @(/\\)@ operator.------ The @(//)@ operator (or @(⫽)@ U+2AFD) combines the fields of both records,--- preferring fields from the right record if they share fields in common:------ > $ dhall--- > { foo = 1, bar = "ABC" } // { baz = True }--- > <Ctrl-D>--- > { bar : Text, baz : Bool, foo : Natural }--- > --- > { bar = "ABC", baz = True, foo = 1 }--- > $ dhall--- > { foo = 1, bar = "ABC" } ⫽ { bar = True } -- Fancy unicode--- > <Ctrl-D>--- > { bar : Bool, foo : Natural }--- > --- > { bar = True, foo = 1 }------ Note that the order of record fields does not matter. The compiler--- automatically sorts the fields.------ The @(/\\)@ operator (or @(∧)@ U+2227) also lets you combine records, but--- behaves differently if the records share fields in common. The operator--- combines shared fields recursively if they are both records:------ > $ dhall--- > { foo = { bar = True }, baz = "ABC" } /\ { foo = { qux = 1.0 } }--- > <Ctrl-D>--- > { baz : Text, foo : { bar : Bool, qux : Double } }--- > --- > { baz = "ABC", foo = { bar = True, qux = 1.0 } }------ ... but fails with a type error if either shared field is not a record:------ > $ dhall--- > { foo = 1, bar = "ABC" } ∧ { foo = True }--- > <Ctrl-D>--- > Use "dhall --explain" for detailed errors--- > --- > Error: Field collision--- > --- > { foo = 1, bar = "ABC" } ∧ { foo = True }--- > --- > (stdin):1:1------ __Exercise__: Combine any record with the empty record. What do you expect--- to happen?------ You can analogously combine record types using the @//\\\\@ operator (or @(⩓)@ U+2A53):------ > $ dhall--- > { foo : Natural } ⩓ { bar : Text }--- > <Ctrl-D>--- > { foo : Natural, bar : Text }------ ... which behaves the exact same, except at the type level, meaning that the--- operator descends recursively into record types:------ > $ dhall--- > { foo : { bar : Text } } ⩓ { foo : { baz : Bool }, qux : Natural }--- > <Ctrl-D>--- > { foo : { bar : Text, baz : Bool }, qux : Natural }---- $let------ Dhall also supports @let@ expressions, which you can use to define--- intermediate values in the course of a computation, like this:------ > $ dhall--- > let x = "ha" in x ++ x--- > <Ctrl-D>--- > Text--- >--- > "haha"------ You can also annotate the types of values defined within a @let@ expression,--- like this:------ > $ dhall--- > let x : Text = "ha" in x ++ x--- > <Ctrl-D>--- > Text--- >--- > "haha"------ You need to nest @let@ expressions if you want to define more than one value--- in this way:------ > $ dhall--- > let x = "Hello, "--- > in let y = "world!"--- > in x ++ y--- > <Ctrl-D>--- > Text--- > --- > "Hello, world!"------ Dhall is whitespace-insensitive, so feel free to format things over multiple--- lines or indent in any way that you please.------ If you want to define a named function, just give a name to an anonymous--- function:------ > $ dhall--- > let twice = λ(x : Text) → x ++ x in twice "ha"--- > <Ctrl-D>--- > Text--- > --- > "haha"------ Unlike Haskell, Dhall does not support function arguments on the left-hand--- side of the equals sign, so this will not work:------ > $ dhall--- > let twice (x : Text) = x ++ x in twice "ha"--- > <Ctrl-D>--- > Error: Invalid input--- > --- > (stdin):1:11:--- > |--- > 1 | let twice (x : Text) = x ++ x in twice "ha"--- > | ^--- > unexpected '('--- > expecting ':', '=', or the rest of label------ The error message says that Dhall expected either a @(:)@ (i.e. the beginning--- of a type annotation) or a @(=)@ (the beginning of the assignment) and not a--- function argument.------ You can also use @let@ expressions to rename imports, like this:------ > $ dhall--- > let not = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not--- > in not True--- > <Ctrl-D>--- > Bool--- > --- > False------ ... or to define synonyms for types:------ > $ dhall <<< 'let Name : Type = Text in [ "John", "Mary" ] : List Name'--- > List Text--- > --- > [ "John", "Mary" ]------ __Exercise:__ What do you think the following code will normalize to?------ > let x = 1--- > in let x = 2--- > in x------ Test your guess using the @dhall@ compiler------ __Exercise:__ Now try to guess what this code will normalize to:------ > let x = "ha"--- > in let x = x ++ "ha"--- > in x------ __Exercise:__ What about this code?------ > let x = x ++ "ha"--- > in x---- $unions------ A union is a value that can be one of many alternative types of values. For--- example, the following union type:------ > < Left : Natural | Right : Bool >------ ... represents a value that can be either a @Natural@ or a @Bool@ value. If--- you are familiar with Haskell these are exactly analogous to Haskell's--- \"sum types\".------ Each alternative is associated with a tag that distinguishes that alternative--- from other alternatives. In the above example, the @Left@ tag is used for--- the @Natural@ alternative and the @Right@ tag is used for the @Bool@--- alternative.------ You can specify the value of a union constructor like this:------ > let Union = < Left : Natural | Right : Bool>--- > --- > [ Union.Left 0, Union.Right True ] : List Union------ In other words, you can access a union constructor as a field of a union--- type and use that constructor to wrap a value of a type appropriate for--- that alternative. In the above example, the @Left@ constructor can wrap--- a @Natural@ value and the @Right@ constructor can wrap a @Bool@ value. We--- can also confirm that by inspecting their type:------ > $ echo '< Left : Natural | Right : Bool>' > ./Union------ > $ dhall --annotate <<< '(./Union).Left'--- > < Left : Natural | Right : Bool >.Left--- > : ∀(Left : Natural) → < Left : Natural | Right : Bool >------ > $ dhall --annotate <<< '(./Union).Right'--- > < Left : Natural | Right : Bool >.Right--- > : ∀(Right : Bool) → < Left : Natural | Right : Bool >------ In other words, the @Left@ constructor is a function from a @Natural@ to a--- value of our @Union@ type and the @Right@ constructor is a separate function--- from a @Bool@ to that same @Union@ type.------ You can consume a union using the built-in @merge@ function. For example,--- suppose we want to convert our union to a @Bool@ but we want to behave--- differently depending on whether or not the union is a @Natural@ wrapped in--- the @Left@ constructor or a @Bool@ wrapped in the @Right@ constructor . We--- would write:------ > $ cat > process <<EOF--- > λ(union : < Left : Natural | Right : Bool >)--- > → let handlers =--- > { Left = Natural/even -- Natural/even is a built-in function--- > , Right = λ(b : Bool) → b--- > }--- > in merge handlers union : Bool--- > EOF------ Now our @./process@ function can handle both alternatives:------ > $ dhall <<< './process ((./Union).Left 3)'--- > False------ > $ dhall <<< './process ((./Union).Right True)'--- > True------ Every @merge@ has the following form:------ > merge handlers union : type------ ... where: ------ * @union@ is the union you want to consume--- * @handlers@ is a record with one function per alternative of the union--- * @type@ is the declared result type of the @merge@------ The @merge@ function selects which function to apply from the record based on--- which alternative the union selects:------ > merge { Foo = f, ... } (< … >.Foo x) = f x------ So, for example:------ > merge { Left = Natural/even, Right = λ(b : Bool) → b } (< Left : Natural | Right : Bool >.Left 3)--- > = Natural/even 3--- > = False------ ... and similarly:------ > merge { Left = Natural/even, Right = λ(b : Bool) → b } (< Left : Natural | Right : Bool >.Right True)--- > = (λ(b : Bool) → b) True--- > = True------ Notice that each handler has to return the same type of result (@Bool@ in--- this case).------ You can also store more than one value within alternatives using Dhall's--- support for anonymous records. You can nest an anonymous record within a--- union such as in this type:------ > < Empty : {} | Person : { name : Text, age : Natural } >------ You can even go a step further and omit the type of an alternative if it--- stores no data, like this:------ > < Empty | Person : { name : Text, age : Natural } >--------- This union of records resembles following equivalent Haskell data type:------ > data Example = Empty | Person { name :: Text, age :: Text }------ Empty alternatives like @Empty@ require no argument:------ > let MyType = < Empty | Person : { name : Text, age : Natural } >--- > --- > in [ MyType.Empty -- Note the absence of any argument to `Empty`--- > , MyType.Person { name = "John", age = 23 }--- > , MyType.Person { name = "Amy" , age = 25 }--- > ]------ ... and when you @merge@ an empty alternative the correspond handler takes no--- argument:------ > λ(x : < Empty | Person : { name : Text, age : Natural } >)--- > → merge--- > { Empty = "Unknown" -- Note the absence of a `λ`--- >--- > , Person =--- > λ(person : { name : Text, age : Natural })--- > → "Name: ${person.name}, Age: ${Natural/show person.age}"--- > }--- > x------ __Exercise__: Create a list of the following type with at least one element--- per alternative:------ > List < Left : Natural | Right : Double >---- $polymorphic------ The Dhall language supports defining polymorphic functions (a.k.a.--- \"generic\" functions) that work on more than one type of value. However,--- Dhall differs from Haskell by not inferring the types of these polymorphic--- functions. Instead, you must be explicit about what type of value the--- function is specialized to.------ Take, for example, Haskell's identity function named @id@:------ > id :: a -> a--- > id = \x -> x------ The identity function is polymorphic, meaning that `id` works on values of--- different types:------ >>> id 4--- 4--- >>> id True--- True------ The equivalent function in Dhall is:------ > λ(a : Type) → λ(x : a) → x------ Notice how this function takes two arguments instead of one. The first--- argument is the type of the second argument.------ Let's illustrate how this works by actually using the above function:------ > $ echo "λ(a : Type) → λ(x : a) → x" > id------ If we supply the function alone to the compiler we get the inferred type as--- the first line:--- --- > $ dhall--- > ./id--- > <Ctrl-D>--- > ∀(a : Type) → ∀(x : a) → a--- > --- > λ(a : Type) → λ(x : a) → x------ You can read the type @(∀(a : Type) → ∀(x : a) → a)@ as saying: \"This is the--- type of a function whose first argument is named @a@ and is a @Type@. The--- second argument is named @x@ and has type @a@ (i.e. the value of the first--- argument). The result also has type @a@.\"------ This means that the type of the second argument changes depending on what--- type we provide for the first argument. When we apply @./id@ to @Natural@,--- we create a function that expects an @Natural@ argument:------ > $ dhall--- > ./id Natural--- > <Ctrl-D>--- > ∀(x : Natural) → Natural--- > --- > λ(x : Natural) → x------ Similarly, when we apply @./id@ to @Bool@, we create a function that expects a--- @Bool@ argument:------ > $ dhall--- > ./id Bool--- > <Ctrl-D>--- > ∀(x : Bool) → Bool--- > --- > λ(x : Bool) → x------ We can then supply the final argument to each of those functions to show--- that they both work on their respective types:------ > $ dhall--- > ./id Natural 4--- > <Ctrl-D>--- > Natural--- > --- > 4------ > $ dhall--- > ./id Bool True--- > <Ctrl-D>--- > Bool--- > --- > True------ Built-in functions can also be polymorphic, too. For example, we can ask--- the compiler for the type of @List/reverse@, the function that reverses a--- list:------ > $ dhall--- > List/reverse--- > <Ctrl-D>--- > ∀(a : Type) → List a → List a--- > --- > List/reverse------ The first argument to @List/reverse@ is the type of the list to reverse:------ > $ dhall--- > List/reverse Bool--- > <Ctrl-D>--- > List Bool → List Bool--- > --- > List/reverse Bool------ ... and the second argument is the list to reverse:------ > $ dhall--- > List/reverse Bool [True, False]--- > <Ctrl-D>--- > List Bool--- > --- > [False, True] : List Bool------ Note that the second argument has no name. This type:------ > ∀(a : Type) → List a → List a------ ... is equivalent to this type:------ > ∀(a : Type) → ∀(_ : List a) → List a------ In other words, if you don't see the @∀@ symbol surrounding a function--- argument type then that means that the name of the argument is @"_"@. This--- is true even for user-defined functions:------ > $ dhall--- > λ(_ : Text) → 1--- > <Ctrl-D>--- > Text → Natural--- > --- > λ(_ : Text) → 1------ The type @(Text → Natural)@ is the same as @(∀(_ : Text) → Natural)@------ __Exercise__ : Translate Haskell's `flip` function to Dhall---- $total------ Dhall is a total programming language, which means that Dhall is not--- Turing-complete and evaluation of every Dhall program is guaranteed to--- eventually halt. There is no upper bound on how long the program might take--- to evaluate, but the program is guaranteed to terminate in a finite amount of--- time and not hang forever.------ This guarantees that all Dhall programs can be safely reduced to a normal--- form where as many functions have been evaluated as possible. In fact, Dhall--- expressions can be evaluated even if all function arguments haven't been fully--- applied. For example, the following program is an anonymous function:------ > $ dhall--- > \(n : Bool) -> 10 * 10--- > <Ctrl-D>--- > ∀(n : Bool) → Natural--- > --- > λ(n : Bool) → 100------ ... and even though the function is still missing the first argument named--- @n@ the compiler is smart enough to evaluate the body of the anonymous--- function ahead of time before the function has even been invoked.------ We can use the @map@ function from the Prelude to illustrate an even more--- complex example:------ > $ dhall--- > let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map--- > in λ(f : Natural → Natural) → Prelude/List/map Natural Natural f [1, 2, 3]--- > <Ctrl-D>--- > ∀(f : Natural → Natural) → List Natural--- > --- > λ(f : Natural → Natural) → [f 1, f 2, f 3] : List Natural------ Dhall can apply our function to each element of the list even before we specify--- which function to apply.------ The language will also never crash or throw any exceptions. Every--- computation will succeed and produce something, even if the result might be--- an @Optional@ value:------ > $ dhall--- > List/head Natural ([] : List Natural)--- > <Ctrl-D>--- > Optional Natural--- > --- > None Natural------ __Exercise__: The Dhall Prelude provides a @replicate@ function which you can--- find here:------ <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate>------ Test what the following Dhall expression normalizes to:------ > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate--- > in replicate 10------ __Exercise__: If you have a lot of spare time, try to \"break the compiler\" by--- finding an input expression that crashes or loops forever (and file a bug--- report if you succeed)---- $headers------ Sometimes you would like to provide additional request headers when importing--- Dhall expressions from URLs. For example, you might want to provide an--- authorization header or specify the expected content type.------ Dhall URL imports let you add or modify request headers with the @using@--- keyword:------ > https://example.com/example.dhall using ./headers------ ... where you can replace @./headers@ with any import that points to a Dhall--- expression of the following type:------ > List { header : Text, value : Text }------ For example, if you needed to specify the content type correctly in order to--- download the file, then your @./headers@ file might look like this:------ > $ cat headers--- > [ { header = "Accept", value = "application/dhall" } ]------ ... or if you needed to provide an authorization token to access a private--- GitHub repository, then your headers could look like this:------ > [ { header = "Authorization", value = "token ${env:GITHUB_TOKEN as Text}" } ]------ This would read your GitHub API token from the @GITHUB_TOKEN@ environment--- variable and supply that token in the authorization header.------ You cannot inline the headers within the same file as the URL. You must--- provide them as a separate import. That means that this is /not/ legal code:------ > http://example.com/example.dhall using [ { header = "Accept", value = "application/dhall" } ] -- NOT legal------ Dhall will forward imports if you import an expression from a URL that--- contains a relative import. For example, if you import an expression like--- this:--- --- > http://example.com/example.dhall using ./headers--- --- ... and @http:\/\/example.com/example.dhall@ contains a relative import of @./foo@--- then Dhall will import @http:\/\/example.com/foo@ using the same @./headers@ file.---- $integrity------ Sometimes you want to use share code while still ensuring that the imported--- value never changes and can't be corrupted by a malicious attacker. Dhall--- provides built-in support for hashing imported values to verify that their--- value never changes------ For example, suppose you save the following two files:------ > $ cat ./foo--- > ./bar sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b------ > $ cat ./bar--- > ./baz------ > $ cat ./baz--- > 1------ The first file named @./foo@ contains an example of an integrity check. You--- can add @sha256:XXX@ after any import (such as after @./bar@), where @XXX@ is--- an expected 64-character @sha256@ hash of the Dhall value. To be precise,--- the hash represents a @sha256@ hash of the UTF-8 encoding of a canonical text--- representation of the fully resolved and normalized abstract syntax tree of--- the imported expression.------ Dhall will verify that the expected hash matches the actual hash of the--- imported Dhall value and reject the import if there is a hash mismatch:------ > $ dhall <<< './foo'--- > Natural--- > --- > 1------ This implies that the hash only changes if the Dhall value changes. For--- example, if you add a comment to the @./bar@ file:------ > $ cat ./bar--- > -- This comment does not change the hash--- > ./baz------ ... then @./foo@ will still successfully import @./bar@ because the hash--- only depends on the normalized value and does not depend on meaningless--- changes to whitespace or comments:------ > $ dhall <<< './foo' # This still succeeds--- > Natural--- > --- > 1------ You can compute the Hash for any import by using the hash subcommand --- of this package. For example:------ > dhall hash <<< './bar'--- > sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b------ Then you can paste that output into your code after the import------ Now suppose that you you change the value of the @./baz@ file:------ > $ cat ./baz--- > 2------ ... then the @./foo@ file will fail to import @./bar@, even though the--- text of the @./bar@ file technically never changed:------ > dhall <<< './foo'--- > --- > Error: Import integrity check failed--- > --- > Expected hash:--- > --- > ↳ 6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b--- > --- > Actual hash:--- > --- > ↳ d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35------ This is because the @./bar@ file now represents a new value (@2@ instead of--- @1@), even though the text of the @./bar@ is still the same. Since the value--- changed the hash must change as well. However, we could change @./baz@ to:------ > $ cat baz--- > if True then 1 else 2------ ... and the import would succeed again because the final result is still @1@.------ The integrity hash ensures that your import's final meaning can never change,--- so an attacker can never compromise an imported value protected by a hash--- unless they can break SHA-256 encryption. The hash not only protects the--- file that you immediately import, but also protects every transitive import--- as well.------ You can also safely refactor your imported dependencies knowing that the--- refactor will not change your hash so long as your refactor is--- behavior-preserving. This provides an easy way to detect refactoring errors--- that you might accidentally introduce. The hash not only protects you--- from attackers, but also protects against human error, too!------ If you have a file which either doesn't already use hashed imports,--- or you changed some of the imports and want to update the hashes you can use the--- freeze command to either add or update hashes:------ > $ cat foo.dhall--- > let replicate =--- > https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate--- > in replicate 5--- > $--- > $ dhall freeze --inplace ./foo.dhall--- > $ cat ./foo.dhall--- > let replicate =--- > https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad--- > in replicate 5------ $rawText------ Sometimes you want to import the contents of a raw text file as a Dhall--- value of type `Text`. For example, one of the fields of a record might be--- the contents of a software license:------ > { package = "dhall"--- > , author = "Gabriel Gonzalez"--- > , license = ./LICENSE--- > }------ Normally if you wanted to import a text file you would need to wrap the--- contents of the file in double single-quotes, like this:------ > $ cat LICENSE--- > ''--- > Copyright (c) 2017 Gabriel Gonzalez--- > All rights reserved.--- > --- > ...--- > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--- > ''------ ... which does not work well if you need to reuse the same text file for--- other programs------ However, Dhall supports importing a raw text file by adding @as Text@ to the--- end of the import, like this:------ > { package = "dhall"--- > , author = "Gabriel Gonzalez"--- > , license = ./LICENSE as Text--- > }------ ... and then you can use the original text file unmodified:------ > $ cat LICENSE--- > Copyright (c) 2017 Gabriel Gonzalez--- > All rights reserved.--- > --- > ...--- > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- $format------ A format subcommand is also available that you can use to --- automatically format Dhall expressions. For example, we can take the--- following unformatted Dhall expression:------ > $ cat ./unformatted--- > λ(a : Type) → λ(kvss : List (List { index : Natural, value : a })) → --- > List/build { index : Natural, value : a } (λ(list : Type) → λ(cons : { --- > index : Natural, value : a } → list → list) → λ(nil : list) → --- > (List/fold (List { index : Natural, value : a }) kvss { count : Natural, diff : --- > Natural → list } (λ(kvs : List { index : Natural, value : a }) → λ(y : { --- > count : Natural, diff : Natural → list }) → { count = y.count + List/length --- > { index : Natural, value : a } kvs, diff = λ(n : Natural) → List/fold { --- > index : Natural, value : a } kvs list (λ(kvOld : { index : Natural, value : a --- > }) → λ(z : list) → cons { index = kvOld.index + n, value = kvOld.value } --- > z) (y.diff (n + List/length { index : Natural, value : a } kvs)) }) { count = --- > 0, diff = λ(_ : Natural) → nil }).diff 0)------ ... and run the expression through the formatter:------ > $ dhall format < ./unformatted--- > λ(a : Type)--- > → λ(kvss : List (List { index : Natural, value : a }))--- > → List/build--- > { index : Natural, value : a }--- > ( λ(list : Type)--- > → λ(cons : { index : Natural, value : a } → list → list)--- > → λ(nil : list)--- > → ( List/fold--- > (List { index : Natural, value : a })--- > kvss--- > { count : Natural, diff : Natural → list }--- > ( λ(kvs : List { index : Natural, value : a })--- > → λ(y : { count : Natural, diff : Natural → list })--- > → { count = y.count + List/length { index : Natural, value : a } kvs--- > , diff =--- > λ(n : Natural)--- > → List/fold--- > { index : Natural, value : a }--- > kvs--- > list--- > ( λ(kvOld : { index : Natural, value : a })--- > → λ(z : list)--- > → cons { index = kvOld.index + n, value = kvOld.value } z--- > )--- > (y.diff (n + List/length { index : Natural, value : a } kvs))--- > }--- > )--- > { count = 0, diff = λ(_ : Natural) → nil }--- > ).diff--- > 0--- > )------ The executable formats expressions without resolving, type-checking, or--- normalizing them:------ > $ dhall format--- > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate --- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1))--- > <Ctrl-D>--- > let replicate =--- > https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate --- > --- > in replicate--- > 5--- > (List (List Natural))--- > (replicate 5 (List Natural) (replicate 5 Natural 1))------ You can also use the formatter to modify files in place using the--- @--inplace@ flag (i.e. for formatting source code):------ > $ dhall format --inplace ./unformatted--- > $ cat ./unformatted--- > λ(a : Type)--- > → λ(kvss : List (List { index : Natural, value : a }))--- > → List/build--- > { index : Natural, value : a }--- > ( λ(list : Type)--- > → λ(cons : { index : Natural, value : a } → list → list)--- > → λ(nil : list)--- > → ( List/fold--- > (List { index : Natural, value : a })--- > kvss--- > { count : Natural, diff : Natural → list }--- > ( λ(kvs : List { index : Natural, value : a })--- > → λ(y : { count : Natural, diff : Natural → list })--- > → { count = y.count + List/length { index : Natural, value : a } kvs--- > , diff =--- > λ(n : Natural)--- > → List/fold--- > { index : Natural, value : a }--- > kvs--- > list--- > ( λ(kvOld : { index : Natural, value : a })--- > → λ(z : list)--- > → cons { index = kvOld.index + n, value = kvOld.value } z--- > )--- > (y.diff (n + List/length { index : Natural, value : a } kvs))--- > }--- > )--- > { count = 0, diff = λ(_ : Natural) → nil }--- > ).diff--- > 0--- > )------ Carefully note that the code formatter does not preserve all comments.--- Currently, the formatter only preserves leading comments and whitespace--- up until the last newline preceding the code. In other words:------ > $ dhall format--- > {- This comment will be preserved by the formatter -}--- > -- ... and this comment will be preserved, too--- > {- This comment will *NOT* be preserved -} 1--- > -- ... and this comment will also *NOT* be preserved--- > <Ctrl-D>--- > {- This comment will be preserved by the formatter -}--- > -- ... and this comment will be preserved, too--- > 1------ Note that you do not need to format the output of the--- @dhall@ interpreter. The interpreter already automatically formats--- multi-line expressions, too:------ > $ dhall--- > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate --- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1))--- > <Ctrl-D>--- > List (List (List Natural))--- > --- > [ [ [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > ]--- > : List (List Natural)--- > , [ [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > ]--- > : List (List Natural)--- > , [ [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > ]--- > : List (List Natural)--- > , [ [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > ]--- > : List (List Natural)--- > , [ [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > , [ 1, 1, 1, 1, 1 ] : List Natural--- > ]--- > : List (List Natural)--- > ]--- > : List (List (List Natural))---- $builtins------ Dhall is a restricted programming language that only supports simple built-in--- functions and operators. If you want to do anything fancier you will need to--- load your data into Haskell for further processing------ This section covers types, functions, and operators that are built into the--- language, meaning that you do not need to import any code to use them.--- Additionally, Dhall also comes with a Prelude (covered in the next section)--- hosted online that contains functions derived from these base utilities. The--- Prelude also re-exports all built-in functions for people who prefer--- consistency.------ The following documentation on built-ins is provided primarily as a reference.--- You don't need to read about every single built-in and you may want to skip to--- the following Prelude section.---- The language provides built-in support for the following primitive types:------ * @Bool@ values--- * @Natural@ values--- * @Integer@ values--- * @Double@ values--- * @Text@ values------ ... as well as support for the following derived types:------ * @List@s of values--- * @Optional@ values--- * Anonymous records--- * Anonymous unions---- $caveats------ Dhall differs in a few important ways from other programming languages, so--- you should keep the following caveats in mind:------ First, Dhall only supports addition and multiplication on @Natural@ numbers--- (i.e. non-negative integers), which are not the same type of number as--- @Integer@s (which can be negative). An @Integer@ number is a number prefixed--- with either a @+@ or @-@ symbol whereas a @Natural@ number has no leading--- sign. If you try to add or multiply two @Integer@s you will get a type--- error:------ > $ dhall--- > +2 + +2--- > <Ctrl-D>--- > Use "dhall --explain" for detailed errors--- > --- > Error: ❰+❱ only works on ❰Natural❱s--- > --- > +2 + +2--- > --- > (stdin):1:1------ In fact, there are no built-in functions for @Integer@s (or @Double@s). As--- far as the language is concerned they are opaque values that can only be--- shuffled around but not used in any meaningful way until they have been--- loaded into Haskell.------ Second, the equality @(==)@ and inequality @(!=)@ operators only work on--- @Bool@s. You cannot test any other types of values for equality.------ However, you can extend the language with your own built-ins using the--- Haskell API, as described in the next section.---- $extending------ You can use the Haskell API to extend the Dhall configuration language with--- new built-in functions. This section contains a simple Haskell recipe to add--- a new @Natural/equal@ built-in function of type:------ > Natural/equal : Natural → Natural → Bool------ To do so, we:--- --- * extend the type-checking context to include the type of @Natural/equal@--- * extend the normalizer to evaluate all occurrences of @Natural/equal@------ ... like this:------ > -- example.hs--- > --- > {-# LANGUAGE OverloadedStrings #-}--- > --- > module Main where--- > --- > import Dhall.Core (Expr(..), ReifiedNormalizer(..))--- > --- > import qualified Data.Text.IO--- > import qualified Dhall--- > import qualified Dhall.Context--- > import qualified Lens.Family as Lens--- > --- > main :: IO ()--- > main = do--- > text <- Data.Text.IO.getContents--- > --- > let startingContext = transform Dhall.Context.empty--- > where--- > transform = Dhall.Context.insert "Natural/equal" naturalEqualType--- > --- > naturalEqualType =--- > Pi "_" Natural (Pi "_" Natural Bool)--- > --- > let normalizer (App (App (Var "Natural/equal") (NaturalLit x)) (NaturalLit y)) =--- > Just (BoolLit (x == y))--- > normalizer _ =--- > Nothing--- > --- > let inputSettings = transform Dhall.defaultInputSettings--- > where--- > transform =--- > Lens.set Dhall.normalizer (ReifiedNormalizer (pure . normalizer))--- > . Lens.set Dhall.startingContext startingContext--- > --- > x <- Dhall.inputWithSettings inputSettings Dhall.auto text--- > --- > Data.Text.IO.putStrLn x------ Here is an example use of the above program:------ > $ ./example <<< 'if Natural/equal 2 (1 + 1) then "Equal" else "Not equal"'--- > Equal------ Note that existing Dhall tools that type-check expressions will reject--- expressions containing unexpected free variable such as @Natural/equal@:------ > $ dhall <<< 'Natural/equal 2 (1 + 1)'--- > --- > Use "dhall --explain" for detailed errors--- > --- > Error: Unbound variable--- > --- > Natural/equal --- > --- > (stdin):1:1------ You will need to either:--- --- * create your own parallel versions of these tools, or:--- * < https://github.com/dhall-lang/dhall-lang/blob/master/.github/CONTRIBUTING.md#how-do-i-change-the-language try to upstream your built-ins into the language>--- --- The general guidelines for adding new built-ins to the language are:--- --- * Keep built-ins easy to implement across language bindings--- * Prefer general purpose built-ins or built-ins appropriate for the task of program configuration--- * Design built-ins to catch errors as early as possible (i.e. when type-checking the configuration)---- $builtinOverview------ Each of the following sections provides an overview of builtin functions and--- operators for each type. For each function you get:------ * An example use of that function------ * A \"type judgement\" explaining when that function or operator is well--- typed------ For example, for the following judgement:------ > Γ ⊢ x : Bool Γ ⊢ y : Bool--- > ───────────────────────────--- > Γ ⊢ x && y : Bool------ ... you can read that as saying: "if @x@ has type @Bool@ and @y@ has type--- @Bool@, then @x && y@ has type @Bool@"------ Similarly, for the following judgement:------ > ─────────────────────────────────--- > Γ ⊢ Natural/even : Natural → Bool------ ... you can read that as saying: "@Natural/even@ always has type--- @Natural → Bool@"------ * Rules for how that function or operator behaves------ These rules are just equalities that come in handy when reasoning about code.--- For example, the section on @(&&)@ has the following rules:------ > (x && y) && z = x && (y && z)--- >--- > x && True = x--- >--- > True && x = x------ These rules are also a contract for how the compiler should behave. If you--- ever observe code that does not obey these rules you should file a bug--- report.---- $bool------ There are two values that have type @Bool@ named @True@ and @False@:------ > ───────────────--- > Γ ⊢ True : Bool------ > ────────────────--- > Γ ⊢ False : Bool------ The built-in operations for values of type @Bool@ are:------- $or------ Example:------ > $ dhall--- > True || False--- > <Ctrl-D>--- > Bool--- > --- > True------ Type:------ > Γ ⊢ x : Bool Γ ⊢ y : Bool--- > ───────────────────────────--- > Γ ⊢ x || y : Bool------ Rules:------ > (x || y) || z = x || (y || z)--- > --- > x || False = x--- > --- > False || x = x--- >--- > x || (y && z) = (x || y) && (x || z)--- > --- > x || True = True--- > --- > True || x = True---- $and------ Example:------ > $ dhall--- > True && False--- > <Ctrl-D>--- > Bool--- > --- > False------ Type:------ > Γ ⊢ x : Bool Γ ⊢ y : Bool--- > ───────────────────────────--- > Γ ⊢ x && y : Bool------ Rules:------ > (x && y) && z = x && (y && z)--- > --- > x && True = x--- > --- > True && x = x--- >--- > x && (y || z) = (x && y) || (x && z)--- > --- > x && False = False--- > --- > False && x = False---- $equal------ Example:------ > $ dhall--- > True == False--- > <Ctrl-D>--- > Bool--- > --- > False------ Type:------ > Γ ⊢ x : Bool Γ ⊢ y : Bool--- > ───────────────────────────--- > Γ ⊢ x == y : Bool------ Rules:------ > (x == y) == z = x == (y == z)--- > --- > x == True = x--- > --- > True == x = x--- >--- > x == x = True---- $unequal------ Example:------ > $ dhall--- > True != False--- > <Ctrl-D>--- > Bool--- > --- > True------ Type:------ > Γ ⊢ x : Bool Γ ⊢ y : Bool--- > ───────────────────────────--- > Γ ⊢ x != y : Bool------ Rules:------ > (x != y) != z = x != (y != z)--- > --- > x != False = x--- > --- > False != x = x--- >--- > x != x = False---- $ifthenelse------ Example:------ > $ dhall--- > if True then 3 else 5--- > <Ctrl-D>--- > Natural--- > --- > 3------ Type:------ > Γ ⊢ t : Type--- > ─────────────────────--- > Γ ⊢ b : Bool Γ ⊢ l : t Γ ⊢ r : t--- > ────────────────────────────────────--- > Γ ⊢ if b then l else r : t------ Rules:------ > if b then True else False = b--- > --- > if True then l else r = l--- > --- > if False then l else r = r---- $natural------ @Natural@ literals are non-negative numbers without any leading sign, like--- this:------ > 4 : Natural------ If you add a @+@ or @-@ sign then you get an @Integer@ literal, which is a--- different type of value---- $plus------ Example:------ > $ dhall--- > 2 + 3--- > <Ctrl-D>--- > Natural--- > --- > 5------ Type:------ > Γ ⊢ x : Natural Γ ⊢ y : Natural--- > ─────────────────────────────────--- > Γ ⊢ x + y : Natural------ Rules:------ > (x + y) + z = x + (y + z)--- >--- > x + 0 = x--- >--- > 0 + x = x---- $times------ Example:------ > $ dhall--- > 2 * 3--- > <Ctrl-D>--- > Natural--- > --- > 6------ Type:------ > Γ ⊢ x : Natural Γ ⊢ y : Natural--- > ─────────────────────────────────--- > Γ ⊢ x * y : Natural------ Rules:------ > (x * y) * z = x * (y * z)--- >--- > x * 1 = x--- >--- > 1 * x = x--- >--- > (x + y) * z = (x * z) + (y * z)--- >--- > x * (y + z) = (x * y) + (x * z)--- >--- > x * 0 = 0--- >--- > 0 * x = 0---- $even------ Example:------ > $ dhall--- > Natural/even 6--- > <Ctrl-D>--- > Bool--- > --- > True------ Type:------ > ─────────────────────────────────--- > Γ ⊢ Natural/even : Natural → Bool------ Rules:------ > Natural/even (x + y) = Natural/even x == Natural/even y--- >--- > Natural/even 0 = True--- >--- > Natural/even (x * y) = Natural/even x || Natural/even y--- >--- > Natural/even 1 = False---- $odd------ Example:------ > $ dhall--- > Natural/odd 6--- > <Ctrl-D>--- > Bool--- > --- > False------ Type:------ > ────────────────────────────────--- > Γ ⊢ Natural/odd : Natural → Bool------ Rules:------ > Natural/odd (x + y) = Natural/odd x != Natural/odd y--- >--- > Natural/odd 0 = False--- >--- > Natural/odd (x * y) = Natural/odd x && Natural/odd y--- >--- > Natural/odd 1 = True---- $isZero------ Example:------ > $ dhall--- > Natural/isZero 6--- > <Ctrl-D>--- > Bool--- > --- > False------ Type:------ > ───────────────────────────────────--- > Γ ⊢ Natural/isZero : Natural → Bool------ Rules:------ > Natural/isZero (x + y) = Natural/isZero x && Natural/isZero y--- >--- > Natural/isZero 0 = True--- >--- > Natural/isZero (x * y) = Natural/isZero x || Natural/isZero y--- >--- > Natural/isZero 1 = False---- $naturalFold------ Example:------ > $ dhall--- > Natural/fold 40 Text (λ(t : Text) → t ++ "!") "You're welcome"--- > <Ctrl-D>--- > Text--- > --- > "You're welcome!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"------ Type:------ > ──────────────────────────────────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ Natural/fold : Natural → ∀(natural : Type) → ∀(succ : natural → natural) → ∀(zero : natural) → natural------ Rules:--- --- > Natural/fold (x + y) n s z = Natural/fold x n s (Natural/fold y n s z)--- > --- > Natural/fold 0 n s z = z--- > --- > Natural/fold (x * y) n s = Natural/fold x n (Natural/fold y n s)--- > --- > Natural/fold 1 n s = s---- $naturalBuild------ Example:------ > $ dhall--- > Natural/build (λ(natural : Type) → λ(succ : natural → natural) → λ(zero : natural) → succ (succ zero))--- > <Ctrl-D>--- > Natural--- > --- > 2------ Type:------ > ─────────────────────────────────────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ Natural/build : (∀(natural : Type) → ∀(succ : natural → natural) → ∀(zero : natural) → natural) → Natural------ Rules:------ > Natural/fold (Natural/build x) = x--- >--- > Natural/build (Natural/fold x) = x---- $integer------ @Integer@ literals are prefixed with a @+@ (if they are non-negative) or a--- @-@ sign (if they are negative), like this:------ > +3 : Integer--- > -2 : Integer------ If you omit the sign then they are @Natural@ literals and not @Integer@s------ There are no built-in operations on @Integer@s. For all practical purposes--- they are opaque values within the Dhall language---- $double------ A @Double@ literal is a floating point value with at least one decimal--- place, such as:------ > -2.0 : Double--- > 3.14159 : Double------ There are no built-in operations on @Double@s. For all practical purposes--- they are opaque values within the Dhall language---- $text------ A @Text@ literal is just a sequence of characters enclosed in double quotes,--- like:------ > "ABC" : Text------ The only thing you can do with @Text@ values is concatenate them---- $textAppend------ Example:------ > $ dhall--- > "Hello, " ++ "world!"--- > <Ctrl-D>--- > Text--- > --- > "Hello, world!"------ Type:------ > Γ ⊢ x : Text Γ ⊢ y : Text--- > ───────────────────────────--- > Γ ⊢ x && y : Text------ Rules:------ > (x ++ y) ++ z = x ++ (y ++ z)--- > --- > x ++ "" = x--- > --- > "" ++ x = x---- $list------ Dhall @List@ literals are a sequence of values inside of brackets separated by--- commas:------ > Γ ⊢ t : Type Γ ⊢ x : t Γ ⊢ y : t ...--- > ──────────────────────────────────────────--- > Γ ⊢ [x, y, ... ] : List t------ Also, every empty @List@ must end with a mandatory type annotation, for example:------ > [] : List Natural------ The built-in operations on @List@s are:---- $listAppend------ Example:------ > $ dhall--- > [1, 2, 3] # [4, 5, 6]--- > <Ctrl-D>--- > List Natural--- >--- > [1, 2, 3, 4, 5, 6]------ Type:------ > Γ ⊢ x : List a Γ ⊢ y : List a--- > ─────────────────────────────────--- > Γ ⊢ x # y : List a------ Rules:------ > ([] : List a) # xs = xs--- >--- > xs # ([] : List a) = xs--- >--- > (xs # ys) # zs = xs # (ys # zs)---- $listFold------ Example:------ > $ dhall--- > List/fold Bool [True, False, True] Bool (λ(x : Bool) → λ(y : Bool) → x && y) True--- > <Ctrl-D>--- > Bool--- > --- > False------ Type:------ > ────────────────────────────────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ List/fold : ∀(a : Type) → List a → ∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list------ Rules:------ > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat--- >--- > List/fold a (Prelude/List/concat a xss) b c--- > = List/fold (List a) xss b (λ(x : List a) → List/fold a x b c)--- >--- > List/fold a ([] : List a) b c n = n--- >--- > List/fold a ([x] : List a) b c = c x---- $listBuild------ Example:------ > $ dhall--- > List/build Natural (λ(list : Type) → λ(cons : Natural → list → list) → λ(nil : list) → cons 1 (cons 2 (cons 3 nil)))--- > <Ctrl-D>--- > List Natural--- > --- > [1, 2, 3] : List Natural------ Type:------ > ───────────────────────────────────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ List/build : ∀(a : Type) → (∀(list : Type) → ∀(cons : a → list → list) → ∀(nil : list) → list) → List a------ Rules:------ > List/build t (List/fold t x) = x--- >--- > List/fold t (List/build t x) = x---- $listLength------ Example:------ > $ dhall--- > List/length Natural [1, 2, 3]--- > <Ctrl-D>--- > Natural--- > --- > 3------ Type:------ > ────────────────────────────────────────────────--- > Γ ⊢ List/length : ∀(a : Type) → List a → Natural------ Rules:------ > List/length t xs = List/fold t xs Natural (λ(_ : t) → λ(n : Natural) → n + 1) 0---- $listHead------ Example:------ > $ dhall--- > List/head Natural [1, 2, 3]--- > <Ctrl-D>--- > Optional Natural--- > --- > Some 1------ Type:------ > ───────────────────────────────────────────────--- > Γ ⊢ List/head ∀(a : Type) → List a → Optional a------ Rules:------ > let Prelude/Optional/head = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Optional/head--- > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat--- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap--- > let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map--- > --- > List/head a (Prelude/List/concat a xss) =--- > Prelude/Optional/head a (Prelude/List/map (List a) (Optional a) (List/head a) xss)--- > --- > List/head a ([x] : List a) = Some x--- > --- > List/head b (Prelude/List/concatMap a b f m)--- > = Prelude/Optional/concatMap a b (λ(x : a) → List/head b (f x)) (List/head a m)---- $listLast------ Example:------ > $ dhall--- > List/last Natural [1, 2, 3]--- > <Ctrl-D>--- > Optional Natural--- > --- > Some 1------ Type:------ > ─────────────────────────────────────────────────--- > Γ ⊢ List/last : ∀(a : Type) → List a → Optional a------ Rules:------ > let Prelude/Optional/last = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Optional/last--- > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat--- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap--- > let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map--- > --- > List/last a (Prelude/List/concat a xss) =--- > Prelude/Optional/last a (Prelude/List/map (List a) (Optional a) (List/last a) xss)--- > --- > List/last a ([x] : List a) = Some x--- > --- > List/last b (Prelude/List/concatMap a b f m)--- > = Prelude/Optional/concatMap a b (λ(x : a) → List/last b (f x)) (List/last a m)---- $listIndexed------ Example------ > $ dhall--- > List/indexed Text ["ABC", "DEF", "GHI"]--- > <Ctrl-D>--- > List { index : Natural, value : Text }--- > --- > [{ index = 0, value = "ABC" }, { index = 1, value = "DEF" }, { index = 2, value = "GHI" }] : List { index : Natural, value : Text }------ Type:------ > ─────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ List/indexed : ∀(a : Type) → List a → List { index : Natural, value : a }------ Rules:------ > let Prelude/List/shifted = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/shifted--- > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat--- > let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map--- > --- > List/indexed a (Prelude/List/concat a xss) =--- > Prelude/List/shifted a (Prelude/List/map (List a) (List { index : Natural, value : a }) (List/indexed a) xss)---- $listReverse------ Example:------ > $ dhall--- > List/reverse Natural [1, 2, 3]--- > <Ctrl-D>--- > List Natural--- > --- > [3, 2, 1] : List Natural------ Type:------ > ─────────────────────────────────────────────────--- > Γ ⊢ List/reverse : ∀(a : Type) → List a → List a------ Rules:------ > let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map--- > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat--- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap--- > --- > List/reverse a (Prelude/List/concat a xss)--- > = Prelude/List/concat a (List/reverse (List a) (Prelude/List/map (List a) (List a) (List/reverse a) xss))--- >--- > List/reverse a ([x] : List a) = [x] : List a--- >--- > List/reverse b (Prelude/List/concatMap a b f xs)--- > = Prelude/List/concatMap a b (λ(x : a) → List/reverse b (f x)) (List/reverse a xs)--- >--- > List/reverse a ([x, y] : List a) = [y, x] : List a---- $optional1------ Dhall @Optional@ literals are either @Some@ followed by a value:------ > Γ ⊢ x : t Γ ⊢ t : Type--- > ────────────────────────--- > Γ ⊢ Some x : Optional t------ ... or @None@ followed by a type:------ > ───────────────────────────────────--- > Γ ⊢ None : ∀(t : Type) → Optional t------ Note that `None` is a valid standalone function------ The built-in operations on @Optional@ values are:---- $optionalFold------ Example:------ > $ dhall--- > Optional/fold Text (Some "ABC") Text (λ(t : Text) → t) ""--- > <Ctrl-D>--- > Text--- > --- > "ABC"------ Type:------ > ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────--- > Γ ⊢ Optional/fold : ∀(a : Type) → Optional a → ∀(optional : Type) → ∀(some : a → optional) → ∀(none : optional) → optional------ Rules:------ > Optional/fold a (None a) o j n = n--- >--- > Optional/fold a (Some x) o j n = j x---- $prelude------ There is also a Prelude available at:------ <http://prelude.dhall-lang.org>------ ... which currenty redirects to:------ <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75>------ There is nothing \"official\" or \"standard\" about this Prelude other than--- the fact that it is mentioned in this tutorial. The \"Prelude\" is just a--- set of convenient utilities which didn't quite make the cut to be built into--- the language. Feel free to host your own custom Prelude if you want!------ If you visit the above link you can browse the Prelude, which has a few--- subdirectories. For example, the @Bool@ subdirectory has a @not@ file--- located here:------ <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not>------ The @not@ function is just a UTF8-encoded text file hosted online with the--- following contents------ > $ curl https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not--- > {---- > Flip the value of a `Bool`--- > --- > Examples:--- > --- > ```--- > ./not True = False--- > --- > ./not False = True--- > ```--- > -}--- > let not : Bool → Bool--- > = λ(b : Bool) → b == False--- > --- > in not------ The file could have been much shorter, like this:------ > λ(b : Bool) → b == False------ ... but all the functions exported from the Prelude try to be as--- self-documenting as possible by including:------ * the name of the function--- * the type of the function--- * documentation (including a few examples)------ The performance penalty for adding these helpful features is negligible.------ You can use this @not@ function either directly:------ > $ dhall--- > https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not True--- > <Ctrl-D>--- > Bool--- > --- > False------ ... or assign the URL to a shorter name:------ > $ dhall--- > let Bool/not = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not--- > in Bool/not True--- > <Ctrl-D>--- > Bool--- > --- > False------ Some functions in the Prelude just re-export built-in functions for--- consistency and documentation, such as @Prelude\/Natural\/even@, which--- re-exports the built-in @Natural/even@ function:------ > $ curl https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Natural/even--- > {---- > Returns `True` if a number if even and returns `False` otherwise--- > --- > Examples:--- > --- > ```--- > ./even 3 = False--- > --- > ./even 0 = True--- > ```--- > -}--- > let even : Natural → Bool--- > = Natural/even--- > --- > in even------ You can also clone the Prelude locally to your filesystem if you prefer--- using `git clone`, like this:------ > $ git clone https://github.com/dhall-lang/Prelude.git--- > $ tree Prelude--- > Prelude--- > ├── Bool--- > │ ├── and--- > │ ├── build--- > │ ├── even--- > │ ├── fold--- > │ ├── not--- > │ ├── odd--- > │ ├── or--- > │ ├── package.dhall--- > │ └── show--- > ├── Double--- > │ ├── package.dhall--- > │ └── show--- > ├── Integer--- > │ ├── package.dhall--- > │ └── show--- > ├── List--- > │ ├── all--- > │ ├── any--- > │ ├── build--- > │ ├── concat--- > │ ├── concatMap--- > │ ├── filter--- > │ ├── fold--- > │ ├── generate--- > │ ├── head--- > │ ├── indexed--- > │ ├── iterate--- > │ ├── last--- > │ ├── length--- > │ ├── map--- > │ ├── null--- > │ ├── package.dhall--- > │ ├── replicate--- > │ ├── reverse--- > │ ├── shifted--- > │ └── unzip--- > ├── Monoid--- > ├── Natural--- > │ ├── build--- > │ ├── enumerate--- > │ ├── even--- > │ ├── fold--- > │ ├── isZero--- > │ ├── odd--- > │ ├── package.dhall--- > │ ├── product--- > │ ├── show--- > │ ├── sum--- > │ └── toInteger--- > ├── Optional--- > │ ├── None--- > │ ├── Some--- > │ ├── all--- > │ ├── any--- > │ ├── build--- > │ ├── concat--- > │ ├── filter--- > │ ├── fold--- > │ ├── head--- > │ ├── last--- > │ ├── length--- > │ ├── map--- > │ ├── null--- > │ ├── package.dhall--- > │ ├── toList--- > │ └── unzip--- > ├── Record--- > │ ├── keyText--- > │ ├── keyValue--- > │ └── package.dhall--- > ├── Text--- > │ ├── concat--- > │ ├── concatMap--- > │ ├── concatMapSep--- > │ ├── concatSep--- > │ └── package.dhall--- > └── package.dhall--- > --- > 8 directories, 70 files------ Browse the Prelude online to learn more by seeing what functions are--- available and reading their inline documentation:------ <https://github.com/dhall-lang/Prelude>------ __Exercise__: Try to use a new Prelude function that has not been covered--- previously in this tutorial------ You can also import the entire Prelude as a single large record for--- convenience:------ > $ dhall--- > let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/package.dhall--- >--- > in λ(x : Text)--- > → Prelude.`List`.length Text (Prelude.`List`.replicate 10 Text x)--- > <Ctrl-D>--- > ∀(x : Text) → Natural--- >--- > λ(x : Text) → 10------ The organization of the package mirrors the layout of the Prelude, meaning--- that every directory is stored as a record whose children are the fields of--- that record.------ __Exercise__: Browse the Prelude by running:------ > $ dhall <<< 'https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/package.dhall'---- $conclusion------ By this point you should be able to use the Dhall configuration language to--- author, import, and program configuration files. If you run into any issues--- you can report them at:------ <https://github.com/dhall-lang/dhall-haskell/issues>------ You can also request features, support, or documentation improvements on the--- above issue tracker.------ If you would like to contribute to the Dhall project you can try to port Dhall--- to other languages besides Haskell so that Dhall configuration files can be--- read into those languages, too.---- $faq------ * Why do empty lists require a type annotation?------ Unlike Haskell, Dhall cannot infer a polymorphic type for the empty list--- because Dhall represents polymorphic values as functions of types, like this:------ > λ(a : Type) → [] : List a------ If the compiler treated an empty list literal as syntactic short-hand for--- the above polymorphic function then you'd get the unexpected behavior where--- a list literal is a function if the list has 0 elements but not a function--- otherwise.--- --- * Does Dhall support user-defined recursive types?------ No, but you can translate recursive code to non-recursive code by following--- this guide:------ <https://github.com/dhall-lang/dhall-lang/wiki/How-to-translate-recursive-code-to-Dhall How to translate recursive code to Dhall>+{-# LANGUAGE CPP #-}++{-| Dhall is a programming language specialized for configuration files. This+ module contains a tutorial explaining how to author configuration files+ using this language++ You might also be interested in the+ <https://docs.dhall-lang.org/tutorials/Language-Tour.html Language Tour>, a+ Haskell-agnostic tour of Dhall's language features.+-}+module Dhall.Tutorial (+ -- * Introduction+ -- $introduction++ -- * Types+ -- $types++ -- * Imports+ -- $imports++ -- * Lists+ -- $lists++ -- * Optional values+ -- $optional0++ -- * Records+ -- $records++ -- * Functions+ -- $functions++ -- * Compiler+ -- $compiler++ -- * Strings+ -- $strings++ -- * Combine+ -- $combine++ -- * Let expressions+ -- $let++ -- * Defaults+ -- $defaults++ -- * Unions+ -- $unions++ -- * Polymorphic functions+ -- $polymorphic++ -- * Total+ -- $total++ -- * Assertions+ -- $assertions++ -- * Headers+ -- $headers++ -- * Import integrity+ -- $integrity++ -- * Raw text+ -- $rawText++ -- * Formatting code+ -- $format++ -- * Built-in functions+ -- $builtins++ -- ** Caveats+ -- $caveats++ -- ** Extending the language+ -- $extending++ -- ** Substitutions+ -- $substitutions++ -- * Prelude+ -- $prelude++ -- * Limitations+ -- $limitations++ -- * Conclusion+ -- $conclusion++ -- * Frequently Asked Questions (FAQ)+ -- $faq+ ) where++import Data.Vector (Vector)+import Dhall++-- $setup+--+-- >>> :set -XOverloadedStrings++-- $introduction+--+-- The simplest way to use Dhall is to ignore the programming language features+-- and use it as a strongly typed configuration format. For example, suppose+-- that you create the following configuration file:+--+-- > -- ./config.dhall+-- > { foo = 1+-- > , bar = [3.0, 4.0, 5.0]+-- > }+--+-- You can read the above configuration file into Haskell using the following+-- code:+--+-- > -- example.hs+-- >+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > import Dhall+-- >+-- > data Example = Example { foo :: Natural, bar :: Vector Double }+-- > deriving (Generic, Show)+-- >+-- > instance FromDhall Example+-- >+-- > main :: IO ()+-- > main = do+-- > x <- input auto "./config.dhall"+-- > print (x :: Example)+--+-- __WARNING__: You must not instantiate FromDhall with a recursive type. See [Limitations](#limitations).+--+-- If you compile and run the above example, the program prints the corresponding+-- Haskell record:+--+-- > $ ./example+-- > Example {foo = 1, bar = [3.0,4.0,5.0]}+--+-- You can also load some types directly into Haskell without having to define a+-- record, like this:+--+-- >>> import Dhall+-- >>> :set -XOverloadedStrings+-- >>> input auto "True" :: IO Bool+-- True+--+-- The `Dhall.input` function can decode any value if we specify the value's+-- expected `Dhall.Type`:+--+-- > input+-- > :: Type a -- Expected type+-- > -> Text -- Dhall program+-- > -> IO a -- Decoded expression+--+-- ... and we can either specify an explicit type like `bool`:+--+-- > bool :: Type Bool+-- >+-- > input bool :: Text -> IO Bool+-- >+-- > input bool "True" :: IO Bool+--+-- >>> input bool "True"+-- True+--+-- ... or we can use `auto` to let the compiler infer what type to decode from+-- the expected return type:+--+-- > auto :: FromDhall a => Type a+-- >+-- > input auto :: FromDhall a => Text -> IO a+--+-- >>> input auto "True" :: IO Bool+-- True+--+-- You can see what types `auto` supports \"out-of-the-box\" by browsing the+-- instances for the `FromDhall` class. For example, the following instance+-- says that we can directly decode any Dhall expression that evaluates to a+-- @Bool@ into a Haskell `Prelude.Bool`:+--+-- > instance FromDhall Bool+--+-- ... which is why we could directly decode the string @\"True\"@ into the+-- value `True`.+--+-- There is also another instance that says that if we can decode a value of+-- type @a@, then we can also decode a @List@ of values as a `Vector` of @a@s:+--+-- > instance FromDhall a => FromDhall (Vector a)+--+-- Therefore, since we can decode a @Bool@, we must also be able to decode a+-- @List@ of @Bool@s, like this:+--+-- >>> input auto "[True, False]" :: IO (Vector Bool)+-- [True,False]+--+-- We could also specify what type to decode by providing an explicit+-- `Dhall.Type` instead of using `auto` with a type annotation:+--+-- >>> input (vector bool) "[True, False]"+-- [True,False]+--+-- __Exercise:__ Create a @./config.dhall@ file that the following program can+-- decode:+--+-- > {-# LANGUAGE DeriveAnyClass #-}+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > import Dhall+-- >+-- > data Person = Person { age :: Natural, name :: Text }+-- > deriving (Generic, FromDhall, Show)+-- >+-- > main :: IO ()+-- > main = do+-- > x <- input auto "./config.dhall"+-- > print (x :: Person)+--+-- __Exercise:__ Create a @./config.dhall@ file that the following program can+-- decode:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > import Data.Functor.Identity+-- > import Dhall+-- >+-- > instance FromDhall a => FromDhall (Identity a)+-- >+-- > main :: IO ()+-- > main = do+-- > x <- input auto "./config.dhall"+-- > print (x :: Identity Double)++-- $types+--+-- Suppose that we try to decode a value of the wrong type, like this:+--+-- >>> input auto "1" :: IO Bool+-- *** Exception:+-- ...Error...: Expression doesn't match annotation+-- ...+-- - Bool+-- + Natural+-- ...+-- 1│ 1 : Bool+-- ...+-- (input):1:1+-- ...+--+-- The interpreter complains because the string @\"1\"@ cannot be decoded into a+-- Haskell value of type `Prelude.Bool`. This part of the type error:+--+-- > - Bool+-- > + Natural+--+-- ... means that the expected type was @Bool@ but the inferred type of the+-- expression @1@ was @Natural@.+--+-- The code excerpt from the above error message has two components:+--+-- * the expression being type checked (i.e. @1@)+-- * the expression's expected type (i.e. @Bool@)+--+-- > Expression+-- > ⇩+-- > 1 : Bool+-- > ⇧+-- > Expected type+--+-- The @(:)@ symbol is how Dhall annotates values with their expected types.+-- This notation is equivalent to type annotations in Haskell using the @(::)@+-- symbol. Whenever you see:+--+-- > x : t+--+-- ... you should read that as \"we expect the expression @x@ to have type+-- @t@\". However, we might be wrong and if our expected type does not match the+-- expression's actual type then the type checker will complain.+--+-- In this case, the expression @1@ does not have type @Bool@ so type checking+-- fails with an exception.+--+-- __Exercise:__ Load the Dhall library into @ghci@ and run these commands to get+-- get a more detailed error message:+--+-- > >>> import Dhall+-- > >>> :set -XOverloadedStrings+-- > >>> detailed (input auto "1") :: IO Bool+-- > ...+--+-- ... then read the entire error message+--+-- __Exercise:__ Fix the type error, either by changing the value to decode or+-- changing the expected type++-- $imports+--+-- You might wonder why in some cases we can decode a configuration file:+--+-- >>> writeFile "bool" "True"+-- >>> input auto "./bool" :: IO Bool+-- True+--+-- ... and in other cases we can decode a value directly:+--+-- >>> input auto "True" :: IO Bool+-- True+--+-- This is because importing a configuration from a file is a special case of a+-- more general language feature: Dhall expressions can reference other+-- expressions by their file path.+--+-- To illustrate this, let's create three files:+--+-- > $ echo "True" > bool1+-- > $ echo "False" > bool2+-- > $ echo "./bool1 && ./bool2" > both+--+-- ... and read in all three files in a single expression:+--+-- >>> input auto "[ ./bool1 , ./bool2 , ./both ]" :: IO (Vector Bool)+-- [True,False,False]+--+-- Each file path is replaced with the Dhall expression contained within that+-- file. If that file contains references to other files then those references+-- are transitively resolved.+--+-- In other words: configuration files can reference other configuration files,+-- either by their relative or absolute paths. This means that we can split a+-- configuration file into multiple files, like this:+--+-- > -- ./config.dhall+-- > { foo = 1+-- > , bar = ./bar.dhall+-- > }+--+-- > -- ./bar.dhall+-- > [3.0, 4.0, 5.0]+--+-- ... which is equivalent to our original configuration:+--+-- > -- ./config.dhall+-- > { foo = 1+-- > , bar = [3.0, 4.0, 5.0]+-- > }+--+-- However, the Dhall language will forbid cycles in these file references. For+-- example, if we create the following cycle:+--+-- > $ echo './file1' > file2+-- > $ echo './file2' > file1+--+-- ... then the interpreter will reject the import:+--+-- >>> input auto "./file1" :: IO Natural+-- *** Exception:+-- ↳ ./file1+-- ↳ ./file2+-- ...+-- Cyclic import: ./file1+-- ...+--+-- You can also import expressions by URL. For example, you can find a Dhall+-- expression hosted at this GitHub URL:+--+-- <https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True>+--+-- > $ curl https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True+-- > True+--+-- ... and you can reference that expression either directly:+--+#if defined(WITH_HTTP) && defined(USE_HTTP_CLIENT_TLS) && defined(NETWORK_TESTS)+-- >>> input auto "https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool+-- True+#else+-- > >>> input auto "https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool+-- > True+#endif+--+-- ... or inside of a larger expression:+--+#if defined(WITH_HTTP) && defined(USE_HTTP_CLIENT_TLS) && defined(NETWORK_TESTS)+-- >>> input auto "False == https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool+-- False+#else+-- > >>> input auto "False == https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool+-- > False+#endif+--+-- You're not limited to hosting Dhall expressions on GitHub. You can host a+-- Dhall expression anywhere that you can host UTF8-encoded text on the web,+-- such as a pastebin, or your own web server.+--+-- You can also import Dhall expressions from environment variables, too:+--+-- >>> System.Environment.setEnv "FOO" "1"+-- >>> input auto "env:FOO" :: IO Natural+-- 1+--+-- You can import types, too. For example, we can change our @./bar@ file to:+--+-- > -- ./bar.dhall+-- > [3.0, 4.0, 5.0] : List ./type.dhall+--+-- ... then specify the type in a separate file:+--+-- > -- ./type.dhall+-- > Double+--+-- ... and everything still type checks:+--+-- > $ ./example+-- > Example {foo = 1, bar = [3.0,4.0,5.0]}+--+-- Note that imports should be terminated by whitespace or parentheses otherwise+-- you will get either an import error or a parse error, like this:+--+-- >>> writeFile "baz" "2.0"+-- >>> input auto "./baz: Double" :: IO Double+-- *** Exception:+-- ↳ ./baz:+-- ...+-- ...Error...: Missing file ...baz:+-- ...+--+-- This is because the parser thinks that @./baz:@ is a single token due to+-- the missing whitespace before the colon and tries to import a file named+-- @./baz:@, which does not exist. To fix the problem we have to add a space+-- after @./baz@:+--+-- >>> input auto "./baz : Double" :: IO Double+-- 2.0+--+-- __Exercise:__ There is a @not@ function hosted online here:+--+-- <https://prelude.dhall-lang.org/Bool/not>+--+-- Visit that link and read the documentation. Then try to guess what this+-- code returns:+--+-- > >>> input auto "https://prelude.dhall-lang.org/Bool/not https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool+-- > ???+--+-- Run the code to test your guess++-- $lists+--+-- You can store 0 or more values of the same type in a list, like this:+--+-- > [1, 2, 3]+--+-- Every list can be followed by the type of the list. The type annotation is+-- required for empty lists but optional for non-empty lists. You will get a+-- parse error if you provide an empty list without a type annotation:+--+-- >>> input auto "[]" :: IO (Vector Natural)+-- *** Exception:+-- ...Error...: Invalid input+-- ...+-- (input):1:3:+-- |+-- 1 | []+-- | ^+-- Empty list literal without annotation+-- ...+--+-- Also, list elements must all have the same type. You will get an error if+-- you try to store elements of different types in a list:+--+-- >>> input auto "[1, True, 3]" :: IO (Vector Natural)+-- *** Exception:+-- ...Error...: List elements should all have the same type+-- ...+-- - Natural+-- + Bool+-- ...+-- 1│ True+-- ...+-- (input):1:5+-- ...+--+-- __Exercise:__ Replace the @\"???\"@ with an expression that successfully+-- decodes to the specified type:+--+-- > >>> input auto "???" :: IO (Vector (Vector Natural))++-- $optional0+--+-- @Optional@ values are either of the form @Some value@ or @None type@.+--+-- For example, these are valid @Optional@ values:+--+-- > Some 1+-- >+-- > None Natural+--+-- ... which both have type @Optional Natural@+--+-- An @Optional@ corresponds to Haskell's `Maybe` type for decoding purposes:+--+-- >>> input auto "Some 1" :: IO (Maybe Natural)+-- Just 1+-- >>> input auto "None Natural" :: IO (Maybe Natural)+-- Nothing+--+-- __Exercise:__ Replace the @\"???\"@ with an expression that successfully+-- decodes to the specified type:+--+-- > >>> input auto "???" :: IO (Maybe (Maybe (Maybe Natural)))++-- $records+--+-- Record literals are delimited by curly braces and their fields are separated+-- by commas. For example, this is a valid record literal:+--+-- > { foo = True+-- > , bar = 2+-- > , baz = 4.2+-- > }+--+-- A record type is like a record literal except instead of specifying each+-- field's value we specify each field's type. For example, the preceding+-- record literal has the following record type:+--+-- > { foo : Bool+-- > , bar : Natural+-- > , baz : Double+-- > }+--+-- If you want to specify an empty record literal, you must use @{=}@, which is+-- special syntax reserved for empty records. If you want to specify the empty+-- record type, then you use @{}@. If you forget which is which you can always+-- ask the @dhall@ compiler to remind you of the type for each one:+--+-- > $ dhall type <<< '{=}'+-- > {}+--+-- > $ dhall type <<< '{}'+-- > Type+--+-- This is our first use of the @dhall@ command-line tool (provided by this+-- package), which provides a @type@ subcommand for inferring an expression's+-- type. By default the tool reads the expression on standard input and outputs+-- the type to standard output.+--+-- Note that @<<<@ is a feature specific to the Bash shell to feed a string to+-- a command's standard input. If you are using another shell, then you can+-- instead do this:+--+-- > $ echo '{=}' | dhall type+-- > {}+--+-- __Exercise__: Use the @dhall type@ command to infer the type of this record:+--+-- > -- ./nested.dhall+-- > { foo = 1+-- > , bar =+-- > { baz = 2.0+-- > , qux = True+-- > }+-- > }+--+-- You can specify nested fields using dot-separated keys, like this:+--+-- > { foo = 1, bar.baz = 2.0, bar.qux = True }+--+-- ... which is equivalent to:+--+-- > { foo = 1, bar = { baz = 2.0, qux = True } }+--+-- You can also access a field of a record using the following syntax:+--+-- > record.fieldName+--+-- ... which means to access the value of the field named @fieldName@ from the+-- @record@. For example:+--+-- >>> input auto "{ foo = True, bar = 2, baz = 4.2 }.baz" :: IO Double+-- 4.2+--+-- ... and you can project out multiple fields into a new record using this+-- syntax:+--+-- > someRecord.{ field₀, field₁, … }+--+-- For example:+--+-- > $ dhall <<< '{ x = 1, y = True, z = "ABC" }.{ x, y }'+-- > { x = 1, y = True }+--+-- This is our first example of using the @dhall@ command-line tool with no+-- subcommand (like @type@), which evaluates the provided expression. By+-- default, this reads the expression on standard input and outputs the+-- evaluated result on standard output.+--+-- __Exercise__: Save the above @./nested.dhall@ file and then try to access the+-- value of the @baz@ field. Test that this works by interpreting your code+-- using the @dhall@ command.+--+-- You can convert a record to a list of key-value pairs (a.k.a. a \"Map\") by+-- using the @toMap@ keyword. For example:+--+-- > $ dhall <<< 'toMap { foo = 1, bar = 2 }'+-- > [ { mapKey = "bar", mapValue = 2 }, { mapKey = "foo", mapValue = 1 } ]+--+-- This conversion only works if all field of the record have the same type.+-- This comes in handy when you need to convert a Dhall record to the Dhall+-- equivalent of a homogeneous map (i.e. Haskell's @"Data.Map"@).++-- $functions+--+-- The Dhall programming language also supports user-defined anonymous+-- functions. For example, we can save the following anonymous function to a+-- file:+--+-- > -- ./makeBools.dhall+-- > \(n : Bool) ->+-- > [ n && True, n && False, n || True, n || False ]+--+-- ... or we can use Dhall's support for Unicode characters to use @λ@ (U+03BB)+-- instead of @\\@ and @→@ (U+2192) instead of @->@ (for people who are into+-- that sort of thing):+--+-- > $ -- ./makeBools.dhall+-- > λ(n : Bool) →+-- > [ n && True, n && False, n || True, n || False ]+-- > <Ctrl-D>+--+-- We'll be sticking to ASCII for the remainder of the tutorial, though, while+-- still pointing out Unicode equivalents as we go.+--+-- You can read this as a function of one argument named @n@ that has type+-- @Bool@. This function returns a @List@ of @Bool@s. Each element of the+-- @List@ depends on the input argument named @n@.+--+-- The (ASCII) syntax for anonymous functions resembles the syntax for anonymous+-- functions in Haskell. The only difference is that Dhall requires you to+-- annotate the type of the function's input.+--+-- You can import this function into Haskell, too:+--+-- >>> makeBools <- input auto "./makeBools.dhall" :: IO (Bool -> Vector Bool)+-- >>> makeBools True+-- [True,False,True,True]+--+-- The reason this works is that there is an `FromDhall` instance for simple+-- functions:+--+-- > instance (ToDhall a, FromDhall b) => FromDhall (a -> b)+--+-- Thanks to currying, this instance works for functions of multiple simple+-- arguments:+--+-- >>> dhallAnd <- input auto "\\(x : Bool) -> \\(y : Bool) -> x && y" :: IO (Bool -> Bool -> Bool)+-- >>> dhallAnd True False+-- False+--+-- However, you can't convert anything more complex than that (like a polymorphic+-- or higher-order function). You will need to apply those functions to their+-- arguments within Dhall before converting their result to a Haskell value.+--+-- Just like `FromDhall`, you can derive `ToDhall` for user-defined data types:+--+-- > {-# LANGUAGE DeriveAnyClass #-}+-- > {-# LANGUAGE DeriveGeneric #-}+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > module Main where+-- >+-- > import Dhall+-- >+-- > data Example0 = Example0 { foo :: Bool, bar :: Bool }+-- > deriving (Generic, ToDhall)+-- >+-- > main = do+-- > f <- input auto "\\(r : { foo : Bool, bar : Bool }) -> r.foo && r.bar"+-- > print (f (Example0 { foo = True, bar = False }) :: Bool)+-- > print (f (Example0 { foo = True, bar = True }) :: Bool)+--+-- The above program prints:+--+-- > False+-- > True++-- $compiler+--+-- We can also test our @makeBools@ function directly from the command line.+-- This library comes with a command-line executable program named @dhall@ that+-- you can use to both type-check files and convert them to a normal form. Our+-- compiler takes a program on standard input and then prints the program's type+-- to standard error followed by the program's normal form to standard output:+--+-- > $ dhall --annotate <<< './makeBools.dhall'+-- > (λ(n : Bool) → [ n, False, True, n ]) : ∀(n : Bool) → List Bool+--+-- The @dhall@ command emits Unicode output by default, but you can switch to+-- ASCII output using the @--ascii@ flag:+--+-- > $ dhall --annotate --ascii <<< './makeBools.dhall'+-- > (\(n : Bool) -> [ n, False, True, n ]) : forall (n : Bool) -> List Bool+--+-- The @--annotate@ flag adds a type signature to the output to let us know+-- what type the interpreter inferred for our expression. The type signature+-- is @∀(n : Bool) → List Bool@ which says that @makeBools@ is a function of one+-- argument named @n@ that has type @Bool@ and the function returns a @List@ of+-- @Bool@s. The @∀@ (U+2200) symbol is shorthand for the ASCII @forall@+-- keyword:+--+-- > ∀(x : a) → b -- This type ...+-- >+-- > forall (x : a) -> b -- ... is the same as this type+--+-- ... and Dhall's @forall@ keyword behaves the same way as Haskell's @forall@+-- keyword for input values that are @Type@s:+--+-- > forall (x : Type) -> b -- This Dhall type ...+--+-- > forall x . b -- ... is the same as this Haskell type+--+-- The part where Dhall differs from Haskell is that you can also use+-- @∀@/@forall@ to give names to non-@Type@ arguments (such as the first+-- argument to @makeBools@).+--+-- This expression is our program's normal form:+--+-- > λ(n : Bool) → [ n, False, True, n ]+--+-- ... and the interpreter was able to simplify our expression by noting that:+--+-- * @n && True = n@+-- * @n && False = False@+-- * @n || True = True@+-- * @n || False = n@+--+-- To apply a function to an argument you separate the function and argument by+-- whitespace (just like Haskell):+--+-- @f x@+--+-- You can read the above as \"apply the function @f@ to the argument @x@\". This+-- means that we can \"apply\" our @./makeBools@ function to a @Bool@ argument+-- like this:+--+-- > $ dhall <<< './makeBools.dhall True'+-- > [True, False, True, True]+--+-- Remember that file paths are synonymous with their contents, so the above+-- code is exactly equivalent to:+--+-- > $ dhall <<< '(\(n : Bool) -> [n && True, n && False, n || True, n || False]) True'+-- > [True, False, True, True]+--+-- When you apply an anonymous function to an argument, you substitute the+-- \"bound variable" with the function's argument:+--+-- > Bound variable+-- > ⇩+-- > (\(n : Bool) -> ...) True+-- > ⇧+-- > Function argument+--+-- So in our above example, we would replace all occurrences of @n@ with @True@,+-- like this:+--+-- > -- If we replace all of these `n`s with `True` ...+-- > [n && True, n && False, n || True, n || False]+-- >+-- > -- ... then we get this:+-- > [True && True, True && False, True || True, True || False]+-- >+-- > -- ... which reduces to the following normal form:+-- > [True, False, True, True]+--+-- Now that we've verified that our function type checks and works, we can use+-- the same function within Haskell:+--+-- >>> input auto "./makeBools.dhall True" :: IO (Vector Bool)+-- [True,False,True,True]+--+-- __Exercise__: Create a file named @getFoo@ that is a function of the following+-- type:+--+-- > forall (r : { foo : Bool, bar : Text }) -> Bool+--+-- This function should take a single input argument named @r@ that is a record+-- with two fields. The function should return the value of the @foo@ field.+--+-- __Exercise__: Use the @dhall@ command to infer the type of the function you+-- just created and verify that your function has the correct type+--+-- __Exercise__: Use the @dhall@ command to apply your function to a sample+-- record++-- $strings+-- Dhall supports ordinary string literals with Haskell-style escaping rules:+--+-- > $ dhall+-- > "Hello, \"world\"!"+-- > <Ctrl-D>+-- > "Hello, \"world\"!"+--+-- ... and Dhall also supports Nix-style multi-line string literals:+--+-- > $ dhall+-- > ''+-- > #!/bin/bash+-- >+-- > echo "Hi!"+-- > ''+-- > <Ctrl-D>+-- > "\n#!/bin/bash\n\necho \"Hi!\"\n"+--+-- These \"double single quote strings\" ignore all special characters, with one+-- exception: if you want to include a @''@ in the string, you will need to+-- escape it with a preceding @'@ (i.e. use @'''@ to insert @''@ into the final+-- string).+--+-- These strings also strip leading whitespace using the same rules as Nix.+-- Specifically: \"it strips from each line a number of spaces equal to the+-- minimal indentation of the string as a whole (disregarding the indentation+-- of empty lines).\"+--+-- You can also interpolate expressions into strings using @${...}@ syntax. For+-- example:+--+-- > $ dhall+-- > let name = "John Doe"+-- > let age = 21+-- > in "My name is ${name} and my age is ${Natural/show age}"+-- > <Ctrl-D>+-- > "My name is John Doe and my age is 21"+--+-- Note that you can only interpolate expressions of type @Text@+--+-- If you need to insert a @"${"@ into a string without interpolation then use+-- @"''${"@ (same as Nix)+--+-- > ''+-- > for file in *; do+-- > echo "Found ''${file}"+-- > done+-- > ''++-- $combine+--+-- You can combine two records, using either the @(//)@ operator or the+-- @(/\\)@ operator.+--+-- The @(//)@ operator (or @(⫽)@ U+2AFD) combines the fields of both records,+-- preferring fields from the right record if they share fields in common:+--+-- > $ dhall+-- > { foo = 1, bar = "ABC" } // { baz = True }+-- > <Ctrl-D>+-- > { bar = "ABC", baz = True, foo = 1 }+-- > $ dhall+-- > { foo = 1, bar = "ABC" } ⫽ { bar = True } -- Fancy unicode+-- > <Ctrl-D>+-- > { bar = True, foo = 1 }+--+-- Note that the order of record fields does not matter. The compiler+-- automatically sorts the fields.+--+-- If you need to set or add a deeply nested field you can use the @with@+-- keyword, like this:+--+-- > $ dhall <<< '{ x.y = 1 } with x.z = True'+-- > { x = { y = 1, z = True } }+--+-- > $ dhall <<< '{ x.y = 1 } with x.y = 2'+-- > { x.y = 2 }+--+-- The @with@ keyword is syntactic sugar for the @//@ operator which follows+-- these rules:+--+-- > -- Nested case+-- > record with k.ks… = value ⇒ record // { k = record.k with ks… = value }+-- >+-- > -- Base case+-- > record with k = value ⇒ record // { k = value }+--+-- The @(/\\)@ operator (or @(∧)@ U+2227) also lets you combine records, but+-- behaves differently if the records share fields in common. The operator+-- combines shared fields recursively if they are both records:+--+-- > $ dhall+-- > { foo = { bar = True }, baz = "ABC" } /\ { foo = { qux = 1.0 } }+-- > <Ctrl-D>+-- > { baz = "ABC", foo = { bar = True, qux = 1.0 } }+--+-- ... but fails with a type error if either shared field is not a record:+--+-- > $ dhall+-- > { foo = 1, bar = "ABC" } /\ { foo = True }+-- > <Ctrl-D>+-- > Use "dhall --explain" for detailed errors+-- >+-- > Error: Field collision+-- >+-- > { foo = 1, bar = "ABC" } ∧ { foo = True }+-- >+-- > (input):1:1+--+-- __Exercise__: Combine any record with the empty record. What do you expect+-- to happen?+--+-- You can analogously combine record types using the @//\\\\@ operator (or @(⩓)@ U+2A53):+--+-- > $ dhall+-- > { foo : Natural } //\\ { bar : Text }+-- > <Ctrl-D>+-- > { foo : Natural, bar : Text }+--+-- ... which behaves the exact same, except at the type level, meaning that the+-- operator descends recursively into record types:+--+-- > $ dhall+-- > { foo : { bar : Text } } //\\ { foo : { baz : Bool }, qux : Natural }+-- > <Ctrl-D>+-- > { foo : { bar : Text, baz : Bool }, qux : Natural }++-- $let+--+-- Dhall also supports @let@ expressions, which you can use to define+-- intermediate values in the course of a computation, like this:+--+-- > $ dhall+-- > let x = "ha" in x ++ x+-- > <Ctrl-D>+-- > "haha"+--+-- You can also annotate the types of values defined within a @let@ expression,+-- like this:+--+-- > $ dhall+-- > let x : Text = "ha" in x ++ x+-- > <Ctrl-D>+-- > "haha"+--+-- You need to nest @let@ expressions if you want to define more than one value+-- in this way:+--+-- > $ dhall+-- > let x = "Hello, "+-- > let y = "world!"+-- > in x ++ y+-- > <Ctrl-D>+-- > "Hello, world!"+--+-- Dhall is whitespace-insensitive, so feel free to format things over multiple+-- lines or indent in any way that you please.+--+-- If you want to define a named function, just give a name to an anonymous+-- function:+--+-- > $ dhall+-- > let twice = \(x : Text) -> x ++ x in twice "ha"+-- > <Ctrl-D>+-- > "haha"+--+-- Unlike Haskell, Dhall does not support function arguments on the left-hand+-- side of the equals sign, so this will not work:+--+-- > $ dhall+-- > let twice (x : Text) = x ++ x in twice "ha"+-- > <Ctrl-D>+-- > Error: Invalid input+-- >+-- > (input):1:11:+-- > |+-- > 1 | let twice (x : Text) = x ++ x in twice "ha"+-- > | ^+-- > unexpected '('+-- > expecting ':', '=', or the rest of label+--+-- The error message says that Dhall expected either a @(:)@ (i.e. the beginning+-- of a type annotation) or a @(=)@ (the beginning of the assignment) and not a+-- function argument.+--+-- You can also use @let@ expressions to rename imports, like this:+--+-- > $ dhall+-- > let not = https://prelude.dhall-lang.org/Bool/not+-- > in not True+-- > <Ctrl-D>+-- > False+--+-- ... or to define synonyms for types:+--+-- > $ dhall <<< 'let Name : Type = Text in [ "John", "Mary" ] : List Name'+-- > List Text+-- >+-- > [ "John", "Mary" ]+--+-- __Exercise:__ What do you think the following code will normalize to?+--+-- > let x = 1+-- > let x = 2+-- > in x+--+-- Test your guess using the @dhall@ compiler+--+-- __Exercise:__ Now try to guess what this code will normalize to:+--+-- > let x = "ha"+-- > let x = x ++ "ha"+-- > in x+--+-- __Exercise:__ What about this code?+--+-- > let x = x ++ "ha"+-- > in x++-- $defaults+--+-- For records with a large number of defaultable fields you can use the+-- @::@ operator to auto-complete a record. For example:+--+-- > let greet =+-- > \(args : { greeting : Text, name : Text })+-- > -> "${args.greeting}, ${args.name}!"+-- >+-- > let Greeting =+-- > { Type = { greeting : Text, name : Text }+-- > , default = { greeting = "Hello", name = "John" }+-- > }+-- >+-- > in ''+-- > ${greet Greeting::{=}}+-- > ${greet Greeting::{ greeting = "Hola" }}+-- > ${greet Greeting::{ name = "Jane" }}+-- > ${greet Greeting::{ greeting = "Hola", name = "Jane" }}+-- > ''+--+-- This operator is syntactic sugar. Specifically an expression of the form:+--+-- > T::r+--+-- ... is equivalent to:+--+-- > (T.default // r) : T.Type+--+-- So, for example:+--+-- > Greeting::{ greeting = "Hola" }+--+-- ... is the same thing as:+--+-- > (Greeting.default // { greeting = "Hola" }) : Greeting.Type+--+-- ... which is the same thing as:+--+-- > ({ greeting = "Hello", name = "John" } // { greeting = "Hola" }) : { greeting : Text, name : Text }+--+-- ... which is the same thing as:+--+-- > { greeting = "Hola", name = "John" }++-- $unions+--+-- A union is a value that can be one of many alternative types of values. For+-- example, the following union type:+--+-- > < Left : Natural | Right : Bool >+--+-- ... represents a value that can be either a @Natural@ or a @Bool@ value. If+-- you are familiar with Haskell these are exactly analogous to Haskell's+-- \"sum types\" and the above type is equivalent to @Either Natural Bool@.+--+-- Each alternative is associated with a tag that distinguishes that alternative+-- from other alternatives. In the above example, the @Left@ tag is used for+-- the @Natural@ alternative and the @Right@ tag is used for the @Bool@+-- alternative.+--+-- You can specify the value of a union constructor like this:+--+-- > let Union = < Left : Natural | Right : Bool>+-- >+-- > in [ Union.Left 0, Union.Right True ]+--+-- In other words, you can access a union constructor as a field of a union+-- type and use that constructor to wrap a value of a type appropriate for+-- that alternative. In the above example, the @Left@ constructor can wrap+-- a @Natural@ value and the @Right@ constructor can wrap a @Bool@ value. We+-- can also confirm that by inspecting their type:+--+-- > $ echo '< Left : Natural | Right : Bool>' > ./Union+--+-- > $ dhall --annotate <<< '(./Union).Left'+-- > < Left : Natural | Right : Bool >.Left+-- > : ∀(Left : Natural) → < Left : Natural | Right : Bool >+--+-- > $ dhall --annotate <<< '(./Union).Right'+-- > < Left : Natural | Right : Bool >.Right+-- > : ∀(Right : Bool) → < Left : Natural | Right : Bool >+--+-- In other words, the @Left@ constructor is a function from a @Natural@ to a+-- value of our @Union@ type and the @Right@ constructor is a separate function+-- from a @Bool@ to that same @Union@ type.+--+-- You can consume a union using the built-in @merge@ function. For example,+-- suppose we want to convert our union to a @Bool@ but we want to behave+-- differently depending on whether or not the union is a @Natural@ wrapped in+-- the @Left@ constructor or a @Bool@ wrapped in the @Right@ constructor . We+-- would write:+--+-- > $ cat > process <<EOF+-- > \(union : < Left : Natural | Right : Bool >) ->+-- > let handlers =+-- > { Left = Natural/even -- Natural/even is a built-in function+-- > , Right = \(b : Bool) -> b+-- > }+-- > in merge handlers union+-- > EOF+--+-- Now our @./process@ function can handle both alternatives:+--+-- > $ dhall <<< './process ((./Union).Left 3)'+-- > False+--+-- > $ dhall <<< './process ((./Union).Right True)'+-- > True+--+-- Every @merge@ has the following form:+--+-- > merge handlers union [ : type ]+--+-- ... where:+--+-- * @union@ is the union you want to consume+-- * @handlers@ is a record with one function per alternative of the union+-- * @type@ is an optional declared result type of the @merge@+--+-- The @merge@ function selects which function to apply from the record based on+-- which alternative the union selects:+--+-- > merge { Foo = f, ... } (< … >.Foo x) = f x+--+-- So, for example:+--+-- > merge { Left = Natural/even, Right = \(b : Bool) -> b } (< Left : Natural | Right : Bool >.Left 3)+-- > = Natural/even 3+-- > = False+--+-- ... and similarly:+--+-- > merge { Left = Natural/even, Right = \(b : Bool) -> b } (< Left : Natural | Right : Bool >.Right True)+-- > = (\(b : Bool) -> b) True+-- > = True+--+-- Notice that each handler has to return the same type of result (@Bool@ in+-- this case).+--+-- You can also store more than one value within alternatives using Dhall's+-- support for anonymous records. You can nest an anonymous record within a+-- union such as in this type:+--+-- > < Empty : {} | Person : { name : Text, age : Natural } >+--+-- You can even go a step further and omit the type of an alternative if it+-- stores no data, like this:+--+-- > < Empty | Person : { name : Text, age : Natural } >+--+-- The above Dhall type resembles the following equivalent Haskell data type:+--+-- > data Example = Empty | Person { name :: Text, age :: Text }+--+-- Empty alternatives like @Empty@ require no argument:+--+-- > let Example = < Empty | Person : { name : Text, age : Natural } >+-- >+-- > in [ Example.Empty -- Note the absence of any argument to `Empty`+-- > , Example.Person { name = "John", age = 23 }+-- > , Example.Person { name = "Amy" , age = 25 }+-- > ]+--+-- ... and when you @merge@ an empty alternative the correspond handler takes no+-- argument:+--+-- > \(x : < Empty | Person : { name : Text, age : Natural } >) ->+-- > merge+-- > { Empty = "Unknown" -- Note the absence of an anonymous function+-- >+-- > , Person =+-- > \(person : { name : Text, age : Natural }) ->+-- > "Name: ${person.name}, Age: ${Natural/show person.age}"+-- > }+-- > x+--+-- __Exercise__: Create a list of the following type with at least one element+-- per alternative:+--+-- > List < Left : Natural | Right : Double >++-- $polymorphic+--+-- The Dhall language supports defining polymorphic functions (a.k.a.+-- \"generic\" functions) that work on more than one type of value. However,+-- Dhall differs from Haskell by not inferring the types of these polymorphic+-- functions. Instead, you must be explicit about what type of value the+-- function is specialized to.+--+-- Take, for example, Haskell's identity function named @id@:+--+-- > id :: a -> a+-- > id = \x -> x+--+-- The identity function is polymorphic, meaning that `id` works on values of+-- different types:+--+-- >>> id 4+-- 4+-- >>> id True+-- True+--+-- The equivalent function in Dhall is:+--+-- > \(a : Type) -> \(x : a) -> x+--+-- Notice how this function takes two arguments instead of one. The first+-- argument is the type of the second argument.+--+-- Let's illustrate how this works by actually using the above function:+--+-- > $ echo "\\(a : Type) -> \\(x : a) -> x" > id+--+-- Let's ask the interpreter for the type of this function:+-- the first line:+--+-- > $ dhall type <<< './id'+-- > ∀(a : Type) → ∀(x : a) → a+--+-- You can read the type @(∀(a : Type) → ∀(x : a) → a)@ as saying: \"This is the+-- type of a function whose first argument is named @a@ and is a @Type@. The+-- second argument is named @x@ and has type @a@ (i.e. the value of the first+-- argument). The result also has type @a@.\"+--+-- This means that the type of the second argument changes depending on what+-- type we provide for the first argument. When we apply @./id@ to @Natural@,+-- we create a function that expects an @Natural@ argument:+--+-- > $ dhall type <<< './id Natural'+-- > ∀(x : Natural) → Natural+--+-- Similarly, when we apply @./id@ to @Bool@, we create a function that expects a+-- @Bool@ argument:+--+-- > $ dhall type <<< './id Bool'+-- > ∀(x : Bool) → Bool+--+-- We can then supply the final argument to each of those functions to show+-- that they both work on their respective types:+--+-- > $ dhall <<< './id Natural 4'+-- > 4+--+-- > $ dhall <<< './id Bool True'+-- > True+--+-- Built-in functions can also be polymorphic, too. For example, we can ask+-- the compiler for the type of @List/reverse@, the function that reverses a+-- list:+--+-- > $ dhall --annotate+-- > List/reverse+-- > <Ctrl-D>+-- > List/reverse : ∀(a : Type) → List a → List a+--+-- The first argument to @List/reverse@ is the type of the list to reverse:+--+-- > $ dhall+-- > List/reverse Bool+-- > <Ctrl-D>+-- > List/reverse Bool : List Bool → List Bool+--+-- ... and the second argument is the list to reverse:+--+-- > $ dhall+-- > List/reverse Bool [True, False]+-- > <Ctrl-D>+-- > [False, True]+--+-- Note that the second argument has no name. This type:+--+-- > ∀(a : Type) → List a → List a+--+-- ... is equivalent to this type:+--+-- > ∀(a : Type) → ∀(_ : List a) → List a+--+-- In other words, if you don't see the @∀@ symbol surrounding a function+-- argument type then that means that the name of the argument is @"_"@. This+-- is true even for user-defined functions:+--+-- > $ dhall type <<< '\\(_ : Text) -> 1'+-- > Text → Natural+--+-- The type @Text → Natural@ is the same as @∀(_ : Text) → Natural@+--+-- __Exercise__ : Translate Haskell's `flip` function to Dhall++-- $total+--+-- Dhall is a total programming language, which means that Dhall is not+-- Turing-complete and evaluation of every Dhall program is guaranteed to+-- eventually halt. There is no upper bound on how long the program might take+-- to evaluate, but the program is guaranteed to terminate in a finite amount of+-- time and not hang forever.+--+-- This guarantees that all Dhall programs can be safely reduced to a normal+-- form where as many functions have been evaluated as possible. In fact, Dhall+-- expressions can be evaluated even if all function arguments haven't been fully+-- applied. For example, the following program is an anonymous function:+--+-- > $ dhall+-- > \(n : Bool) -> 10 * 10+-- > <Ctrl-D>+-- > λ(n : Bool) → 100+--+-- ... and even though the function is still missing the first argument named+-- @n@ the compiler is smart enough to evaluate the body of the anonymous+-- function ahead of time before the function has even been invoked.+--+-- We can use the @map@ function from the Prelude to illustrate an even more+-- complex example:+--+-- > $ dhall+-- > let List/map = https://prelude.dhall-lang.org/List/map+-- > in \(f : Natural → Natural) -> List/map Natural Natural f [1, 2, 3]+-- > <Ctrl-D>+-- > λ(f : Natural → Natural) → [f 1, f 2, f 3]+--+-- Dhall can apply our function to each element of the list even before we specify+-- which function to apply.+--+-- The language will also never crash or throw any exceptions. Every+-- computation will succeed and produce something, even if the result might be+-- an @Optional@ value:+--+-- > $ dhall <<< 'List/head Natural ([] : List Natural)'+-- > None Natural+--+-- __Exercise__: The Dhall Prelude provides a @replicate@ function which you can+-- find here:+--+-- <https://prelude.dhall-lang.org/List/replicate>+--+-- Test what the following Dhall expression normalizes to:+--+-- > let replicate = https://prelude.dhall-lang.org/List/replicate+-- > in replicate 10+--+-- __Exercise__: If you have a lot of spare time, try to \"break the compiler\"+-- by finding an input expression that crashes or loops forever (and file a bug+-- report if you succeed).++-- $assertions+--+-- You can add compile-time assertions which you can use to add tests to your+-- code. For example, we can add some tests to our @not@ function like this:+--+-- > let not+-- > : Bool -> Bool+-- > = \(b : Bool) -> b == False+-- >+-- > let example0 = assert : not False === True+-- >+-- > let example1 = assert : not True === False+-- >+-- > in not+--+-- The expression @assert : not False == True@ is a type-checking assertion+-- that two expressions have the same normal form. If the two expressions differ+-- then type-checking rejects the code.+--+-- For example, suppose that we change the example to add an incorrect assertion:+--+-- > -- ./test.dhall+-- >+-- > let not+-- > : Bool -> Bool+-- > = \(b : Bool) -> b == False+-- >+-- > let example0 = assert : not False === True+-- >+-- > let example1 = assert : not True === True -- Oops!+-- >+-- > in not+--+-- The type-checker then rejects the assertion with the following error message:+--+-- > $ dhall <<< './test.dhall'+-- >+-- > ↳ ./test.dhall+-- >+-- > Error: Assertion failed+-- >+-- > - False+-- > + True+-- >+-- > 7│ assert : not True === True -- Oops!+-- > 8│+-- >+-- > ./test.dhall:7:16+-- >+-- > 1│ ./test.dhall+-- >+-- > (input):1:1+--+-- You can compare expressions that contain variables, too, which is equivalent+-- to symbolic reasoning:+--+-- > $ dhall <<< '\(n : Natural) -> assert : n === (n + 0)'+-- > λ(n : Natural) → assert : n ≡ n+--+-- Dhall accepts this because the language has built-in support for normalizing+-- @n + 0@ to @n@, so both sides of the comparison normalize to the same value:+-- @n@.+--+-- Note that this sort of symbolic reasoning is limited and can only detect+-- equality of normal forms. Some equivalent expressions will be rejected+-- if they don't share the same normal form, such as these:+--+-- > $ dhall <<< '\(n : Natural) -> assert : Natural/even (n + n) === True'+-- >+-- > Use "dhall --explain" for detailed errors+-- >+-- > n : Natural+-- >+-- > Error: Assertion failed+-- >+-- > - … …+-- > + True+-- >+-- > 1│ assert : Natural/even (n + n) === True+-- >+-- > (input):1:19+--+-- Here the interpreter is not smart enough to simplify @Natural/even (n + n)@+-- to @True@ so the assertion fails.+--+-- If you prefer to use Unicode, then the Unicode equivalent of @===@ is @≡@+-- (U+2261).++-- $headers+--+-- Sometimes you would like to provide additional request headers when importing+-- Dhall expressions from URLs. For example, you might want to provide an+-- authorization header or specify the expected content type.+--+-- Dhall URL imports let you add or modify request headers with the @using@+-- keyword:+--+-- > https://example.com/example.dhall using ./headers+--+-- ... where you can replace @./headers@ with any import that points to a Dhall+-- expression of the following type:+--+-- > List { header : Text, value : Text }+--+-- For example, if you needed to specify the content type correctly in order to+-- download the file, then your @./headers@ file might look like this:+--+-- > $ cat headers+-- > [ { header = "Accept", value = "application/dhall" } ]+--+-- ... or if you needed to provide an authorization token to access a private+-- GitHub repository, then your headers could look like this:+--+-- > [ { header = "Authorization", value = "token ${env:GITHUB_TOKEN as Text}" } ]+--+-- This would read your GitHub API token from the @GITHUB_TOKEN@ environment+-- variable and supply that token in the authorization header.+--+-- You cannot inline the headers within the same file as the URL. You must+-- provide them as a separate import. That means that this is /not/ legal code:+--+-- > http://example.com/example.dhall using [ { header = "Accept", value = "application/dhall" } ] -- NOT legal+--+-- Dhall will forward imports if you import an expression from a URL that+-- contains a relative import. For example, if you import an expression like+-- this:+--+-- > http://example.com/example.dhall using ./headers+--+-- ... and @http:\/\/example.com/example.dhall@ contains a relative import of @./foo@+-- then Dhall will import @http:\/\/example.com/foo@ using the same @./headers@ file.++-- $integrity+--+-- Sometimes you want to use share code while still ensuring that the imported+-- value never changes and can't be corrupted by a malicious attacker. Dhall+-- provides built-in support for hashing imported values to verify that their+-- value never changes+--+-- For example, suppose you save the following two files:+--+-- > $ cat ./foo+-- > ./bar sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15+--+-- > $ cat ./bar+-- > ./baz+--+-- > $ cat ./baz+-- > 1+--+-- The first file named @./foo@ contains an example of an integrity check. You+-- can add @sha256:XXX@ after any import (such as after @./bar@), where @XXX@ is+-- an expected 64-character @sha256@ hash of the Dhall value. To be precise,+-- the hash represents a @sha256@ hash of the UTF-8 encoding of a canonical text+-- representation of the fully resolved and normalized abstract syntax tree of+-- the imported expression.+--+-- Dhall will verify that the expected hash matches the actual hash of the+-- imported Dhall value and reject the import if there is a hash mismatch:+--+-- > $ dhall <<< './foo'+-- > Natural+-- >+-- > 1+--+-- Any import protected by a semantic integrity check is automatically cached+-- locally underneath either @~\/.cache\/dhall\/1220${HASH}@ or+-- @${XDG_CACHE_HOME}\/dhall/1220${HASH}@ if you define the @XDG_CACHE_HOME@+-- environment variable.+--+-- For example, after you import @./foo@ the contents of `./bar` are locally+-- cached in a fully-evaluated and binary-encoded form which you can inspect by+-- running:+--+-- > $ dhall decode < ~/.cache/dhall/1220d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15+-- > 1+--+-- Subsequent attempts to resolve the same import will automatically retrieve+-- the import from the cache. This matters less for local imports, but comes in+-- handy for remote imports to avoid redownloading them.+--+-- The local cache takes precedence when resolving imports, so changing the+-- original import afterwards will have no affect until you update the hash.+-- From Dhall's point of view, the hash is the true address and the file path+-- is just a suggestion for how to obtain the import if it's not already cached.+--+-- You can disable the cache by setting @XDG_CACHE_HOME@ to `/var/empty` (an+-- empty and unwritable directory), like this:+--+-- > $ XDG_CACHE_HOME=/var/empty dhall <<< './foo'+-- > Natural+-- >+-- > 1+--+-- We'll use this trick to test changes to the protected import in the following+-- examples.+--+-- Now, suppose you add a comment to the @./bar@ file:+--+-- > $ cat ./bar+-- > -- This comment does not change the hash+-- > ./baz+--+-- ... then @./foo@ will still successfully import @./bar@ because the hash+-- only depends on the normalized value and does not depend on meaningless+-- changes to whitespace or comments:+--+-- > $ XDG_CACHE_HOME=/var/empty dhall <<< './foo' # This still succeeds+-- > Natural+-- >+-- > 1+--+-- You can compute the Hash for any import by using the hash subcommand+-- of this package. For example:+--+-- > $ dhall hash <<< './bar'+-- > sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15+--+-- Now suppose that you actually change the value of the @./baz@ file:+--+-- > $ cat ./baz+-- > 2+--+-- ... then the @./foo@ file will fail to import @./bar@, even though the+-- text of the @./bar@ file technically never changed:+--+-- > XDG_CACHE_HOME=/var/empty dhall <<< './foo'+-- >+-- > Error: Import integrity check failed+-- >+-- > Expected hash:+-- >+-- > ↳ d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15+-- >+-- > Actual hash:+-- >+-- > ↳ 4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb+--+-- This is because the @./bar@ file now represents a new value (@2@ instead of+-- @1@), even though the text of the @./bar@ file is still the same. Since the+-- value changed the hash must change as well. However, we could change @./baz@+-- to:+--+-- > $ cat baz+-- > if True then 1 else 2+--+-- ... and the import would now succeed again because the final result is @1@.+--+-- The integrity hash ensures that your import's final meaning can never change,+-- so an attacker can never compromise an imported value protected by a hash+-- unless they can break SHA-256 encryption. The hash not only protects the+-- file that you immediately import, but also protects every transitive import+-- as well.+--+-- You can also safely refactor your imported dependencies knowing that the+-- refactor will not change your hash so long as your refactor is+-- behavior-preserving. This provides an easy way to detect refactoring errors+-- that you might accidentally introduce. The hash not only protects you+-- from attackers, but also protects against human error, too!+--+-- If you have a file which either doesn't already use hashed imports,+-- or you changed some of the imports and want to update the hashes you can use the+-- freeze command to either add or update hashes:+--+-- > $ cat foo.dhall+-- > let replicate = https://prelude.dhall-lang.org/List/replicate+-- > in replicate 5+-- > $+-- > $ dhall freeze ./foo.dhall+-- > $ cat ./foo.dhall+-- > let replicate =+-- > https://prelude.dhall-lang.org/List/replicate sha256:d4250b45278f2d692302489ac3e78280acb238d27541c837ce46911ff3baa347+-- >+-- > in replicate 5++-- $rawText+--+-- Sometimes you want to import the contents of a raw text file as a Dhall+-- value of type `Dhall.Syntax.Text`. For example, one of the fields of a+-- record might be the contents of a software license:+--+-- > { package = "dhall"+-- > , author = "Gabriella Gonzalez"+-- > , license = ./LICENSE+-- > }+--+-- Normally if you wanted to import a text file you would need to wrap the+-- contents of the file in double single-quotes, like this:+--+-- > $ cat LICENSE+-- > ''+-- > Copyright (c) 2017 Gabriella Gonzalez+-- > All rights reserved.+-- >+-- > ...+-- > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+-- > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+-- > ''+--+-- ... which does not work well if you need to reuse the same text file for+-- other programs+--+-- However, Dhall supports importing a raw text file by adding @as Text@ to the+-- end of the import, like this:+--+-- > { package = "dhall"+-- > , author = "Gabriella Gonzalez"+-- > , license = ./LICENSE as Text+-- > }+--+-- ... and then you can use the original text file unmodified:+--+-- > $ cat LICENSE+-- > Copyright (c) 2017 Gabriella Gonzalez+-- > All rights reserved.+-- >+-- > ...+-- > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+-- > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++-- $format+--+-- A format subcommand is also available that you can use to+-- automatically format Dhall expressions. For example, we can take the+-- following unformatted Dhall expression:+--+-- > $ cat ./unformatted+-- > λ(a : Type) → λ(kvss : List (List { index : Natural, value : a })) →+-- > List/build { index : Natural, value : a } (λ(list : Type) → λ(cons : {+-- > index : Natural, value : a } → list → list) → λ(nil : list) →+-- > (List/fold (List { index : Natural, value : a }) kvss { count : Natural, diff :+-- > Natural → list } (λ(kvs : List { index : Natural, value : a }) → λ(y : {+-- > count : Natural, diff : Natural → list }) → { count = y.count + List/length+-- > { index : Natural, value : a } kvs, diff = λ(n : Natural) → List/fold {+-- > index : Natural, value : a } kvs list (λ(kvOld : { index : Natural, value : a+-- > }) → λ(z : list) → cons { index = kvOld.index + n, value = kvOld.value }+-- > z) (y.diff (n + List/length { index : Natural, value : a } kvs)) }) { count =+-- > 0, diff = λ(_ : Natural) → nil }).diff 0)+--+-- ... and run the expression through the formatter:+--+-- > $ dhall format < ./unformatted+-- > λ(a : Type) →+-- > λ(kvss : List (List { index : Natural, value : a })) →+-- > List/build+-- > { index : Natural, value : a }+-- > ( λ(list : Type) →+-- > λ(cons : { index : Natural, value : a } → list → list) →+-- > λ(nil : list) →+-- > ( List/fold+-- > (List { index : Natural, value : a })+-- > kvss+-- > { count : Natural, diff : Natural → list }+-- > ( λ(kvs : List { index : Natural, value : a }) →+-- > λ(y : { count : Natural, diff : Natural → list }) →+-- > { count =+-- > y.count + List/length { index : Natural, value : a } kvs+-- > , diff =+-- > λ(n : Natural) →+-- > List/fold+-- > { index : Natural, value : a }+-- > kvs+-- > list+-- > ( λ(kvOld : { index : Natural, value : a }) →+-- > λ(z : list) →+-- > cons+-- > { index = kvOld.index + n, value = kvOld.value }+-- > z+-- > )+-- > ( y.diff+-- > (n + List/length { index : Natural, value : a } kvs)+-- > )+-- > }+-- > )+-- > { count = 0, diff = λ(_ : Natural) → nil }+-- > ).diff+-- > 0+-- > )+--+-- The executable formats expressions without resolving, type-checking, or+-- normalizing them:+--+-- > $ dhall format+-- > let replicate = https://prelude.dhall-lang.org/List/replicate+-- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1))+-- > <Ctrl-D>+-- > let replicate = https://prelude.dhall-lang.org/List/replicate+-- >+-- > in replicate+-- > 5+-- > (List (List Natural))+-- > (replicate 5 (List Natural) (replicate 5 Natural 1))+--+-- You can also use the formatter to modify files in place:+--+-- > $ dhall format ./unformatted+--+-- Carefully note that the code formatter does not preserve all comments.+-- Currently, the formatter only preserves two types of comments:+--+-- * Leading comments at the beginning of the file+-- * Comments within a @let@ binding+--+-- For example:+--+-- > $ dhall format+-- > {- This comment will be preserved by the formatter -}+-- > -- ... and this comment will be preserved, too+-- > {- This comment will *NOT* be preserved -} 1+-- > -- ... and this comment will also *NOT* be preserved+-- > <Ctrl-D>+-- > {- This comment will be preserved by the formatter -}+-- > -- ... and this comment will be preserved, too+-- > 1+--+-- Also:+--+-- > let {- This comment will be preserved -}+-- > x {- This comment will also be preserved-} =+-- > {- ... and this one will be preserved, too -}+-- > 1+-- >+-- > in x+--+-- Note that you do not need to format the output of the+-- @dhall@ interpreter. The interpreter already automatically formats+-- multi-line expressions, too:+--+-- > $ dhall+-- > let replicate = https://prelude.dhall-lang.org/List/replicate+-- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1))+-- > <Ctrl-D>+-- > [ [ [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > ]+-- > , [ [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > ]+-- > , [ [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > ]+-- > , [ [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > ]+-- > , [ [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > , [ 1, 1, 1, 1, 1 ]+-- > ]+-- > ]++-- $builtins+--+-- Dhall is a restricted programming language that only supports simple built-in+-- functions and operators. If you want to do anything fancier you will need to+-- load your data into Haskell for further processing+--+-- This section covers types, functions, and operators that are built into the+-- language, meaning that you do not need to import any code to use them.+-- Additionally, Dhall also comes with a Prelude (covered in the next section)+-- hosted online that contains functions derived from these base utilities. The+-- Prelude also re-exports all built-in functions for people who prefer+-- consistency.+--+-- The language provides built-in support for the following primitive types:+--+-- * @Bool@ values+-- * @Natural@ values+-- * @Integer@ values+-- * @Double@ values+-- * @Text@ values+--+-- ... as well as support for the following derived types:+--+-- * @List@s of values+-- * @Optional@ values+-- * Anonymous records+-- * Anonymous unions+--+-- You can find an up-to-date list of available built-in functions and operators+-- here:+--+-- <https://docs.dhall-lang.org/references/Built-in-types.html>++-- $caveats+--+-- Dhall differs in a few important ways from other programming languages, so+-- you should keep the following caveats in mind:+--+-- First, Dhall only supports addition and multiplication on @Natural@ numbers+-- (i.e. non-negative integers), which are not the same type of number as+-- @Integer@s (which can be negative). An @Integer@ number is a number prefixed+-- with either a @+@ or @-@ symbol whereas a @Natural@ number has no leading+-- sign. If you try to add or multiply two @Integer@s you will get a type+-- error:+--+-- > $ dhall+-- > +2 + +2+-- > <Ctrl-D>+-- > Use "dhall --explain" for detailed errors+-- >+-- > Error: ❰+❱ only works on ❰Natural❱s+-- >+-- > +2 + +2+-- >+-- > (input):1:1+--+-- There are no built-in functions for @Integer@ arithmetic; however, conversion+-- to and from @Natural@s is possible usinng @Integer/clamp@, @Integer/negate@+-- and @Natural/toInteger@.+--+-- For @Double@s the situation is even more extreme: there are no built-in+-- functions other than @Double/show@. As far as the language is concerned they+-- are opaque values that can only be shuffled around but not used in any+-- meaningful way until they have been loaded into Haskell.+--+-- Second, the equality @(==)@ and inequality @(!=)@ operators only work on+-- @Bool@s. You cannot test any other types of values for equality.+--+-- However, you can extend the language with your own built-ins using the+-- Haskell API, as described in the next section.++-- $extending+--+-- You can use the Haskell API to extend the Dhall configuration language with+-- new built-in functions. This section contains a simple Haskell recipe to add+-- a new @Natural/equal@ built-in function of type:+--+-- > Natural/equal : Natural -> Natural -> Bool+--+-- To do so, we:+--+-- * extend the type-checking context to include the type of @Natural/equal@+-- * extend the normalizer to evaluate all occurrences of @Natural/equal@+--+-- ... like this:+--+-- > -- example.hs+-- >+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > module Main where+-- >+-- > import Dhall.Core (Expr(..), ReifiedNormalizer(..))+-- >+-- > import qualified Data.Text.IO+-- > import qualified Dhall+-- > import qualified Dhall.Context+-- > import qualified Lens.Family as Lens+-- >+-- > main :: IO ()+-- > main = do+-- > text <- Data.Text.IO.getContents+-- >+-- > let startingContext = transform Dhall.Context.empty+-- > where+-- > transform = Dhall.Context.insert "Natural/equal" naturalEqualType+-- >+-- > naturalEqualType =+-- > Pi "_" Natural (Pi "_" Natural Bool)+-- >+-- > let normalizer (App (App (Var "Natural/equal") (NaturalLit x)) (NaturalLit y)) =+-- > Just (BoolLit (x == y))+-- > normalizer _ =+-- > Nothing+-- >+-- > let inputSettings = transform Dhall.defaultInputSettings+-- > where+-- > transform =+-- > Lens.set Dhall.normalizer (Just (ReifiedNormalizer (pure . normalizer)))+-- > . Lens.set Dhall.startingContext startingContext+-- >+-- > x <- Dhall.inputWithSettings inputSettings Dhall.auto text+-- >+-- > Data.Text.IO.putStrLn x+--+-- Here is an example use of the above program:+--+-- > $ ./example <<< 'if Natural/equal 2 (1 + 1) then "Equal" else "Not equal"'+-- > Equal+--+-- Note that existing Dhall tools that type-check expressions will reject+-- expressions containing unexpected free variable such as @Natural/equal@:+--+-- > $ dhall <<< 'Natural/equal 2 (1 + 1)'+-- >+-- > Use "dhall --explain" for detailed errors+-- >+-- > Error: Unbound variable+-- >+-- > Natural/equal+-- >+-- > (input):1:1+--+-- You will need to either:+--+-- * create your own parallel versions of these tools, or:+-- * < https://github.com/dhall-lang/dhall-lang/blob/master/.github/CONTRIBUTING.md#how-do-i-change-the-language try to upstream your built-ins into the language>+--+-- The general guidelines for adding new built-ins to the language are:+--+-- * Keep built-ins easy to implement across language bindings+-- * Prefer general purpose built-ins or built-ins appropriate for the task of program configuration+-- * Design built-ins to catch errors as early as possible (i.e. when type-checking the configuration)++-- $substitutions+--+-- Substitutions are another way to extend the language.+--+-- Suppose we have the following Haskell datatype:+--+-- > data Result = Failure Integer | Success String+-- > deriving (Eq, Generic, Show)+-- >+-- > instance FromDhall Result+--+-- We can use it in Dhall like that:+--+-- > -- example.dhall+-- >+-- > let Result = < Failure : Integer | Success : Text >+-- > in Result.Failure +1+--+-- Right now it is quite easy to keep these two definitions (the one in Haskell source and the one in the Dhall file) synchronized:+-- If we implement a new feature in the Haskell source we update the corresponding type in the Dhall file.+-- But what happens if our application is growing and our Result type contains e.g. 10 unions with possible types embedded in it?+--+-- We can override the interpreter's @evaluateSettings@ with a custom set of+-- substitutions, like this:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > myexample :: IO Result+-- > myexample = let+-- > evaluateSettings = Lens.over Dhall.substitutions (Dhall.Map.insert "Result" resultType) Dhall.defaultEvaluateSettings+-- > in Dhall.inputFileWithSettings evaluateSettings resultDecoder "example.dhall"+--+-- Substitutions are a simple 'Dhall.Map.Map' mapping variables to expressions. The application of these substitutions reflect the order of the insertions in the substitution map:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > substitute (Dhall.Core.Var "Foo") (Dhall.Map.fromList [("Foo", Dhall.Core.Var "Bar"), ("Bar", Dhall.Core.BoolLit True)])+--+-- results in @Dhall.Core.Var \"Baz\"@ since we first substitute \"Foo\" with \"Bar\" and then the resulting \"Bar\" with the final @True@.+--+-- Notable differences to the other extensions of the builtin language:+--+-- * This approach works well with the inputFile/inputFileWithSettings functions while the let-wrapping will not.+--+-- * In contrast to the custom built-ins described above substitutions are made BEFORE the type-checking.++-- $prelude+--+-- There is also a Prelude available at:+--+-- <https://prelude.dhall-lang.org>+--+-- If you visit the above link you can browse the Prelude, which has a few+-- subdirectories. For example, the @Bool@ subdirectory has a @not@ file, which+-- you can reference using this URL:+--+-- <https://prelude.dhall-lang.org/Bool/not>+--+-- The @not@ function is just a UTF8-encoded text file hosted online with the+-- following contents+--+-- > $ dhall <<< 'https://prelude.dhall-lang.org/Bool/not as Text'+-- > ''+-- > {-+-- > Flip the value of a Bool+-- > -}+-- > let not : Bool → Bool = λ(b : Bool) → b == False+-- >+-- > let example0 = assert : not True ≡ False+-- >+-- > let example1 = assert : not False ≡ True+-- >+-- > in not+-- > ''+--+-- The file could have been much shorter, like this:+--+-- > λ(b : Bool) → b == False+--+-- ... but all the functions exported from the Prelude try to be as+-- self-documenting as possible by including:+--+-- * the name of the function+-- * the type of the function+-- * documentation+-- * tests+--+-- The performance penalty for adding these helpful features is negligible,+-- especially if you protect the import with a semantic integrity check because+-- then the import would be cached compactly as @λ(_ : Bool) → _ == False@.+--+-- You can use this @not@ function either directly:+--+-- > $ dhall+-- > https://prelude.dhall-lang.org/Bool/not True+-- > <Ctrl-D>+-- > False+--+-- ... or assign the URL to a shorter name:+--+-- > $ dhall+-- > let Bool/not = https://prelude.dhall-lang.org/Bool/not+-- > in Bool/not True+-- > <Ctrl-D>+-- > False+--+-- Some functions in the Prelude just re-export built-in functions for+-- consistency and documentation, such as @Prelude\/Natural\/even@, which+-- re-exports the built-in @Natural/even@ function:+--+-- > $ dhall <<< 'https://prelude.dhall-lang.org/Natural/even as Text'+-- > ''+-- > {-+-- > Returns `True` if a number if even and returns `False` otherwise+-- > -}+-- > let even : Natural → Bool = Natural/even+-- >+-- > let example0 = assert : even 3 ≡ False+-- >+-- > let example1 = assert : even 0 ≡ True+-- >+-- > in even+-- > ''+--+-- You can also clone the Prelude locally to your filesystem if you prefer+-- using `git clone`, like this:+--+-- > $ git clone https://github.com/dhall-lang/dhall-lang.git+-- > $ tree dhall-lang/Prelude+-- > dhall-lang/Prelude+-- > ├── Bool+-- > │ ├── and+-- > │ ├── build+-- > │ ├── even+-- > │ ├── fold+-- > │ ├── not+-- > │ ├── odd+-- > │ ├── or+-- > │ ├── package.dhall+-- > │ └── show+-- > ├── Double+-- > │ ├── package.dhall+-- > │ └── show+-- > ├── Function+-- > │ ├── compose+-- > │ └── package.dhall+-- > ├── Integer+-- > │ ├── package.dhall+-- > │ ├── show+-- > │ └── toDouble+-- > ├── JSON+-- > │ ├── Nesting+-- > │ ├── Tagged+-- > │ ├── Type+-- > │ ├── array+-- > │ ├── bool+-- > │ ├── keyText+-- > │ ├── keyValue+-- > │ ├── null+-- > │ ├── number+-- > │ ├── object+-- > │ ├── package.dhall+-- > │ ├── render+-- > │ └── string+-- > ├── List+-- > │ ├── all+-- > │ ├── any+-- > │ ├── build+-- > │ ├── concat+-- > │ ├── concatMap+-- > │ ├── default+-- > │ ├── empty+-- > │ ├── filter+-- > │ ├── fold+-- > │ ├── generate+-- > │ ├── head+-- > │ ├── indexed+-- > │ ├── iterate+-- > │ ├── last+-- > │ ├── length+-- > │ ├── map+-- > │ ├── null+-- > │ ├── package.dhall+-- > │ ├── replicate+-- > │ ├── reverse+-- > │ ├── shifted+-- > │ └── unzip+-- > ├── Location+-- > │ ├── Type+-- > │ └── package.dhall+-- > ├── Map+-- > │ ├── Entry+-- > │ ├── Type+-- > │ ├── empty+-- > │ ├── keyText+-- > │ ├── keyValue+-- > │ ├── keys+-- > │ ├── map+-- > │ ├── package.dhall+-- > │ └── values+-- > ├── Monoid+-- > ├── Natural+-- > │ ├── build+-- > │ ├── enumerate+-- > │ ├── equal+-- > │ ├── even+-- > │ ├── fold+-- > │ ├── greaterThan+-- > │ ├── greaterThanEqual+-- > │ ├── isZero+-- > │ ├── lessThan+-- > │ ├── lessThanEqual+-- > │ ├── odd+-- > │ ├── package.dhall+-- > │ ├── product+-- > │ ├── show+-- > │ ├── subtract+-- > │ ├── sum+-- > │ ├── toDouble+-- > │ └── toInteger+-- > ├── Optional+-- > │ ├── all+-- > │ ├── any+-- > │ ├── build+-- > │ ├── concat+-- > │ ├── default+-- > │ ├── filter+-- > │ ├── fold+-- > │ ├── head+-- > │ ├── last+-- > │ ├── length+-- > │ ├── map+-- > │ ├── null+-- > │ ├── package.dhall+-- > │ ├── toList+-- > │ └── unzip+-- > ├── Text+-- > │ ├── concat+-- > │ ├── concatMap+-- > │ ├── concatMapSep+-- > │ ├── concatSep+-- > │ ├── default+-- > │ ├── defaultMap+-- > │ ├── package.dhall+-- > │ └── show+-- > ├── XML+-- > │ ├── Type+-- > │ ├── attribute+-- > │ ├── element+-- > │ ├── emptyAttributes+-- > │ ├── leaf+-- > │ ├── package.dhall+-- > │ ├── render+-- > │ └── text+-- > └── package.dhall+--+-- Browse the Prelude online to learn more by seeing what functions are+-- available and reading their inline documentation:+--+-- <https://prelude.dhall-lang.org>+--+-- __Exercise__: Try to use a new Prelude function that has not been covered+-- previously in this tutorial+--+-- You can also import the entire Prelude as a single large record for+-- convenience:+--+-- > $ dhall+-- > let Prelude = https://prelude.dhall-lang.org/package.dhall+-- >+-- > in \(x : Text) ->+-- > Prelude.List.length Text (Prelude.List.replicate 10 Text x)+-- > <Ctrl-D>+-- > ∀(x : Text) → Natural+-- >+-- > λ(x : Text) → 10+--+-- The organization of the package mirrors the layout of the Prelude, meaning+-- that every directory is stored as a record whose children are the fields of+-- that record.+--+-- __Exercise__: Browse the Prelude by running:+--+-- > $ dhall <<< 'https://prelude.dhall-lang.org/package.dhall'++-- $limitations+-- #limitations#+--+-- `FromDhall` has a limitiation: It won't work for recursive types.+-- If you instantiate these using their Generic instance you end up with one of+-- the following two cases:+--+-- If the type appears in it's own definition like+--+-- > data Foo = Foo Foo+-- > deriving Generic+-- >+-- > instance FromDhall Foo+--+-- the resulting Decoder will throw an exception /ON USAGE/.+-- However, if the recursion is indirect like+--+-- > data Foo = Foo Bar+-- > deriving Generic+-- >+-- > instance FromDhall Foo+-- >+-- > data Bar = Bar Foo+-- > deriving Generic+-- >+-- > instance FromDhall Bar+--+-- the resulting Decoder will __NOT TERMINATE__ /ON USAGE/.++-- $conclusion+--+-- By this point you should be able to use the Dhall configuration language to+-- author, import, and program configuration files. If you run into any issues+-- you can report them at:+--+-- <https://github.com/dhall-lang/dhall-haskell/issues>+--+-- Also, you might want to check out the+-- <https://docs.dhall-lang.org/tutorials/Language-Tour.html Language Tour>, a+-- more comprehensive tour of Dhall which may cover features missing from this+-- Haskell tutorial.+--+-- You can also request features, support, or documentation improvements on the+-- above issue tracker.+--+-- If you would like to contribute to the Dhall project you can try to port+-- Dhall to languages that do not yet have Dhall integrations so that Dhall configuration files+-- can be read into those languages, too.++-- $faq+--+-- <https://docs.dhall-lang.org/howtos/FAQ.html>
@@ -1,3926 +1,4851 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# OPTIONS_GHC -Wall #-}---- | This module contains the logic for type checking Dhall code--module Dhall.TypeCheck (- -- * Type-checking- typeWith- , typeOf- , typeWithA- , checkContext-- -- * Types- , Typer- , X(..)- , TypeError(..)- , DetailedTypeError(..)- , TypeMessage(..)- ) where--import Control.Applicative (empty)-import Control.Exception (Exception)-import Data.Data (Data(..))-import Data.Foldable (forM_, toList)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Monoid (First(..))-import Data.Sequence (Seq, ViewL(..))-import Data.Semigroup (Semigroup(..))-import Data.Set (Set)-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty(..))-import Data.Traversable (forM)-import Data.Typeable (Typeable)-import Dhall.Binary (FromTerm(..), ToTerm(..))-import Dhall.Core (Binding(..), Const(..), Chunks(..), Expr(..), Var(..))-import Dhall.Context (Context)-import Dhall.Pretty (Ann, layoutOpts)--import qualified Data.Foldable-import qualified Data.Sequence-import qualified Data.Set-import qualified Data.Text as Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty-import qualified Dhall.Context-import qualified Dhall.Core-import qualified Dhall.Diff-import qualified Dhall.Map-import qualified Dhall.Set-import qualified Dhall.Pretty.Internal-import qualified Dhall.Util--traverseWithIndex_ :: Applicative f => (Int -> a -> f b) -> Seq a -> f ()-traverseWithIndex_ k xs =- Data.Foldable.sequenceA_ (Data.Sequence.mapWithIndex k xs)--axiom :: Const -> Either (TypeError s a) Const-axiom Type = return Kind-axiom Kind = return Sort-axiom Sort = Left (TypeError Dhall.Context.empty (Const Sort) Untyped)--rule :: Const -> Const -> Either () Const-rule Type Type = return Type-rule Kind Type = return Type-rule Sort Type = return Type-rule Kind Kind = return Kind-rule Sort Kind = return Sort-rule Sort Sort = return Sort--- This forbids dependent types. If this ever changes, then the fast--- path in the Let case of typeWithA will become unsound.-rule _ _ = Left ()--{-| Type-check an expression and return the expression's type if type-checking- succeeds or an error if type-checking fails-- `typeWith` does not necessarily normalize the type since full normalization- is not necessary for just type-checking. If you actually care about the- returned type then you may want to `Dhall.Core.normalize` it afterwards.-- The supplied `Context` records the types of the names in scope. If- these are ill-typed, the return value may be ill-typed.--}-typeWith :: Context (Expr s X) -> Expr s X -> Either (TypeError s X) (Expr s X)-typeWith ctx expr = do- checkContext ctx- typeWithA absurd ctx expr--{-| Function that converts the value inside an `Embed` constructor into a new- expression--}-type Typer a = forall s. a -> Expr s a--{-| Generalization of `typeWith` that allows type-checking the `Embed`- constructor with custom logic--}-typeWithA- :: (Eq a, Pretty a)- => Typer a- -> Context (Expr s a)- -> Expr s a- -> Either (TypeError s a) (Expr s a)-typeWithA tpa = loop- where- loop _ (Const c ) = do- fmap Const (axiom c)- loop ctx e@(Var (V x n) ) = do- case Dhall.Context.lookup x n ctx of- Nothing -> Left (TypeError ctx e (UnboundVariable x))- Just a -> do- -- Note: no need to typecheck the value we're- -- returning; that is done at insertion time.- return a- loop ctx (Lam x _A b ) = do- _ <- loop ctx _A- let ctx' = fmap (Dhall.Core.shift 1 (V x 0)) (Dhall.Context.insert x (Dhall.Core.normalize _A) ctx)- _B <- loop ctx' b- let p = Pi x _A _B- _t <- loop ctx p- return p- loop ctx e@(Pi x _A _B ) = do- tA <- fmap Dhall.Core.normalize (loop ctx _A)- kA <- case tA of- Const k -> return k- _ -> Left (TypeError ctx e (InvalidInputType _A))-- let ctx' = fmap (Dhall.Core.shift 1 (V x 0)) (Dhall.Context.insert x (Dhall.Core.normalize _A) ctx)- tB <- fmap Dhall.Core.normalize (loop ctx' _B)- kB <- case tB of- Const k -> return k- _ -> Left (TypeError ctx' e (InvalidOutputType _B))-- case rule kA kB of- Left () -> Left (TypeError ctx e (NoDependentTypes _A _B))- Right k -> Right (Const k)- loop ctx e@(App f a ) = do- tf <- fmap Dhall.Core.normalize (loop ctx f)- (x, _A, _B) <- case tf of- Pi x _A _B -> return (x, _A, _B)- _ -> Left (TypeError ctx e (NotAFunction f tf))- _A' <- loop ctx a- if Dhall.Core.judgmentallyEqual _A _A'- then do- let a' = Dhall.Core.shift 1 (V x 0) a- let _B' = Dhall.Core.subst (V x 0) a' _B- let _B'' = Dhall.Core.shift (-1) (V x 0) _B'- return _B''- else do- let nf_A = Dhall.Core.normalize _A- let nf_A' = Dhall.Core.normalize _A'- Left (TypeError ctx e (TypeMismatch f nf_A a nf_A'))- loop ctx e@(Let (Binding x mA a0 :| ls) b0) = do- _A1 <- loop ctx a0- case mA of- Just _A0 -> do- _ <- loop ctx _A0- let nf_A0 = Dhall.Core.normalize _A0- let nf_A1 = Dhall.Core.normalize _A1- if Dhall.Core.judgmentallyEqual _A0 _A1- then return ()- else Left (TypeError ctx e (AnnotMismatch a0 nf_A0 nf_A1))- Nothing -> return ()-- t <- loop ctx _A1-- let a1 = Dhall.Core.normalize a0- let a2 = Dhall.Core.shift 1 (V x 0) a1-- let rest = case ls of- [] -> b0- l' : ls' -> Let (l' :| ls') b0-- -- The catch-all branch directly implements the Dhall- -- specification as written; it is necessary to substitute in- -- types in order to get 'dependent let' behaviour and to- -- allow type synonyms (see #69). However, doing a full- -- substitution is slow if the value is large and used many- -- times. If the value being substitued in is a term (i.e.,- -- its type is a Type), then we can get a very significant- -- speed-up by doing the type-checking once at binding-time,- -- as opposed to doing it at every use site (see #412).- case Dhall.Core.normalize t of- Const Type -> do- let ctx' = fmap (Dhall.Core.shift 1 (V x 0)) (Dhall.Context.insert x (Dhall.Core.normalize _A1) ctx)- _B0 <- loop ctx' rest- let _B1 = Dhall.Core.subst (V x 0) a2 _B0- let _B2 = Dhall.Core.shift (-1) (V x 0) _B1- return _B2-- _ -> do- let b1 = Dhall.Core.subst (V x 0) a2 rest- let b2 = Dhall.Core.shift (-1) (V x 0) b1- loop ctx b2-- loop ctx e@(Annot x t ) = do- _ <- loop ctx t-- t' <- loop ctx x- if Dhall.Core.judgmentallyEqual t t'- then do- return t- else do- let nf_t = Dhall.Core.normalize t- let nf_t' = Dhall.Core.normalize t'- Left (TypeError ctx e (AnnotMismatch x nf_t nf_t'))- loop _ Bool = do- return (Const Type)- loop _ (BoolLit _ ) = do- return Bool- loop ctx e@(BoolAnd l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Bool -> return ()- _ -> Left (TypeError ctx e (CantAnd l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Bool -> return ()- _ -> Left (TypeError ctx e (CantAnd r tr))-- return Bool- loop ctx e@(BoolOr l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Bool -> return ()- _ -> Left (TypeError ctx e (CantOr l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Bool -> return ()- _ -> Left (TypeError ctx e (CantOr r tr))-- return Bool- loop ctx e@(BoolEQ l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Bool -> return ()- _ -> Left (TypeError ctx e (CantEQ l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Bool -> return ()- _ -> Left (TypeError ctx e (CantEQ r tr))-- return Bool- loop ctx e@(BoolNE l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Bool -> return ()- _ -> Left (TypeError ctx e (CantNE l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Bool -> return ()- _ -> Left (TypeError ctx e (CantNE r tr))-- return Bool- loop ctx e@(BoolIf x y z ) = do- tx <- fmap Dhall.Core.normalize (loop ctx x)- case tx of- Bool -> return ()- _ -> Left (TypeError ctx e (InvalidPredicate x tx))- ty <- fmap Dhall.Core.normalize (loop ctx y )- tty <- fmap Dhall.Core.normalize (loop ctx ty)- case tty of- Const Type -> return ()- _ -> Left (TypeError ctx e (IfBranchMustBeTerm True y ty tty))-- tz <- fmap Dhall.Core.normalize (loop ctx z)- ttz <- fmap Dhall.Core.normalize (loop ctx tz)- case ttz of- Const Type -> return ()- _ -> Left (TypeError ctx e (IfBranchMustBeTerm False z tz ttz))-- if Dhall.Core.judgmentallyEqual ty tz- then return ()- else Left (TypeError ctx e (IfBranchMismatch y z ty tz))- return ty- loop _ Natural = do- return (Const Type)- loop _ (NaturalLit _ ) = do- return Natural- loop _ NaturalFold = do- return- (Pi "_" Natural- (Pi "natural" (Const Type)- (Pi "succ" (Pi "_" "natural" "natural")- (Pi "zero" "natural" "natural") ) ) )- loop _ NaturalBuild = do- return- (Pi "_"- (Pi "natural" (Const Type)- (Pi "succ" (Pi "_" "natural" "natural")- (Pi "zero" "natural" "natural") ) )- Natural )- loop _ NaturalIsZero = do- return (Pi "_" Natural Bool)- loop _ NaturalEven = do- return (Pi "_" Natural Bool)- loop _ NaturalOdd = do- return (Pi "_" Natural Bool)- loop _ NaturalToInteger = do- return (Pi "_" Natural Integer)- loop _ NaturalShow = do- return (Pi "_" Natural Text)- loop ctx e@(NaturalPlus l r) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Natural -> return ()- _ -> Left (TypeError ctx e (CantAdd l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Natural -> return ()- _ -> Left (TypeError ctx e (CantAdd r tr))- return Natural- loop ctx e@(NaturalTimes l r) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Natural -> return ()- _ -> Left (TypeError ctx e (CantMultiply l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Natural -> return ()- _ -> Left (TypeError ctx e (CantMultiply r tr))- return Natural- loop _ Integer = do- return (Const Type)- loop _ (IntegerLit _ ) = do- return Integer- loop _ IntegerShow = do- return (Pi "_" Integer Text)- loop _ IntegerToDouble = do- return (Pi "_" Integer Double)- loop _ Double = do- return (Const Type)- loop _ (DoubleLit _ ) = do- return Double- loop _ DoubleShow = do- return (Pi "_" Double Text)- loop _ Text = do- return (Const Type)- loop ctx e@(TextLit (Chunks xys _)) = do- let process (_, y) = do- ty <- fmap Dhall.Core.normalize (loop ctx y)- case ty of- Text -> return ()- _ -> Left (TypeError ctx e (CantInterpolate y ty))- mapM_ process xys- return Text- loop ctx e@(TextAppend l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- case tl of- Text -> return ()- _ -> Left (TypeError ctx e (CantTextAppend l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- case tr of- Text -> return ()- _ -> Left (TypeError ctx e (CantTextAppend r tr))- return Text- loop _ TextShow = do- return (Pi "_" Text Text)- loop _ List = do- return (Pi "_" (Const Type) (Const Type))- loop ctx e@(ListLit Nothing xs) = do- case Data.Sequence.viewl xs of- x0 :< _ -> do- t <- loop ctx x0- s <- fmap Dhall.Core.normalize (loop ctx t)- case s of- Const Type -> return ()- _ -> Left (TypeError ctx e (InvalidListType t))- flip traverseWithIndex_ xs (\i x -> do- t' <- loop ctx x- if Dhall.Core.judgmentallyEqual t t'- then return ()- else do- let nf_t = Dhall.Core.normalize t- let nf_t' = Dhall.Core.normalize t'- let err = MismatchedListElements i nf_t x nf_t'- Left (TypeError ctx x err) )- return (App List t)- _ -> Left (TypeError ctx e MissingListType)- loop ctx e@(ListLit (Just t ) xs) = do- s <- fmap Dhall.Core.normalize (loop ctx t)- case s of- Const Type -> return ()- _ -> Left (TypeError ctx e (InvalidListType t))- flip traverseWithIndex_ xs (\i x -> do- t' <- loop ctx x- if Dhall.Core.judgmentallyEqual t t'- then return ()- else do- let nf_t = Dhall.Core.normalize t- let nf_t' = Dhall.Core.normalize t'- Left (TypeError ctx x (InvalidListElement i nf_t x nf_t')) )- return (App List t)- loop ctx e@(ListAppend l r ) = do- tl <- fmap Dhall.Core.normalize (loop ctx l)- el <- case tl of- App List el -> return el- _ -> Left (TypeError ctx e (CantListAppend l tl))-- tr <- fmap Dhall.Core.normalize (loop ctx r)- er <- case tr of- App List er -> return er- _ -> Left (TypeError ctx e (CantListAppend r tr))-- if Dhall.Core.judgmentallyEqual el er- then return (App List el)- else Left (TypeError ctx e (ListAppendMismatch el er))- loop _ ListBuild = do- return- (Pi "a" (Const Type)- (Pi "_"- (Pi "list" (Const Type)- (Pi "cons" (Pi "_" "a" (Pi "_" "list" "list"))- (Pi "nil" "list" "list") ) )- (App List "a") ) )- loop _ ListFold = do- return- (Pi "a" (Const Type)- (Pi "_" (App List "a")- (Pi "list" (Const Type)- (Pi "cons" (Pi "_" "a" (Pi "_" "list" "list"))- (Pi "nil" "list" "list")) ) ) )- loop _ ListLength = do- return (Pi "a" (Const Type) (Pi "_" (App List "a") Natural))- loop _ ListHead = do- return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Optional "a")))- loop _ ListLast = do- return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Optional "a")))- loop _ ListIndexed = do- let kts = [("index", Natural), ("value", "a")]- return- (Pi "a" (Const Type)- (Pi "_" (App List "a")- (App List (Record (Dhall.Map.fromList kts))) ) )- loop _ ListReverse = do- return (Pi "a" (Const Type) (Pi "_" (App List "a") (App List "a")))- loop _ Optional = do- return (Pi "_" (Const Type) (Const Type))- loop _ None = do- return (Pi "A" (Const Type) (App Optional "A"))- loop ctx e@(OptionalLit t xs) = do- s <- fmap Dhall.Core.normalize (loop ctx t)- case s of- Const Type -> return ()- _ -> Left (TypeError ctx e (InvalidOptionalType t))- forM_ xs (\x -> do- t' <- loop ctx x- if Dhall.Core.judgmentallyEqual t t'- then return ()- else do- let nf_t = Dhall.Core.normalize t- let nf_t' = Dhall.Core.normalize t'- Left (TypeError ctx e (InvalidOptionalElement nf_t x nf_t')) )- return (App Optional t)- loop ctx e@(Some a) = do- _A <- loop ctx a- s <- fmap Dhall.Core.normalize (loop ctx _A)- case s of- Const Type -> return ()- _ -> Left (TypeError ctx e (InvalidSome a _A s))- return (App Optional _A)- loop _ OptionalFold = do- return- (Pi "a" (Const Type)- (Pi "_" (App Optional "a")- (Pi "optional" (Const Type)- (Pi "just" (Pi "_" "a" "optional")- (Pi "nothing" "optional" "optional") ) ) ) )- loop _ OptionalBuild = do- return- (Pi "a" (Const Type)- (Pi "_" f (App Optional "a") ) )- where f = Pi "optional" (Const Type)- (Pi "just" (Pi "_" "a" "optional")- (Pi "nothing" "optional" "optional") )- loop ctx e@(Record kts ) = do- case Dhall.Map.uncons kts of- Nothing -> return (Const Type)- Just (k0, t0, rest) -> do- s0 <- fmap Dhall.Core.normalize (loop ctx t0)- c <- case s0 of- Const c -> pure c- _ -> Left (TypeError ctx e (InvalidFieldType k0 t0))- let process k t = do- s <- fmap Dhall.Core.normalize (loop ctx t)- case s of- Const c' ->- if c == c'- then return ()- else Left (TypeError ctx e (FieldAnnotationMismatch k t c k0 t0 c'))- _ -> Left (TypeError ctx e (InvalidFieldType k t))- Dhall.Map.unorderedTraverseWithKey_ process rest- return (Const c)- loop ctx e@(RecordLit kvs ) = do- case Dhall.Map.toList kvs of- [] -> return (Record mempty)- (k0, v0):_ -> do- t0 <- loop ctx v0- s0 <- fmap Dhall.Core.normalize (loop ctx t0)- c <- case s0 of- Const c -> pure c- _ -> Left (TypeError ctx e (InvalidField k0 v0))- let process k v = do- t <- loop ctx v- s <- fmap Dhall.Core.normalize (loop ctx t)- case s of- Const c' ->- if c == c'- then return ()- else Left (TypeError ctx e (FieldMismatch k v c k0 v0 c'))- _ -> Left (TypeError ctx e (InvalidField k t))-- return t- kts <- Dhall.Map.traverseWithKey process kvs- return (Record kts)- loop ctx e@(Union kts ) = do- let nonEmpty k mt = First (fmap (\t -> (k, t)) mt)-- case getFirst (Dhall.Map.foldMapWithKey nonEmpty kts) of- Nothing -> do- return (Const Type)-- Just (k0, t0) -> do- s0 <- fmap Dhall.Core.normalize (loop ctx t0)-- c0 <- case s0 of- Const c0 -> do- return c0-- _ -> do- Left (TypeError ctx e (InvalidAlternativeType k0 t0))-- let process _ Nothing = do- return ()-- process k (Just t) = do- s <- fmap Dhall.Core.normalize (loop ctx t)-- c <- case s of- Const c -> do- return c-- _ -> do- Left (TypeError ctx e (InvalidAlternativeType k t))-- if c0 == c- then return ()- else Left (TypeError ctx e (AlternativeAnnotationMismatch k t c k0 t0 c0))-- Dhall.Map.unorderedTraverseWithKey_ process kts-- return (Const c0)- loop ctx e@(UnionLit k v kts) = do- case Dhall.Map.lookup k kts of- Just _ -> Left (TypeError ctx e (DuplicateAlternative k))- Nothing -> return ()- t <- loop ctx v- let union = Union (Dhall.Map.insert k (Just (Dhall.Core.normalize t)) kts)- _ <- loop ctx union- return union- loop ctx e@(Combine kvsX kvsY) = do- tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX)- ktsX <- case tKvsX of- Record kts -> return kts- _ -> Left (TypeError ctx e (MustCombineARecord '∧' kvsX tKvsX))-- tKvsY <- fmap Dhall.Core.normalize (loop ctx kvsY)- ktsY <- case tKvsY of- Record kts -> return kts- _ -> Left (TypeError ctx e (MustCombineARecord '∧' kvsY tKvsY))-- ttKvsX <- fmap Dhall.Core.normalize (loop ctx tKvsX)- constX <- case ttKvsX of- Const constX -> return constX- _ -> Left (TypeError ctx e (MustCombineARecord '∧' kvsX tKvsX))-- ttKvsY <- fmap Dhall.Core.normalize (loop ctx tKvsY)- constY <- case ttKvsY of- Const constY -> return constY- _ -> Left (TypeError ctx e (MustCombineARecord '∧' kvsY tKvsY))-- if constX == constY- then return ()- else Left (TypeError ctx e (RecordMismatch '∧' kvsX kvsY constX constY))-- let combineTypes ktsL ktsR = do- let ksL =- Data.Set.fromList (Dhall.Map.keys ktsL)- let ksR =- Data.Set.fromList (Dhall.Map.keys ktsR)- let ks = Data.Set.union ksL ksR- kts <- forM (toList ks) (\k -> do- case (Dhall.Map.lookup k ktsL, Dhall.Map.lookup k ktsR) of- (Just (Record ktsL'), Just (Record ktsR')) -> do- t <- combineTypes ktsL' ktsR'- return (k, t)- (Nothing, Just t) -> do- return (k, t)- (Just t, Nothing) -> do- return (k, t)- _ -> do- Left (TypeError ctx e (FieldCollision k)) )- return (Record (Dhall.Map.fromList kts))-- combineTypes ktsX ktsY- loop ctx e@(CombineTypes l r) = do- tL <- loop ctx l- let l' = Dhall.Core.normalize l- cL <- case tL of- Const cL -> return cL- _ -> Left (TypeError ctx e (CombineTypesRequiresRecordType l l'))- tR <- loop ctx r- let r' = Dhall.Core.normalize r- cR <- case tR of- Const cR -> return cR- _ -> Left (TypeError ctx e (CombineTypesRequiresRecordType r r'))- let decide Type Type =- return Type- decide Kind Kind =- return Kind- decide Sort Sort =- return Sort- decide x y =- Left (TypeError ctx e (RecordTypeMismatch x y l r))- c <- decide cL cR-- ktsL0 <- case l' of- Record kts -> return kts- _ -> Left (TypeError ctx e (CombineTypesRequiresRecordType l l'))- ktsR0 <- case r' of- Record kts -> return kts- _ -> Left (TypeError ctx e (CombineTypesRequiresRecordType r r'))-- let combineTypes ktsL ktsR = do- let ksL =- Data.Set.fromList (Dhall.Map.keys ktsL)- let ksR =- Data.Set.fromList (Dhall.Map.keys ktsR)- let ks = Data.Set.union ksL ksR- forM_ (toList ks) (\k -> do- case (Dhall.Map.lookup k ktsL, Dhall.Map.lookup k ktsR) of- (Just (Record ktsL'), Just (Record ktsR')) -> do- combineTypes ktsL' ktsR'- (Nothing, Just _) -> do- return ()- (Just _, Nothing) -> do- return ()- _ -> do- Left (TypeError ctx e (FieldCollision k)) )-- combineTypes ktsL0 ktsR0-- return (Const c)- loop ctx e@(Prefer kvsX kvsY) = do- tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX)- ktsX <- case tKvsX of- Record kts -> return kts- _ -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsX tKvsX))-- tKvsY <- fmap Dhall.Core.normalize (loop ctx kvsY)- ktsY <- case tKvsY of- Record kts -> return kts- _ -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsY tKvsY))-- ttKvsX <- fmap Dhall.Core.normalize (loop ctx tKvsX)- constX <- case ttKvsX of- Const constX -> return constX- _ -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsX tKvsX))-- ttKvsY <- fmap Dhall.Core.normalize (loop ctx tKvsY)- constY <- case ttKvsY of- Const constY -> return constY- _ -> Left (TypeError ctx e (MustCombineARecord '⫽' kvsY tKvsY))-- if constX == constY- then return ()- else Left (TypeError ctx e (RecordMismatch '⫽' kvsX kvsY constX constY))-- return (Record (Dhall.Map.union ktsY ktsX))- loop ctx e@(Merge kvsX kvsY mT₁) = do- tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX)-- ktsX <- case tKvsX of- Record kts -> return kts- _ -> Left (TypeError ctx e (MustMergeARecord kvsX tKvsX))-- tKvsY <- fmap Dhall.Core.normalize (loop ctx kvsY)-- ktsY <- case tKvsY of- Union kts -> return kts- _ -> Left (TypeError ctx e (MustMergeUnion kvsY tKvsY))-- let ksX = Data.Set.fromList (Dhall.Map.keys ktsX)- let ksY = Data.Set.fromList (Dhall.Map.keys ktsY)-- let diffX = Data.Set.difference ksX ksY- let diffY = Data.Set.difference ksY ksX-- if Data.Set.null diffX- then return ()- else Left (TypeError ctx e (UnusedHandler diffX))-- (mKX, _T₁) <- do- case mT₁ of- Just _T₁ -> do- return (Nothing, _T₁)-- Nothing -> do- case Dhall.Map.uncons ktsX of- Nothing -> do- Left (TypeError ctx e MissingMergeType)-- Just (kX, tX, _) -> do- _T₁ <- do- case Dhall.Map.lookup kX ktsY of- Nothing -> do- Left (TypeError ctx e (UnusedHandler diffX))-- Just Nothing -> do- return tX-- Just (Just _) ->- case tX of- Pi x _A₀ _T₀ -> do- return (Dhall.Core.shift (-1) (V x 0) _T₀)- _ -> do- Left (TypeError ctx e (HandlerNotAFunction kX tX))-- return (Just kX, _T₁)-- _ <- loop ctx _T₁-- let process kY mTY = do- case Dhall.Map.lookup kY ktsX of- Nothing -> do- Left (TypeError ctx e (MissingHandler diffY))-- Just tX -> do- _T₃ <- do- case mTY of- Nothing -> do- return tX- Just _A₁ -> do- case tX of- Pi x _A₀ _T₂ -> do- if Dhall.Core.judgmentallyEqual _A₀ _A₁- then return ()- else Left (TypeError ctx e (HandlerInputTypeMismatch kY _A₁ _A₀))-- return (Dhall.Core.shift (-1) (V x 0) _T₂)- _ -> do- Left (TypeError ctx e (HandlerNotAFunction kY tX))-- if Dhall.Core.judgmentallyEqual _T₁ _T₃- then return ()- else- case mKX of- Nothing -> do- Left (TypeError ctx e (InvalidHandlerOutputType kY _T₁ _T₃))- Just kX -> do- Left (TypeError ctx e (HandlerOutputTypeMismatch kX _T₁ kY _T₃))-- Dhall.Map.unorderedTraverseWithKey_ process ktsY-- return _T₁- loop ctx e@(Field r x ) = do- t <- fmap Dhall.Core.normalize (loop ctx r)-- let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabel x)-- case t of- Record kts -> do- _ <- loop ctx t-- case Dhall.Map.lookup x kts of- Just t' -> return t'- Nothing -> Left (TypeError ctx e (MissingField x t))- _ -> do- case Dhall.Core.normalize r of- Union kts ->- case Dhall.Map.lookup x kts of- Just (Just t') -> return (Pi x t' (Union kts))- Just Nothing -> return (Union kts)- Nothing -> Left (TypeError ctx e (MissingField x t))- r' -> Left (TypeError ctx e (CantAccess text r' t))- loop ctx e@(Project r (Left xs)) = do- t <- fmap Dhall.Core.normalize (loop ctx r)-- case t of- Record kts -> do- _ <- loop ctx t-- let process k =- case Dhall.Map.lookup k kts of- Just t' -> return (k, t')- Nothing -> Left (TypeError ctx e (MissingField k t))-- let adapt = Record . Dhall.Map.fromList-- fmap adapt (traverse process (Dhall.Set.toList xs))- _ -> do- let text =- Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs)-- Left (TypeError ctx e (CantProject text r t))- loop ctx e@(Project r (Right t)) = do- _R <- loop ctx r-- case _R of- Record ktsR -> do- _ <- fmap Dhall.Core.normalize (loop ctx t)-- case Dhall.Core.normalize t of- Record ktsT -> do- let keysR = Dhall.Set.fromList (Dhall.Map.keys ktsR)- let keysT = Dhall.Set.fromList (Dhall.Map.keys ktsT)-- case Dhall.Set.difference keysT keysR of- k : _ -> do- Left (TypeError ctx e (MissingField k t))- [] -> do- return (Record ktsT)- _ -> do- Left (TypeError ctx e (CantProjectByExpression t))-- _ -> do- let text = Dhall.Core.pretty t-- Left (TypeError ctx e (CantProject text r t))- loop ctx (Note s e' ) = case loop ctx e' of- Left (TypeError ctx' (Note s' e'') m) -> Left (TypeError ctx' (Note s' e'') m)- Left (TypeError ctx' e'' m) -> Left (TypeError ctx' (Note s e'') m)- Right r -> Right r- loop ctx (ImportAlt l _r ) =- fmap Dhall.Core.normalize (loop ctx l)- loop _ (Embed p ) = Right $ tpa p--{-| `typeOf` is the same as `typeWith` with an empty context, meaning that the- expression must be closed (i.e. no free variables), otherwise type-checking- will fail.--}-typeOf :: Expr s X -> Either (TypeError s X) (Expr s X)-typeOf = typeWith Dhall.Context.empty---- | Like `Data.Void.Void`, except with a shorter inferred type-newtype X = X { absurd :: forall a . a }--instance Show X where- show = absurd--instance Eq X where- _ == _ = True--instance Data X where- dataTypeOf = absurd- gunfold _ _ _ = undefined- toConstr = absurd--instance Pretty X where- pretty = absurd--instance FromTerm X where- decode _ = empty--instance ToTerm X where- encode = absurd---- | The specific type error-data TypeMessage s a- = UnboundVariable Text- | InvalidInputType (Expr s a)- | InvalidOutputType (Expr s a)- | NotAFunction (Expr s a) (Expr s a)- | TypeMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)- | AnnotMismatch (Expr s a) (Expr s a) (Expr s a)- | Untyped- | MissingListType- | MismatchedListElements Int (Expr s a) (Expr s a) (Expr s a)- | InvalidListElement Int (Expr s a) (Expr s a) (Expr s a)- | InvalidListType (Expr s a)- | InvalidOptionalElement (Expr s a) (Expr s a) (Expr s a)- | InvalidOptionalType (Expr s a)- | InvalidSome (Expr s a) (Expr s a) (Expr s a)- | InvalidPredicate (Expr s a) (Expr s a)- | IfBranchMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)- | IfBranchMustBeTerm Bool (Expr s a) (Expr s a) (Expr s a)- | InvalidField Text (Expr s a)- | InvalidFieldType Text (Expr s a)- | FieldAnnotationMismatch Text (Expr s a) Const Text (Expr s a) Const- | FieldMismatch Text (Expr s a) Const Text (Expr s a) Const- | InvalidAlternative Text (Expr s a)- | InvalidAlternativeType Text (Expr s a)- | AlternativeAnnotationMismatch Text (Expr s a) Const Text (Expr s a) Const- | ListAppendMismatch (Expr s a) (Expr s a)- | DuplicateAlternative Text- | MustCombineARecord Char (Expr s a) (Expr s a)- | RecordMismatch Char (Expr s a) (Expr s a) Const Const- | CombineTypesRequiresRecordType (Expr s a) (Expr s a)- | RecordTypeMismatch Const Const (Expr s a) (Expr s a)- | FieldCollision Text- | MustMergeARecord (Expr s a) (Expr s a)- | MustMergeUnion (Expr s a) (Expr s a)- | UnusedHandler (Set Text)- | MissingHandler (Set Text)- | HandlerInputTypeMismatch Text (Expr s a) (Expr s a)- | HandlerOutputTypeMismatch Text (Expr s a) Text (Expr s a)- | InvalidHandlerOutputType Text (Expr s a) (Expr s a)- | MissingMergeType- | HandlerNotAFunction Text (Expr s a)- | ConstructorsRequiresAUnionType (Expr s a) (Expr s a)- | CantAccess Text (Expr s a) (Expr s a)- | CantProject Text (Expr s a) (Expr s a)- | CantProjectByExpression (Expr s a)- | MissingField Text (Expr s a)- | CantAnd (Expr s a) (Expr s a)- | CantOr (Expr s a) (Expr s a)- | CantEQ (Expr s a) (Expr s a)- | CantNE (Expr s a) (Expr s a)- | CantInterpolate (Expr s a) (Expr s a)- | CantTextAppend (Expr s a) (Expr s a)- | CantListAppend (Expr s a) (Expr s a)- | CantAdd (Expr s a) (Expr s a)- | CantMultiply (Expr s a) (Expr s a)- | NoDependentTypes (Expr s a) (Expr s a)- deriving (Show)--shortTypeMessage :: (Eq a, Pretty a, ToTerm a) => TypeMessage s a -> Doc Ann-shortTypeMessage msg =- "\ESC[1;31mError\ESC[0m: " <> short <> "\n"- where- ErrorMessages {..} = prettyTypeMessage msg--longTypeMessage :: (Eq a, Pretty a, ToTerm a) => TypeMessage s a -> Doc Ann-longTypeMessage msg =- "\ESC[1;31mError\ESC[0m: " <> short <> "\n"- <> "\n"- <> long- where- ErrorMessages {..} = prettyTypeMessage msg--data ErrorMessages = ErrorMessages- { short :: Doc Ann- -- ^ Default succinct 1-line explanation of what went wrong- , long :: Doc Ann- -- ^ Longer and more detailed explanation of the error- }--_NOT :: Doc ann-_NOT = "\ESC[1mnot\ESC[0m"--insert :: Pretty a => a -> Doc Ann-insert = Dhall.Util.insert--prettyDiff :: (Eq a, Pretty a, ToTerm a) => Expr s a -> Expr s a -> Doc Ann-prettyDiff exprL exprR = Dhall.Diff.diffNormalized exprL exprR--prettyTypeMessage- :: (Eq a, Pretty a, ToTerm a) => TypeMessage s a -> ErrorMessages-prettyTypeMessage (UnboundVariable x) = ErrorMessages {..}- -- We do not need to print variable name here. For the discussion see:- -- https://github.com/dhall-lang/dhall-haskell/pull/116- where- short = "Unbound variable: " <> Pretty.pretty x-- long =- "Explanation: Expressions can only reference previously introduced (i.e. “bound”)\n\- \variables that are still “in scope” \n\- \ \n\- \For example, the following valid expressions introduce a “bound” variable named \n\- \❰x❱: \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ λ(x : Bool) → x │ Anonymous functions introduce “bound” variables \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This is the bound variable \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ let x = 1 in x │ ❰let❱ expressions introduce “bound” variables \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This is the bound variable \n\- \ \n\- \ \n\- \However, the following expressions are not valid because they all reference a \n\- \variable that has not been introduced yet (i.e. an “unbound” variable): \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ λ(x : Bool) → y │ The variable ❰y❱ hasn't been introduced yet \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This is the unbound variable \n\- \ \n\- \ \n\- \ ┌──────────────────────────┐ \n\- \ │ (let x = True in x) && x │ ❰x❱ is undefined outside the parentheses \n\- \ └──────────────────────────┘ \n\- \ ⇧ \n\- \ This is the unbound variable \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ let x = x in x │ The definition for ❰x❱ cannot reference itself \n\- \ └────────────────┘ \n\- \ ⇧ \n\- \ This is the unbound variable \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You misspell a variable name, like this: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────────────────────┐ \n\- \ │ λ(empty : Bool) → if emty then \"Empty\" else \"Full\" │ \n\- \ └────────────────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Typo \n\- \ \n\- \ \n\- \● You misspell a reserved identifier, like this: \n\- \ \n\- \ \n\- \ ┌──────────────────────────┐ \n\- \ │ foral (a : Type) → a → a │ \n\- \ └──────────────────────────┘ \n\- \ ⇧ \n\- \ Typo \n\- \ \n\- \ \n\- \● You tried to define a recursive value, like this: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ let x = x + 1 in x │ \n\- \ └────────────────────┘ \n\- \ ⇧ \n\- \ Recursive definitions are not allowed \n\- \ \n\- \ \n\- \● You accidentally forgot a ❰λ❱ or ❰∀❱/❰forall❱ \n\- \ \n\- \ \n\- \ Unbound variable \n\- \ ⇩ \n\- \ ┌─────────────────┐ \n\- \ │ (x : Bool) → x │ \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ A ❰λ❱ here would transform this into a valid anonymous function \n\- \ \n\- \ \n\- \ Unbound variable \n\- \ ⇩ \n\- \ ┌────────────────────┐ \n\- \ │ (x : Bool) → Bool │ \n\- \ └────────────────────┘ \n\- \ ⇧ \n\- \ A ❰∀❱ or ❰forall❱ here would transform this into a valid function type \n\- \ \n\- \ \n\- \● You forgot to prefix a file path with ❰./❱: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ path/to/file.dhall │ \n\- \ └────────────────────┘ \n\- \ ⇧ \n\- \ This should be ❰./path/to/file.dhall❱ \n"--prettyTypeMessage (InvalidInputType expr) = ErrorMessages {..}- where- short = "Invalid function input"-- long =- "Explanation: A function can accept an input “term” that has a given “type”, like\n\- \this: \n\- \ \n\- \ \n\- \ This is the input term that the function accepts \n\- \ ⇩ \n\- \ ┌───────────────────────┐ \n\- \ │ ∀(x : Natural) → Bool │ This is the type of a function that accepts an \n\- \ └───────────────────────┘ input term named ❰x❱ that has type ❰Natural❱ \n\- \ ⇧ \n\- \ This is the type of the input term \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ Bool → Natural │ This is the type of a function that accepts an anonymous\n\- \ └────────────────┘ input term that has type ❰Bool❱ \n\- \ ⇧ \n\- \ This is the type of the input term \n\- \ \n\- \ \n\- \... or a function can accept an input “type” that has a given “kind”, like this:\n\- \ \n\- \ \n\- \ This is the input type that the function accepts \n\- \ ⇩ \n\- \ ┌────────────────────┐ \n\- \ │ ∀(a : Type) → Type │ This is the type of a function that accepts an input\n\- \ └────────────────────┘ type named ❰a❱ that has kind ❰Type❱ \n\- \ ⇧ \n\- \ This is the kind of the input type \n\- \ \n\- \ \n\- \ ┌──────────────────────┐ \n\- \ │ (Type → Type) → Type │ This is the type of a function that accepts an \n\- \ └──────────────────────┘ anonymous input type that has kind ❰Type → Type❱ \n\- \ ⇧ \n\- \ This is the kind of the input type \n\- \ \n\- \ \n\- \Other function inputs are " <> _NOT <> " valid, like this: \n\- \ \n\- \ \n\- \ ┌──────────────┐ \n\- \ │ ∀(x : 1) → x │ ❰1❱ is a “term” and not a “type” nor a “kind” so ❰x❱ \n\- \ └──────────────┘ cannot have “type” ❰1❱ or “kind” ❰1❱ \n\- \ ⇧ \n\- \ This is not a type or kind \n\- \ \n\- \ \n\- \ ┌──────────┐ \n\- \ │ True → x │ ❰True❱ is a “term” and not a “type” nor a “kind” so the \n\- \ └──────────┘ anonymous input cannot have “type” ❰True❱ or “kind” ❰True❱ \n\- \ ⇧ \n\- \ This is not a type or kind \n\- \ \n\- \ \n\- \You annotated a function input with the following expression: \n\- \ \n\- \" <> txt <> "\n\- \ \n\- \... which is neither a type nor a kind \n"- where- txt = insert expr--prettyTypeMessage (InvalidOutputType expr) = ErrorMessages {..}- where- short = "Invalid function output"-- long =- "Explanation: A function can return an output “term” that has a given “type”, \n\- \like this: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ ∀(x : Text) → Bool │ This is the type of a function that returns an \n\- \ └────────────────────┘ output term that has type ❰Bool❱ \n\- \ ⇧ \n\- \ This is the type of the output term \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ Bool → Natural │ This is the type of a function that returns an output \n\- \ └────────────────┘ term that has type ❰Natural❱ \n\- \ ⇧ \n\- \ This is the type of the output term \n\- \ \n\- \ \n\- \... or a function can return an output “type” that has a given “kind”, like \n\- \this: \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ ∀(a : Type) → Type │ This is the type of a function that returns an \n\- \ └────────────────────┘ output type that has kind ❰Type❱ \n\- \ ⇧ \n\- \ This is the kind of the output type \n\- \ \n\- \ \n\- \ ┌──────────────────────┐ \n\- \ │ (Type → Type) → Type │ This is the type of a function that returns an \n\- \ └──────────────────────┘ output type that has kind ❰Type❱ \n\- \ ⇧ \n\- \ This is the kind of the output type \n\- \ \n\- \ \n\- \Other outputs are " <> _NOT <> " valid, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ ∀(x : Bool) → x │ ❰x❱ is a “term” and not a “type” nor a “kind” so the \n\- \ └─────────────────┘ output cannot have “type” ❰x❱ or “kind” ❰x❱ \n\- \ ⇧ \n\- \ This is not a type or kind \n\- \ \n\- \ \n\- \ ┌─────────────┐ \n\- \ │ Text → True │ ❰True❱ is a “term” and not a “type” nor a “kind” so the \n\- \ └─────────────┘ output cannot have “type” ❰True❱ or “kind” ❰True❱ \n\- \ ⇧ \n\- \ This is not a type or kind \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You use ❰∀❱ instead of ❰λ❱ by mistake, like this: \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ ∀(x: Bool) → x │ \n\- \ └────────────────┘ \n\- \ ⇧ \n\- \ Using ❰λ❱ here instead of ❰∀❱ would transform this into a valid function \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You specified that your function outputs a: \n\- \ \n\- \" <> txt <> "\n\- \ \n\- \... which is neither a type nor a kind: \n"- where- txt = insert expr--prettyTypeMessage (NotAFunction expr0 expr1) = ErrorMessages {..}- where- short = "Not a function"-- long =- "Explanation: Expressions separated by whitespace denote function application, \n\- \like this: \n\- \ \n\- \ \n\- \ ┌─────┐ \n\- \ │ f x │ This denotes the function ❰f❱ applied to an argument named ❰x❱ \n\- \ └─────┘ \n\- \ \n\- \ \n\- \A function is a term that has type ❰a → b❱ for some ❰a❱ or ❰b❱. For example, \n\- \the following expressions are all functions because they have a function type: \n\- \ \n\- \ \n\- \ The function's input type is ❰Bool❱ \n\- \ ⇩ \n\- \ ┌───────────────────────────────┐ \n\- \ │ λ(x : Bool) → x : Bool → Bool │ User-defined anonymous function \n\- \ └───────────────────────────────┘ \n\- \ ⇧ \n\- \ The function's output type is ❰Bool❱ \n\- \ \n\- \ \n\- \ The function's input type is ❰Natural❱ \n\- \ ⇩ \n\- \ ┌───────────────────────────────┐ \n\- \ │ Natural/even : Natural → Bool │ Built-in function \n\- \ └───────────────────────────────┘ \n\- \ ⇧ \n\- \ The function's output type is ❰Bool❱ \n\- \ \n\- \ \n\- \ The function's input kind is ❰Type❱ \n\- \ ⇩ \n\- \ ┌───────────────────────────────┐ \n\- \ │ λ(a : Type) → a : Type → Type │ Type-level functions are still functions \n\- \ └───────────────────────────────┘ \n\- \ ⇧ \n\- \ The function's output kind is ❰Type❱ \n\- \ \n\- \ \n\- \ The function's input kind is ❰Type❱ \n\- \ ⇩ \n\- \ ┌────────────────────┐ \n\- \ │ List : Type → Type │ Built-in type-level function \n\- \ └────────────────────┘ \n\- \ ⇧ \n\- \ The function's output kind is ❰Type❱ \n\- \ \n\- \ \n\- \ Function's input has kind ❰Type❱ \n\- \ ⇩ \n\- \ ┌─────────────────────────────────────────────────┐ \n\- \ │ List/head : ∀(a : Type) → (List a → Optional a) │ A function can return \n\- \ └─────────────────────────────────────────────────┘ another function \n\- \ ⇧ \n\- \ Function's output has type ❰List a → Optional a❱\n\- \ \n\- \ \n\- \ The function's input type is ❰List Text❱ \n\- \ ⇩ \n\- \ ┌────────────────────────────────────────────┐ \n\- \ │ List/head Text : List Text → Optional Text │ A function applied to an \n\- \ └────────────────────────────────────────────┘ argument can be a function \n\- \ ⇧ \n\- \ The function's output type is ❰Optional Text❱\n\- \ \n\- \ \n\- \An expression is not a function if the expression's type is not of the form \n\- \❰a → b❱. For example, these are " <> _NOT <> " functions: \n\- \ \n\- \ \n\- \ ┌─────────────┐ \n\- \ │ 1 : Natural │ ❰1❱ is not a function because ❰Natural❱ is not the type of \n\- \ └─────────────┘ a function \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ Natural/even 2 : Bool │ ❰Natural/even 2❱ is not a function because \n\- \ └───────────────────────┘ ❰Bool❱ is not the type of a function \n\- \ \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ List Text : Type │ ❰List Text❱ is not a function because ❰Type❱ is not \n\- \ └──────────────────┘ the type of a function \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You tried to add two ❰Natural❱s without a space around the ❰+❱, like this: \n\- \ \n\- \ \n\- \ ┌─────┐ \n\- \ │ 2+2 │ \n\- \ └─────┘ \n\- \ \n\- \ \n\- \ The above code is parsed as: \n\- \ \n\- \ \n\- \ ┌────────┐ \n\- \ │ 2 (+2) │ \n\- \ └────────┘ \n\- \ ⇧ \n\- \ The compiler thinks that this ❰2❱ is a function whose argument is ❰+2❱ \n\- \ \n\- \ \n\- \ This is because the ❰+❱ symbol has two meanings: you use ❰+❱ to add two \n\- \ numbers, but you also can prefix ❰Natural❱ literals with a ❰+❱ to turn them \n\- \ into ❰Integer❱ literals (like ❰+2❱) \n\- \ \n\- \ To fix the code, you need to put spaces around the ❰+❱, like this: \n\- \ \n\- \ \n\- \ ┌───────┐ \n\- \ │ 2 + 2 │ \n\- \ └───────┘ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to use the following expression as a function: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... but this expression's type is: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not a function type \n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (TypeMismatch expr0 expr1 expr2 expr3) = ErrorMessages {..}- where- short = "Wrong type of function argument\n"- <> "\n"- <> prettyDiff expr1 expr3-- long =- "Explanation: Every function declares what type or kind of argument to accept \n\- \ \n\- \For example: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────┐ \n\- \ │ λ(x : Bool) → x : Bool → Bool │ This anonymous function only accepts \n\- \ └───────────────────────────────┘ arguments that have type ❰Bool❱ \n\- \ ⇧ \n\- \ The function's input type \n\- \ \n\- \ \n\- \ ┌───────────────────────────────┐ \n\- \ │ Natural/even : Natural → Bool │ This built-in function only accepts \n\- \ └───────────────────────────────┘ arguments that have type ❰Natural❱ \n\- \ ⇧ \n\- \ The function's input type \n\- \ \n\- \ \n\- \ ┌───────────────────────────────┐ \n\- \ │ λ(a : Type) → a : Type → Type │ This anonymous function only accepts \n\- \ └───────────────────────────────┘ arguments that have kind ❰Type❱ \n\- \ ⇧ \n\- \ The function's input kind \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ List : Type → Type │ This built-in function only accepts arguments that \n\- \ └────────────────────┘ have kind ❰Type❱ \n\- \ ⇧ \n\- \ The function's input kind \n\- \ \n\- \ \n\- \For example, the following expressions are valid: \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ (λ(x : Bool) → x) True │ ❰True❱ has type ❰Bool❱, which matches the type \n\- \ └────────────────────────┘ of argument that the anonymous function accepts \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ Natural/even 2 │ ❰2❱ has type ❰Natural❱, which matches the type of \n\- \ └────────────────┘ argument that the ❰Natural/even❱ function accepts, \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ (λ(a : Type) → a) Bool │ ❰Bool❱ has kind ❰Type❱, which matches the kind \n\- \ └────────────────────────┘ of argument that the anonymous function accepts \n\- \ \n\- \ \n\- \ ┌───────────┐ \n\- \ │ List Text │ ❰Text❱ has kind ❰Type❱, which matches the kind of argument \n\- \ └───────────┘ that that the ❰List❱ function accepts \n\- \ \n\- \ \n\- \However, you can " <> _NOT <> " apply a function to the wrong type or kind of argument\n\- \ \n\- \For example, the following expressions are not valid: \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ (λ(x : Bool) → x) \"A\" │ ❰\"A\"❱ has type ❰Text❱, but the anonymous function\n\- \ └───────────────────────┘ expects an argument that has type ❰Bool❱ \n\- \ \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ Natural/even \"A\" │ ❰\"A\"❱ has type ❰Text❱, but the ❰Natural/even❱ function\n\- \ └──────────────────┘ expects an argument that has type ❰Natural❱ \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ (λ(a : Type) → a) True │ ❰True❱ has type ❰Bool❱, but the anonymous \n\- \ └────────────────────────┘ function expects an argument of kind ❰Type❱ \n\- \ \n\- \ \n\- \ ┌────────┐ \n\- \ │ List 1 │ ❰1❱ has type ❰Natural❱, but the ❰List❱ function expects an \n\- \ └────────┘ argument that has kind ❰Type❱ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You omit a function argument by mistake: \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ List/head [1, 2, 3] │ \n\- \ └───────────────────────┘ \n\- \ ⇧ \n\- \ ❰List/head❱ is missing the first argument, \n\- \ which should be: ❰Natural❱ \n\- \ \n\- \ \n\- \● You supply an ❰Integer❱ literal to a function that expects a ❰Natural❱ \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ Natural/even +2 │ \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This should be ❰2❱ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to invoke the following function: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which expects an argument of type or kind: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... on the following argument: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... which has a different type or kind: \n\- \ \n\- \" <> txt3 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2- txt3 = insert expr3--prettyTypeMessage (AnnotMismatch expr0 expr1 expr2) = ErrorMessages {..}- where- short = "Expression doesn't match annotation\n"- <> "\n"- <> prettyDiff expr1 expr2- long =- "Explanation: You can annotate an expression with its type or kind using the \n\- \❰:❱ symbol, like this: \n\- \ \n\- \ \n\- \ ┌───────┐ \n\- \ │ x : t │ ❰x❱ is an expression and ❰t❱ is the annotated type or kind of ❰x❱\n\- \ └───────┘ \n\- \ \n\- \The type checker verifies that the expression's type or kind matches the \n\- \provided annotation \n\- \ \n\- \For example, all of the following are valid annotations that the type checker \n\- \accepts: \n\- \ \n\- \ \n\- \ ┌─────────────┐ \n\- \ │ 1 : Natural │ ❰1❱ is an expression that has type ❰Natural❱, so the type \n\- \ └─────────────┘ checker accepts the annotation \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ Natural/even 2 : Bool │ ❰Natural/even 2❱ has type ❰Bool❱, so the type \n\- \ └───────────────────────┘ checker accepts the annotation \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ List : Type → Type │ ❰List❱ is an expression that has kind ❰Type → Type❱,\n\- \ └────────────────────┘ so the type checker accepts the annotation \n\- \ \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ List Text : Type │ ❰List Text❱ is an expression that has kind ❰Type❱, so \n\- \ └──────────────────┘ the type checker accepts the annotation \n\- \ \n\- \ \n\- \However, the following annotations are " <> _NOT <> " valid and the type checker will\n\- \reject them: \n\- \ \n\- \ \n\- \ ┌──────────┐ \n\- \ │ 1 : Text │ The type checker rejects this because ❰1❱ does not have type \n\- \ └──────────┘ ❰Text❱ \n\- \ \n\- \ \n\- \ ┌─────────────┐ \n\- \ │ List : Type │ ❰List❱ does not have kind ❰Type❱ \n\- \ └─────────────┘ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● The Haskell Dhall interpreter implicitly inserts a top-level annotation \n\- \ matching the expected type \n\- \ \n\- \ For example, if you run the following Haskell code: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────┐ \n\- \ │ >>> input auto \"1\" :: IO Text │ \n\- \ └───────────────────────────────┘ \n\- \ \n\- \ \n\- \ ... then the interpreter will actually type check the following annotated \n\- \ expression: \n\- \ \n\- \ \n\- \ ┌──────────┐ \n\- \ │ 1 : Text │ \n\- \ └──────────┘ \n\- \ \n\- \ \n\- \ ... and then type-checking will fail \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You or the interpreter annotated this expression: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... with this type or kind: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but the inferred type or kind of the expression is actually: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2--prettyTypeMessage Untyped = ErrorMessages {..}- where- short = "❰Sort❱ has no type, kind, or sort"-- long =- "Explanation: There are five levels of expressions that form a hierarchy: \n\- \ \n\- \● terms \n\- \● types \n\- \● kinds \n\- \● sorts \n\- \● orders \n\- \ \n\- \The following example illustrates this hierarchy: \n\- \ \n\- \ ┌───────────────────────────────────┐ \n\- \ │ \"ABC\" : Text : Type : Kind : Sort │ \n\- \ └───────────────────────────────────┘ \n\- \ ⇧ ⇧ ⇧ ⇧ ⇧ \n\- \ term type kind sort order \n\- \ \n\- \There is nothing above ❰Sort❱ in this hierarchy, so if you try to type check any\n\- \expression containing ❰Sort❱ anywhere in the expression then type checking fails\n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You supplied a sort where a kind was expected \n\- \ \n\- \ For example, the following expression will fail to type check: \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ f : Type -> Kind │ \n\- \ └──────────────────┘ \n\- \ ⇧ \n\- \ ❰Kind❱ is a sort, not a kind \n"--prettyTypeMessage (InvalidPredicate expr0 expr1) = ErrorMessages {..}- where- short = "Invalid predicate for ❰if❱"-- long =- "Explanation: Every ❰if❱ expression begins with a predicate which must have type \n\- \❰Bool❱ \n\- \ \n\- \For example, these are valid ❰if❱ expressions: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────┐ \n\- \ │ if True then \"Yes\" else \"No\" │ \n\- \ └──────────────────────────────┘ \n\- \ ⇧ \n\- \ Predicate \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────┐ \n\- \ │ λ(x : Bool) → if x then False else True │ \n\- \ └─────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Predicate \n\- \ \n\- \ \n\- \... but these are " <> _NOT <> " valid ❰if❱ expressions: \n\- \ \n\- \ \n\- \ ┌───────────────────────────┐ \n\- \ │ if 0 then \"Yes\" else \"No\" │ ❰0❱ does not have type ❰Bool❱ \n\- \ └───────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ if \"\" then False else True │ ❰\"\"❱ does not have type ❰Bool❱ \n\- \ └────────────────────────────┘ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You might be used to other programming languages that accept predicates other \n\- \ than ❰Bool❱ \n\- \ \n\- \ For example, some languages permit ❰0❱ or ❰\"\"❱ as valid predicates and treat\n\- \ them as equivalent to ❰False❱. However, the Dhall language does not permit \n\- \ this \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \Your ❰if❱ expression begins with the following predicate: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... that has type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but the predicate must instead have type ❰Bool❱ \n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (IfBranchMustBeTerm b expr0 expr1 expr2) =- ErrorMessages {..}- where- short = "❰if❱ branch is not a term"-- long =- "Explanation: Every ❰if❱ expression has a ❰then❱ and ❰else❱ branch, each of which\n\- \is an expression: \n\- \ \n\- \ \n\- \ Expression for ❰then❱ branch \n\- \ ⇩ \n\- \ ┌────────────────────────────────┐ \n\- \ │ if True then \"Hello, world!\" │ \n\- \ │ else \"Goodbye, world!\" │ \n\- \ └────────────────────────────────┘ \n\- \ ⇧ \n\- \ Expression for ❰else❱ branch \n\- \ \n\- \ \n\- \These expressions must be a “term”, where a “term” is defined as an expression \n\- \that has a type thas has kind ❰Type❱ \n\- \ \n\- \For example, the following expressions are all valid “terms”: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ 1 : Natural : Type │ ❰1❱ is a term with a type (❰Natural❱) of kind ❰Type❱\n\- \ └────────────────────┘ \n\- \ ⇧ \n\- \ term \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────┐ \n\- \ │ Natural/odd : Natural → Bool : Type │ ❰Natural/odd❱ is a term with a type\n\- \ └─────────────────────────────────────┘ (❰Natural → Bool❱) of kind ❰Type❱ \n\- \ ⇧ \n\- \ term \n\- \ \n\- \ \n\- \However, the following expressions are " <> _NOT <> " valid terms: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ Text : Type : Kind │ ❰Text❱ has kind (❰Type❱) of sort ❰Kind❱ and is \n\- \ └────────────────────┘ therefore not a term \n\- \ ⇧ \n\- \ type \n\- \ \n\- \ \n\- \ ┌───────────────────────────┐ \n\- \ │ List : Type → Type : Kind │ ❰List❱ has kind (❰Type → Type❱) of sort \n\- \ └───────────────────────────┘ ❰Kind❱ and is therefore not a term \n\- \ ⇧ \n\- \ type-level function \n\- \ \n\- \ \n\- \This means that you cannot define an ❰if❱ expression that returns a type. For \n\- \example, the following ❰if❱ expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────┐ \n\- \ │ if True then Text else Bool │ Invalid ❰if❱ expression \n\- \ └─────────────────────────────┘ \n\- \ ⇧ ⇧ \n\- \ type type \n\- \ \n\- \ \n\- \Your ❰" <> txt0 <> "❱ branch of your ❰if❱ expression is: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which has kind: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... of sort: \n\- \ \n\- \" <> txt3 <> "\n\- \ \n\- \... and is not a term. Therefore your ❰if❱ expression is not valid \n"- where- txt0 = if b then "then" else "else"- txt1 = insert expr0- txt2 = insert expr1- txt3 = insert expr2--prettyTypeMessage (IfBranchMismatch expr0 expr1 expr2 expr3) =- ErrorMessages {..}- where- short = "❰if❱ branches must have matching types\n"- <> "\n"- <> prettyDiff expr1 expr3-- long =- "Explanation: Every ❰if❱ expression has a ❰then❱ and ❰else❱ branch, each of which\n\- \is an expression: \n\- \ \n\- \ \n\- \ Expression for ❰then❱ branch \n\- \ ⇩ \n\- \ ┌────────────────────────────────┐ \n\- \ │ if True then \"Hello, world!\" │ \n\- \ │ else \"Goodbye, world!\" │ \n\- \ └────────────────────────────────┘ \n\- \ ⇧ \n\- \ Expression for ❰else❱ branch \n\- \ \n\- \ \n\- \These two expressions must have the same type. For example, the following ❰if❱ \n\- \expressions are all valid: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────┐ \n\- \ │ λ(b : Bool) → if b then 0 else 1 │ Both branches have type ❰Natural❱ \n\- \ └──────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ λ(b : Bool) → │ \n\- \ │ if b then Natural/even │ Both branches have type ❰Natural → Bool❱ \n\- \ │ else Natural/odd │ \n\- \ └────────────────────────────┘ \n\- \ \n\- \ \n\- \However, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ This branch has type ❰Natural❱ \n\- \ ⇩ \n\- \ ┌────────────────────────┐ \n\- \ │ if True then 0 │ \n\- \ │ else \"ABC\" │ \n\- \ └────────────────────────┘ \n\- \ ⇧ \n\- \ This branch has type ❰Text❱ \n\- \ \n\- \ \n\- \The ❰then❱ and ❰else❱ branches must have matching types, even if the predicate \n\- \is always ❰True❱ or ❰False❱ \n\- \ \n\- \Your ❰if❱ expression has the following ❰then❱ branch: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which has type: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... and the following ❰else❱ branch: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which has a different type: \n\- \ \n\- \" <> txt3 <> "\n\- \ \n\- \Fix your ❰then❱ and ❰else❱ branches to have matching types \n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2- txt3 = insert expr3--prettyTypeMessage (InvalidListType expr0) = ErrorMessages {..}- where- short = "Invalid type for ❰List❱ elements"-- long =- "Explanation: ❰List❱s can optionally document the type of their elements with a \n\- \type annotation, like this: \n\- \ \n\- \ \n\- \ ┌──────────────────────────┐ \n\- \ │ [1, 2, 3] : List Natural │ A ❰List❱ of three ❰Natural❱ numbers \n\- \ └──────────────────────────┘ \n\- \ ⇧ \n\- \ The type of the ❰List❱'s elements, which are ❰Natural❱ \n\- \ numbers \n\- \ \n\- \ \n\- \ ┌───────────────────┐ \n\- \ │ [] : List Natural │ An empty ❰List❱ \n\- \ └───────────────────┘ \n\- \ ⇧ \n\- \ You must specify the type when the ❰List❱ is empty \n\- \ \n\- \ \n\- \The element type must be a type and not something else. For example, the \n\- \following element types are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌──────────────┐ \n\- \ │ ... : List 1 │ \n\- \ └──────────────┘ \n\- \ ⇧ \n\- \ This is a ❰Natural❱ number and not a ❰Type❱ \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ ... : List Type │ \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This is a ❰Kind❱ and not a ❰Type❱ \n\- \ \n\- \ \n\- \You declared that the ❰List❱'s elements should have type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a ❰Type❱ \n"- where- txt0 = insert expr0--prettyTypeMessage MissingListType = do- ErrorMessages {..}- where- short = "An empty list requires a type annotation"-- long =- "Explanation: Lists do not require a type annotation if they have at least one \n\- \element: \n\- \ \n\- \ \n\- \ ┌───────────┐ \n\- \ │ [1, 2, 3] │ The compiler can infer that this list has type ❰List Natural❱\n\- \ └───────────┘ \n\- \ \n\- \ \n\- \However, empty lists still require a type annotation: \n\- \ \n\- \ \n\- \ ┌───────────────────┐ \n\- \ │ [] : List Natural │ This type annotation is mandatory \n\- \ └───────────────────┘ \n\- \ \n\- \ \n\- \You cannot supply an empty list without a type annotation \n"--prettyTypeMessage (MismatchedListElements i expr0 _expr1 expr2) =- ErrorMessages {..}- where- short = "List elements should all have the same type\n"- <> "\n"- <> prettyDiff expr0 expr2-- long =- "Explanation: Every element in a list must have the same type \n\- \ \n\- \For example, this is a valid ❰List❱: \n\- \ \n\- \ \n\- \ ┌───────────┐ \n\- \ │ [1, 2, 3] │ Every element in this ❰List❱ is a ❰Natural❱ number \n\- \ └───────────┘ \n\- \ \n\- \ \n\- \.. but this is " <> _NOT <> " a valid ❰List❱: \n\- \ \n\- \ \n\- \ ┌───────────────┐ \n\- \ │ [1, \"ABC\", 3] │ The first and second element have different types \n\- \ └───────────────┘ \n\- \ \n\- \ \n\- \Your first ❰List❱ element has this type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... but the element at index #" <> txt1 <> " has this type instead: \n\- \ \n\- \" <> txt3 <> "\n"- where- txt0 = insert expr0- txt1 = pretty i- txt3 = insert expr2--prettyTypeMessage (InvalidListElement i expr0 _expr1 expr2) =- ErrorMessages {..}- where- short = "List element has the wrong type\n"- <> "\n"- <> prettyDiff expr0 expr2-- long =- "Explanation: Every element in the list must have a type matching the type \n\- \annotation at the end of the list \n\- \ \n\- \For example, this is a valid ❰List❱: \n\- \ \n\- \ \n\- \ ┌──────────────────────────┐ \n\- \ │ [1, 2, 3] : List Natural │ Every element in this ❰List❱ is an ❰Natural❱ \n\- \ └──────────────────────────┘ \n\- \ \n\- \ \n\- \.. but this is " <> _NOT <> " a valid ❰List❱: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────┐ \n\- \ │ [1, \"ABC\", 3] : List Natural │ The second element is not an ❰Natural❱ \n\- \ └──────────────────────────────┘ \n\- \ \n\- \ \n\- \Your ❰List❱ elements should have this type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... but the element at index #" <> txt1 <> " has this type instead: \n\- \ \n\- \" <> txt3 <> "\n"- where- txt0 = insert expr0- txt1 = pretty i- txt3 = insert expr2--prettyTypeMessage (InvalidOptionalType expr0) = ErrorMessages {..}- where- short = "Invalid type for ❰Optional❱ element"-- long =- "Explanation: The legacy ❰List❱-like syntax for ❰Optional❱ literals ends with a \n\- \type annotation for the element that might be present, like this: \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ [1] : Optional Natural │ An optional element that's present \n\- \ └────────────────────────┘ \n\- \ ⇧ \n\- \ The type of the ❰Optional❱ element, which is an ❰Natural❱ \n\- \ number \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ [] : Optional Natural │ An optional element that's absent \n\- \ └────────────────────────┘ \n\- \ ⇧ \n\- \ You still specify the type even when the element is absent \n\- \ \n\- \ \n\- \The element type must be a type and not something else. For example, the \n\- \following element types are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ ... : Optional 1 │ \n\- \ └──────────────────┘ \n\- \ ⇧ \n\- \ This is a ❰Natural❱ number and not a ❰Type❱ \n\- \ \n\- \ \n\- \ ┌─────────────────────┐ \n\- \ │ ... : Optional Type │ \n\- \ └─────────────────────┘ \n\- \ ⇧ \n\- \ This is a ❰Kind❱ and not a ❰Type❱ \n\- \ \n\- \ \n\- \Even if the element is absent you still must specify a valid type \n\- \ \n\- \You declared that the ❰Optional❱ element should have type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a ❰Type❱ \n"- where- txt0 = insert expr0--prettyTypeMessage (InvalidOptionalElement expr0 expr1 expr2) = ErrorMessages {..}- where- short = "❰Optional❱ element has the wrong type\n"- <> "\n"- <> prettyDiff expr0 expr2-- long =- "Explanation: An ❰Optional❱ element must have a type matching the type annotation\n\- \ \n\- \For example, this is a valid ❰Optional❱ value: \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ [1] : Optional Natural │ ❰1❱ is a ❰Natural❱ number, which matches the \n\- \ └────────────────────────┘ number \n\- \ \n\- \ \n\- \... but this is " <> _NOT <> " a valid ❰Optional❱ value: \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ [\"ABC\"] : Optional Natural │ ❰\"ABC\"❱ is not a ❰Natural❱ number \n\- \ └────────────────────────────┘ \n\- \ \n\- \ \n\- \Your ❰Optional❱ element should have this type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... but the element you provided: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... has this type instead: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2--prettyTypeMessage (InvalidSome expr0 expr1 expr2) = ErrorMessages {..}- where- short = "❰Some❱ argument has the wrong type"-- long =- "Explanation: The ❰Some❱ constructor expects an argument that is a term, where \n\- \the type of the type of a term must be ❰Type❱ \n\- \ \n\- \For example, this is a valid use of ❰Some❱: \n\- \ \n\- \ \n\- \ ┌────────┐ \n\- \ │ Some 1 │ ❰1❱ is a valid term because ❰1 : Natural : Type❱ \n\- \ └────────┘ \n\- \ \n\- \ \n\- \... but this is " <> _NOT <> " a valid ❰Optional❱ value: \n\- \ \n\- \ \n\- \ ┌───────────┐ \n\- \ │ Some Text │ ❰Text❱ is not a valid term because ❰Text : Type : Kind ❱ \n\- \ └───────────┘ \n\- \ \n\- \ \n\- \The ❰Some❱ argument you provided: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... has this type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but the type of that type is: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... which is not ❰Type❱ \n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2--prettyTypeMessage (InvalidFieldType k expr0) = ErrorMessages {..}- where- short = "Invalid field type"-- long =- "Explanation: Every record type annotates each field with a ❰Type❱, a ❰Kind❱, or \n\- \a ❰Sort❱ like this: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────────┐ \n\- \ │ { foo : Natural, bar : Integer, baz : Text } │ Every field is annotated \n\- \ └──────────────────────────────────────────────┘ with a ❰Type❱ \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ { foo : Type, bar : Type } │ Every field is annotated \n\- \ └────────────────────────────┘ with a ❰Kind❱ \n\- \ \n\- \ \n\- \However, the types of fields may " <> _NOT <> " be term-level values: \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ { foo : Natural, bar : 1 } │ Invalid record type \n\- \ └────────────────────────────┘ \n\- \ ⇧ \n\- \ ❰1❱ is a ❰Natural❱ number and not a ❰Type❱, \n\- \ ❰Kind❱, or ❰Sort❱ \n\- \ \n\- \ \n\- \You provided a record type with a field named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... annotated with the following expression: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is neither a ❰Type❱, a ❰Kind❱, nor a ❰Sort❱ \n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (FieldAnnotationMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}- where- short = "Field annotation mismatch"-- long =- "Explanation: Every record type annotates each field with a ❰Type❱ or a ❰Kind❱, \n\- \like this: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────────┐ \n\- \ │ { foo : Natural, bar : Integer, baz : Text } │ Every field is annotated \n\- \ └──────────────────────────────────────────────┘ with a ❰Type❱ \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ { foo : Type, bar : Type } │ Every field is annotated \n\- \ └────────────────────────────┘ with a ❰Kind❱ \n\- \ \n\- \ \n\- \However, you cannot have a record type with both a ❰Type❱ and ❰Kind❱ annotation:\n\- \ \n\- \ \n\- \ This is a ❰Type❱ annotation \n\- \ ⇩ \n\- \ ┌───────────────────────────────┐ \n\- \ │ { foo : Natural, bar : Type } │ Invalid record type \n\- \ └───────────────────────────────┘ \n\- \ ⇧ \n\- \ ... but this is a ❰Kind❱ annotation \n\- \ \n\- \ \n\- \You provided a record type with a field named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... annotated with the following expression: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is a " <> level c1 <> " whereas another field named: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... annotated with the following expression: \n\- \ \n\- \" <> txt3 <> "\n\- \ \n\- \... is a " <> level c0 <> ", which does not match \n"- where- txt0 = insert k0- txt1 = insert expr0- txt2 = insert k1- txt3 = insert expr1-- level Type = "❰Type❱"- level Kind = "❰Kind❱"- level Sort = "❰Sort❱"--prettyTypeMessage (FieldMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}- where- short = "Field mismatch"-- long =- "Explanation: Every record has fields that can be either terms or types, like \n\- \this: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = True, baz = \"ABC\" } │ Every field is a term \n\- \ └──────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌───────────────────────────────┐ \n\- \ │ { foo = Natural, bar = Text } │ Every field is a type \n\- \ └───────────────────────────────┘ \n\- \ \n\- \ \n\- \However, you cannot have a record that stores both terms and types: \n\- \ \n\- \ \n\- \ This is a term \n\- \ ⇩ \n\- \ ┌─────────────────────────┐ \n\- \ │ { foo = 1, bar = Bool } │ Invalid record \n\- \ └─────────────────────────┘ \n\- \ ⇧ \n\- \ ... but this is a type \n\- \ \n\- \ \n\- \You provided a record with a field named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... whose value was: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is a " <> level c1 <> " whereas another field named: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... whose value was: \n\- \ \n\- \" <> txt3 <> "\n\- \ \n\- \... is a " <> level c0 <> ", which does not match \n"- where- txt0 = insert k0- txt1 = insert expr0- txt2 = insert k1- txt3 = insert expr1-- level Type = "term"- level Kind = "type"- level Sort = "kind"--prettyTypeMessage (InvalidField k expr0) = ErrorMessages {..}- where- short = "Invalid field"-- long =- "Explanation: Every record literal is a set of fields assigned to values, like \n\- \this: \n\- \ \n\- \ ┌────────────────────────────────────────┐ \n\- \ │ { foo = 100, bar = True, baz = \"ABC\" } │ \n\- \ └────────────────────────────────────────┘ \n\- \ \n\- \However, fields can only be terms and or ❰Type❱s and not ❰Kind❱s \n\- \ \n\- \For example, the following record literal is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ { foo = Type } │ \n\- \ └────────────────┘ \n\- \ ⇧ \n\- \ ❰Type❱ is a ❰Kind❱, which is not allowed \n\- \ \n\- \ \n\- \You provided a record literal with a field named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... whose value is: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not a term or ❰Type❱ \n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (InvalidAlternativeType k expr0) = ErrorMessages {..}- where- short = "Invalid alternative type"-- long =- "Explanation: Every union type specifies the type of each alternative, like this:\n\- \ \n\- \ \n\- \ The type of the first alternative is ❰Bool❱ \n\- \ ⇩ \n\- \ ┌──────────────────────────────────┐ \n\- \ │ < Left : Bool, Right : Natural > │ A union type with two alternatives \n\- \ └──────────────────────────────────┘ \n\- \ ⇧ \n\- \ The type of the second alternative is ❰Natural❱ \n\- \ \n\- \ \n\- \However, these alternatives can only be annotated with ❰Type❱s, ❰Kind❱s, or \n\- \❰Sort❱s. For example, the following union types are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ < Left : Bool, Right : 1 > │ Invalid union type \n\- \ └────────────────────────────┘ \n\- \ ⇧ \n\- \ This is a ❰Natural❱ and not a ❰Type❱, ❰Kind❱, or \n\- \ ❰Sort❱ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You accidentally typed ❰:❱ instead of ❰=❱ for a union literal with one \n\- \ alternative: \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ < Example : 1 > │ \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This could be ❰=❱ instead \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided a union type with an alternative named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... annotated with the following expression which is not a ❰Type❱, ❰Kind❱, or \n\- \❰Sort❱: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (InvalidAlternative k expr0) = ErrorMessages {..}- where- short = "Invalid alternative"-- long =- "Explanation: Every union literal begins by selecting one alternative and \n\- \specifying the value for that alternative, like this: \n\- \ \n\- \ \n\- \ Select the ❰Left❱ alternative, whose value is ❰True❱ \n\- \ ⇩ \n\- \ ┌──────────────────────────────────┐ \n\- \ │ < Left = True, Right : Natural > │ A union literal with two alternatives \n\- \ └──────────────────────────────────┘ \n\- \ \n\- \ \n\- \However, this value must be a term, type, or kind. For example, the following \n\- \values are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────┐ \n\- \ │ < Left = Sort > │ Invalid union literal \n\- \ └─────────────────┘ \n\- \ ⇧ \n\- \ This is not a term, type, or kind \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided a union literal with an alternative named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... whose value is: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not a term, type, or kind. \n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (AlternativeAnnotationMismatch k0 expr0 c0 k1 expr1 c1) = ErrorMessages {..}- where- short = "Alternative annotation mismatch"-- long =- "Explanation: Every union type annotates each alternative with a ❰Type❱ or a \n\- \❰Kind❱, like this: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────┐ \n\- \ │ < Left : Natural | Right : Bool > │ Every alternative is annotated with a\n\- \ └───────────────────────────────────┘ ❰Type❱ \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────┐ \n\- \ │ < Foo : Type → Type | Bar : Type > │ Every alternative is annotated with \n\- \ └────────────────────────────────────┘ a ❰Kind❱ \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ < Baz : Kind > │ Every alternative is annotated with a ❰Sort❱ \n\- \ └────────────────┘ \n\- \ \n\- \ \n\- \However, you cannot have a union type that mixes ❰Type❱s, ❰Kind❱s, or ❰Sort❱s \n\- \for the annotations: \n\- \ \n\- \ \n\- \ This is a ❰Type❱ annotation \n\- \ ⇩ \n\- \ ┌───────────────────────────────┐ \n\- \ │ { foo : Natural, bar : Type } │ Invalid union type \n\- \ └───────────────────────────────┘ \n\- \ ⇧ \n\- \ ... but this is a ❰Kind❱ annotation \n\- \ \n\- \ \n\- \You provided a union type with an alternative named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... annotated with the following expression: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is a " <> level c0 <> " whereas another alternative named: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... annotated with the following expression: \n\- \ \n\- \" <> txt3 <> "\n\- \ \n\- \... is a " <> level c1 <> ", which does not match \n"- where- txt0 = insert k0- txt1 = insert expr0- txt2 = insert k1- txt3 = insert expr1-- level Type = "❰Type❱"- level Kind = "❰Kind❱"- level Sort = "❰Sort❱"--prettyTypeMessage (ListAppendMismatch expr0 expr1) = ErrorMessages {..}- where- short = "You can only append ❰List❱s with matching element types\n"- <> "\n"- <> prettyDiff expr0 expr1-- long =- "Explanation: You can append two ❰List❱s using the ❰#❱ operator, like this: \n\- \ \n\- \ \n\- \ ┌────────────────────┐ \n\- \ │ [1, 2, 3] # [4, 5] │ \n\- \ └────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot append two ❰List❱s if they have different element types. \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ These elements have type ❰Natural❱ \n\- \ ⇩ \n\- \ ┌───────────────────────────┐ \n\- \ │ [1, 2, 3] # [True, False] │ Invalid: the element types don't match \n\- \ └───────────────────────────┘ \n\- \ ⇧ \n\- \ These elements have type ❰Bool❱ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to append a ❰List❱ thas has elements of type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... with another ❰List❱ that has elements of type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... and those two types do not match \n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (DuplicateAlternative k) = ErrorMessages {..}- where- short = "Duplicate union alternative"-- long =- "Explanation: Unions may not have two alternatives that share the same name \n\- \ \n\- \For example, the following expressions are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────┐ \n\- \ │ < foo = True | foo : Text > │ Invalid: ❰foo❱ appears twice \n\- \ └─────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────┐ \n\- \ │ < foo = 1 | bar : Bool | bar : Text > │ Invalid: ❰bar❱ appears twice \n\- \ └───────────────────────────────────────┘ \n\- \ \n\- \ \n\- \You have more than one alternative named: \n\- \ \n\- \" <> txt0 <> "\n"- where- txt0 = insert k--prettyTypeMessage (MustCombineARecord c expr0 expr1) = ErrorMessages {..}- where- short = "You can only combine records"-- long =- "Explanation: You can combine records using the ❰" <> op <> "❱ operator, like this:\n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } " <> op <> " { baz = True } │ \n\- \ └───────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────┐ \n\- \ │ λ(r : { foo : Bool }) → r " <> op <> " { bar = \"ABC\" } │ \n\- \ └─────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot combine values that are not records. \n\- \ \n\- \For example, the following expressions are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } " <> op <> " 1 │ \n\- \ └──────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: Not a record \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } " <> op <> " { baz : Bool } │ \n\- \ └───────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: This is a record type and not a record\n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } " <> op <> " < baz = True > │ \n\- \ └───────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: This is a union and not a record \n\- \ \n\- \ \n\- \You tried to combine the following value: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a record, but is actually a: \n\- \ \n\- \" <> txt1 <> "\n"- where- op = pretty c- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (RecordMismatch c expr0 expr1 const0 const1) = ErrorMessages {..}- where- short = "Record mismatch"-- long =- "Explanation: You can only use the ❰" <> op <> "❱ operator to combine records if they both \n\- \store terms or both store types. \n\- \ \n\- \ \n\- \ ┌──────────────────────────────┐ \n\- \ │ { foo = 1 } " <> op <> " { baz = True } │ Valid: Both records store terms \n\- \ └──────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo = Bool } " <> op <> " { bar = Text } │ Valid: Both records store types \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot combine two records if one of the records stores types and \n\- \the other record stores terms. \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ Record of terms \n\- \ ⇩ \n\- \ ┌──────────────────────────────┐ \n\- \ │ { foo = 1 } " <> op <> " { bar = Text } │ Invalid: Mixing terms and types \n\- \ └──────────────────────────────┘ \n\- \ ⇧ \n\- \ Record of types \n\- \ \n\- \ \n\- \You tried to combine the following record: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which stores " <> class0 <> ", with the following record: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which stores " <> class1 <> ". \n"- where- op = pretty c-- txt0 = insert expr0- txt1 = insert expr1-- toClass Type = "terms"- toClass Kind = "types"- toClass Sort = "kinds"-- class0 = toClass const0- class1 = toClass const1--prettyTypeMessage (CombineTypesRequiresRecordType expr0 expr1) =- ErrorMessages {..}- where- short = "❰⩓❱ requires arguments that are record types"-- long =- "Explanation: You can only use the ❰⩓❱ operator on arguments that are record type\n\- \literals, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────┐ \n\- \ │ { age : Natural } ⩓ { name : Text } │ \n\- \ └─────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot use the ❰⩓❱ operator on any other type of arguments. For \n\- \example, you cannot use variable arguments: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────┐ \n\- \ │ λ(t : Type) → t ⩓ { name : Text } │ Invalid: ❰t❱ might not be a record \n\- \ └───────────────────────────────────┘ type \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to supply the following argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which normalized to: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not a record type literal \n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (RecordTypeMismatch const0 const1 expr0 expr1) =- ErrorMessages {..}- where- short = "Record type mismatch"-- long =- "Explanation: You can only use the ❰⩓❱ operator on record types if they are both \n\- \ ❰Type❱s or ❰Kind❱s: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────┐ \n\- \ │ { age : Natural } ⩓ { name : Text } │ Valid: Both arguments are ❰Type❱s \n\- \ └─────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────┐ \n\- \ │ { Input : Type } ⩓ { Output : Type } │ Valid: Both arguments are ❰Kind❱s \n\- \ └──────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot combine a ❰Type❱ and a ❰Kind❱: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────┐ \n\- \ │ { Input : Type } ⩓ { name : Text } │ Invalid: The arguments do not match \n\- \ └────────────────────────────────────┘ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to combine the following record type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... with this record types: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but the former record type is a: \n\- \ \n\- \" <> txt2 <> "\n\- \ \n\- \... but the latter record type is a: \n\- \ \n\- \" <> txt3 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert const0- txt3 = insert const1--prettyTypeMessage (FieldCollision k) = ErrorMessages {..}- where- short = "Field collision"-- long =- "Explanation: You can combine records or record types if they don't share any \n\- \fields in common, like this: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } ∧ { baz = True } │ \n\- \ └───────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo : Text } ⩓ { bar : Bool } │ \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────────┐ \n\- \ │ λ(r : { baz : Bool}) → { foo = 1 } ∧ r │ \n\- \ └────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot merge two records that share the same field unless the field \n\- \is a record on both sides. \n\- \ \n\- \For example, the following expressions are " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } ∧ { foo = True } │ Invalid: Colliding ❰foo❱ \n\- \ └───────────────────────────────────────────┘ fields \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo : Bool } ∧ { foo : Text } │ Invalid: Colliding ❰foo❱ fields \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but the following expressions are valid: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────────────┐ \n\- \ │ { foo = { bar = True } } ∧ { foo = { baz = 1 } } │ Valid: Both ❰foo❱ \n\- \ └──────────────────────────────────────────────────┘ fields are records \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────┐ \n\- \ │ { foo : { bar : Bool } } ⩓ { foo : { baz : Text } } │ Valid: Both ❰foo❱ \n\- \ └─────────────────────────────────────────────────────┘ fields are records \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You tried to use ❰∧❱ to update a field's value, like this: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────────┐ \n\- \ │ { foo = 1, bar = \"ABC\" } ∧ { foo = 2 } │ \n\- \ └────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid attempt to update ❰foo❱'s value to ❰2❱\n\- \ \n\- \ Field updates are intentionally not allowed as the Dhall language discourages \n\- \ patch-oriented programming \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You combined two records that share the following field: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not allowed \n"- where- txt0 = insert k--prettyTypeMessage (MustMergeARecord expr0 expr1) = ErrorMessages {..}- where- short = "❰merge❱ expects a record of handlers"-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but the first argument to ❰merge❱ must be a record and not some other type. \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────┐ \n\- \ │ let handler = λ(x : Bool) → x │ \n\- \ │ in merge handler < Foo = True > : True │ \n\- \ └─────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: ❰handler❱ isn't a record \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You accidentally provide an empty record type instead of an empty record when \n\- \ you ❰merge❱ an empty union: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────┐ \n\- \ │ λ(x : <>) → λ(a : Type) → merge {} x : a │ \n\- \ └──────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ This should be ❰{=}❱ instead \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided the following handler: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a record, but is actually a value of type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (MustMergeUnion expr0 expr1) = ErrorMessages {..}- where- short = "❰merge❱ expects a union"-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but the second argument to ❰merge❱ must be a union and not some other type. \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────┐ \n\- \ │ let handlers = { Foo = λ(x : Bool) → x } │ \n\- \ │ in merge handlers True : True │ \n\- \ └──────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: ❰True❱ isn't a union \n\- \ \n\- \ \n\- \You tried to ❰merge❱ this expression: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a union, but is actually a value of type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (UnusedHandler ks) = ErrorMessages {..}- where- short = "Unused handler"-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you must provide exactly one handler per alternative in the union. You \n\- \cannot supply extra handlers \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 > │ The ❰Right❱ alternative is \n\- \ │ in let handlers = │ missing \n\- \ │ { Left = Natural/even │ \n\- \ │ , Right = λ(x : Bool) → x │ Invalid: ❰Right❱ handler isn't \n\- \ │ } │ used \n\- \ │ in merge handlers union : Bool │ \n\- \ └───────────────────────────────────────┘ \n\- \ \n\- \ \n\- \You provided the following handlers: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which had no matching alternatives in the union you tried to ❰merge❱ \n"- where- txt0 = insert (Text.intercalate ", " (Data.Set.toList ks))--prettyTypeMessage (MissingHandler ks) = ErrorMessages {..}- where- short = "Missing handler"-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you must provide exactly one handler per alternative in the union. You \n\- \cannot omit any handlers \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ Invalid: Missing ❰Right❱ handler \n\- \ ⇩ \n\- \ ┌─────────────────────────────────────────────────┐ \n\- \ │ let handlers = { Left = Natural/even } │ \n\- \ │ in let union = < Left = 2 | Right : Bool > │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \Note that you need to provide handlers for other alternatives even if those \n\- \alternatives are never used \n\- \ \n\- \You need to supply the following handlers: \n\- \ \n\- \" <> txt0 <> "\n"- where- txt0 = insert (Text.intercalate ", " (Data.Set.toList ks))--prettyTypeMessage MissingMergeType =- ErrorMessages {..}- where- short = "An empty ❰merge❱ requires a type annotation"-- long =- "Explanation: A ❰merge❱ does not require a type annotation if the union has at \n\- \least one alternative, like this \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \However, you must provide a type annotation when merging an empty union: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────┐ \n\- \ │ λ(a : <>) → merge {=} a : Bool │ \n\- \ └────────────────────────────────┘ \n\- \ ⇧ \n\- \ This can be any type \n\- \ \n\- \ \n\- \You can provide any type at all as the annotation, since merging an empty \n\- \union can produce any type of output \n"--prettyTypeMessage (HandlerInputTypeMismatch expr0 expr1 expr2) =- ErrorMessages {..}- where- short = "Wrong handler input type\n"- <> "\n"- <> prettyDiff expr1 expr2-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... as long as the input type of each handler function matches the type of the \n\- \corresponding alternative: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────────────────┐ \n\- \ │ union : < Left : Natural | Right : Bool > │ \n\- \ └───────────────────────────────────────────────────────────┘ \n\- \ ⇧ ⇧ \n\- \ These must match These must match \n\- \ ⇩ ⇩ \n\- \ ┌───────────────────────────────────────────────────────────┐ \n\- \ │ handlers : { Left : Natural → Bool, Right : Bool → Bool } │ \n\- \ └───────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ Invalid: Doesn't match the type of the ❰Right❱ alternative \n\- \ ⇩ \n\- \ ┌──────────────────────────────────────────────────────────────────────┐ \n\- \ │ let handlers = { Left = Natural/even | Right = λ(x : Text) → x } │ \n\- \ │ in let union = < Left = 2 | Right : Bool > │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └──────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \Your handler for the following alternative: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... needs to accept an input value of type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but actually accepts an input value of a different type: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2--prettyTypeMessage (InvalidHandlerOutputType expr0 expr1 expr2) =- ErrorMessages {..}- where- short = "Wrong handler output type\n"- <> "\n"- <> prettyDiff expr1 expr2-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... as long as the output type of each handler function matches the declared \n\- \type of the result: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────────────────┐ \n\- \ │ handlers : { Left : Natural → Bool, Right : Bool → Bool } │ \n\- \ └───────────────────────────────────────────────────────────┘ \n\- \ ⇧ ⇧ \n\- \ These output types ... \n\- \ \n\- \ ... must match the declared type of the ❰merge❱ \n\- \ ⇩ \n\- \ ┌─────────────────────────────┐ \n\- \ │ merge handlers union : Bool │ \n\- \ └─────────────────────────────┘ \n\- \ \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Text │ \n\- \ └──────────────────────────────────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: Doesn't match output of either handler\n\- \ \n\- \ \n\- \Your handler for the following alternative: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... needs to return an output value of type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but actually returns an output value of a different type: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1- txt2 = insert expr2--prettyTypeMessage (HandlerOutputTypeMismatch key0 expr0 key1 expr1) =- ErrorMessages {..}- where- short = "Handlers should have the same output type\n"- <> "\n"- <> prettyDiff expr0 expr1-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... as long as the output type of each handler function is the same: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────────────────┐ \n\- \ │ handlers : { Left : Natural → Bool, Right : Bool → Bool } │ \n\- \ └───────────────────────────────────────────────────────────┘ \n\- \ ⇧ ⇧ \n\- \ These output types both match \n\- \ \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = │ \n\- \ │ { Left = λ(x : Natural) → x │ This outputs ❰Natural❱ \n\- \ │ , Right = λ(x : Bool ) → x │ This outputs ❰Bool❱ \n\- \ │ } │ \n\- \ │ in merge handlers union │ \n\- \ └─────────────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: The handlers in this record don't have matching outputs\n\- \ \n\- \ \n\- \The handler for the ❰" <> txt0 <> "❱ alternative has this output type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but the handler for the ❰" <> txt2 <> "❱ alternative has this output type instead:\n\- \ \n\- \" <> txt3 <> "\n"- where- txt0 = pretty key0- txt1 = insert expr0- txt2 = pretty key1- txt3 = insert expr1--prettyTypeMessage (HandlerNotAFunction k expr0) = ErrorMessages {..}- where- short = "Handler is not a function"-- long =- "Explanation: You can ❰merge❱ the alternatives of a union using a record with one\n\- \handler per alternative, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────────────────────┐ \n\- \ │ let union = < Left = 2 | Right : Bool > │ \n\- \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\- \ │ in merge handlers union : Bool │ \n\- \ └─────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... as long as each handler is a function \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────┐ \n\- \ │ merge { Foo = True } < Foo = 1 > : Bool │ \n\- \ └─────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: Not a function \n\- \ \n\- \ \n\- \Your handler for this alternative: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... has the following type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not the type of a function \n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (ConstructorsRequiresAUnionType expr0 expr1) = ErrorMessages {..}- where- short = "❰constructors❱ requires a union type"-- long =- "Explanation: You can only use the ❰constructors❱ keyword on an argument that is \n\- \a union type literal, like this: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────┐ \n\- \ │ constructors < Left : Natural, Right : Bool > │ \n\- \ └───────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot use the ❰constructors❱ keyword on any other type of argument.\n\- \For example, you cannot use a variable argument: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────┐ \n\- \ │ λ(t : Type) → constructors t │ Invalid: ❰t❱ might not be a union type \n\- \ └──────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────┐ \n\- \ │ let t : Type = < Left : Natural, Right : Bool > │ Invalid: Type-checking \n\- \ │ in constructors t │ precedes normalization \n\- \ └─────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \However, you can import the union type argument: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────┐ \n\- \ │ constructors ./unionType.dhall │ Valid: Import resolution precedes \n\- \ └────────────────────────────────┘ type-checking \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to supply the following argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which normalized to: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which is not a union type literal \n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (CantAccess lazyText0 expr0 expr1) = ErrorMessages {..}- where- short = "Not a record or a union"-- long =- "Explanation: You can only access fields on records or unions, like this: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────┐ \n\- \ │ { foo = True, bar = \"ABC\" }.foo │ This is valid ... \n\- \ └───────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ λ(r : { foo : Bool, bar : Text }) → r.foo │ ... and so is this \n\- \ └───────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ < foo : Bool | bar : Text >.foo │ ... and so is this \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────────────┐ \n\- \ │ λ(r : < foo : Bool | bar : Text >) → r.foo │ ... and so is this \n\- \ └────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot access fields on non-record expressions \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌───────┐ \n\- \ │ 1.foo │ \n\- \ └───────┘ \n\- \ ⇧ \n\- \ Invalid: Not a record \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to access the field: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... on the following expression which is not a record nor a union type: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but is actually an expression of type: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert lazyText0- txt1 = insert expr0- txt2 = insert expr1--prettyTypeMessage (CantProject lazyText0 expr0 expr1) = ErrorMessages {..}- where- short = "Not a record"-- long =- "Explanation: You can only project fields on records, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────────────────┐ \n\- \ │ { foo = True, bar = \"ABC\", baz = 1 }.{ foo, bar } │ This is valid ... \n\- \ └─────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────────────────────────────────────┐ \n\- \ │ λ(r : { foo : Bool, bar : Text , baz : Natural }) → r.{ foo, bar } │ ... and so is this \n\- \ └────────────────────────────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot project fields on non-record expressions \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ 1.{ foo, bar } │ \n\- \ └────────────────┘ \n\- \ ⇧ \n\- \ Invalid: Not a record \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You accidentally try to project fields of a union instead of a record, like \n\- \ this: \n\- \ \n\- \ \n\- \ ┌────────────────────────────────────┐ \n\- \ │ < foo : a | bar : b >.{ foo, bar } │ \n\- \ └────────────────────────────────────┘ \n\- \ ⇧ \n\- \ This is a union, not a record \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to access the fields: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... on the following expression which is not a record: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... but is actually an expression of type: \n\- \ \n\- \" <> txt2 <> "\n"- where- txt0 = insert lazyText0- txt1 = insert expr0- txt2 = insert expr1--prettyTypeMessage (CantProjectByExpression expr) = ErrorMessages {..}- where- short = "Selector is not a record type"-- long =- "Explanation: You can project by an expression if that expression is a record \n\- \type: \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo = True }.({ foo : Bool }) │ This is valid ... \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────────────┐ \n\- \ │ λ(r : { foo : Bool }) → r.{ foo : Bool } │ ... and so is this \n\- \ └──────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you cannot project by any other type of expression: \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ { foo = True }.(True) │ \n\- \ └───────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: Not a record type \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You accidentally try to project by a record value instead of a record type, \n\- \ like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ let T = { foo : Bool } │ \n\- \ │ │ \n\- \ │ let x = { foo = True , bar = 1} │ \n\- \ │ │ \n\- \ │ let y = { foo = False, bar = 2} │ \n\- \ │ │ \n\- \ │ in x.(y) │ \n\- \ └─────────────────────────────────┘ \n\- \ ⇧ \n\- \ The user might have meant ❰T❱ here \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You tried to project out the following type: \n\- \ \n\- \" <> txt <> "\n\- \ \n\- \... which is not a record type \n"- where- txt = insert expr--prettyTypeMessage (MissingField k expr0) = ErrorMessages {..}- where- short = "Missing record field"-- long =- "Explanation: You can only access fields on records, like this: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo = True, bar = \"ABC\" }.foo │ This is valid ... \n\- \ └─────────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────┐ \n\- \ │ λ(r : { foo : Bool, bar : Text }) → r.foo │ ... and so is this \n\- \ └───────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \... but you can only access fields if they are present \n\- \ \n\- \For example, the following expression is " <> _NOT <> " valid: \n\- \ \n\- \ ┌─────────────────────────────────┐ \n\- \ │ { foo = True, bar = \"ABC\" }.qux │ \n\- \ └─────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: the record has no ❰qux❱ field \n\- \ \n\- \You tried to access a field named: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... but the field is missing because the record only defines the following \n\- \fields: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert k- txt1 = insert expr0--prettyTypeMessage (CantAnd expr0 expr1) =- buildBooleanOperator "&&" expr0 expr1--prettyTypeMessage (CantOr expr0 expr1) =- buildBooleanOperator "||" expr0 expr1--prettyTypeMessage (CantEQ expr0 expr1) =- buildBooleanOperator "==" expr0 expr1--prettyTypeMessage (CantNE expr0 expr1) =- buildBooleanOperator "!=" expr0 expr1--prettyTypeMessage (CantInterpolate expr0 expr1) = ErrorMessages {..}- where- short = "You can only interpolate ❰Text❱"-- long =- "Explanation: Text interpolation only works on expressions of type ❰Text❱ \n\- \ \n\- \For example, these are all valid uses of string interpolation: \n\- \ \n\- \ \n\- \ ┌──────────────────┐ \n\- \ │ \"ABC${\"DEF\"}GHI\" │ \n\- \ └──────────────────┘ \n\- \ \n\- \ \n\- \ ┌────────────────────────────┐ \n\- \ │ λ(x : Text) → \"ABC${x}GHI\" │ \n\- \ └────────────────────────────┘ \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────┐ \n\- \ │ λ(age : Natural) → \"Age: ${Natural/show age}\" │ \n\- \ └───────────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You might have thought that string interpolation automatically converts the \n\- \ interpolated value to a ❰Text❱ representation of that value: \n\- \ \n\- \ \n\- \ ┌──────────────────────────────────┐ \n\- \ │ λ(age : Natural) → \"Age: ${age}\" │ \n\- \ └──────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid: ❰age❱ has type ❰Natural❱ \n\- \ \n\- \ \n\- \● You might have forgotten to escape a string interpolation that you wanted \n\- \ Dhall to ignore and pass through: \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ \"echo ${HOME}\" │ \n\- \ └────────────────┘ \n\- \ ⇧ \n\- \ ❰HOME❱ is not in scope and this might have meant to use ❰\\${HOME}❱\n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You interpolated this expression: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which does not have type ❰Text❱ but instead has type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (CantTextAppend expr0 expr1) = ErrorMessages {..}- where- short = "❰++❱ only works on ❰Text❱"-- long =- "Explanation: The ❰++❱ operator expects two arguments that have type ❰Text❱ \n\- \ \n\- \For example, this is a valid use of ❰++❱: \n\- \ \n\- \ \n\- \ ┌────────────────┐ \n\- \ │ \"ABC\" ++ \"DEF\" │ \n\- \ └────────────────┘ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You might have thought that ❰++❱ was the operator to combine two lists: \n\- \ \n\- \ \n\- \ ┌────────────────────────┐ \n\- \ │ [1, 2, 3] ++ [4, 5, 6] │ Not valid \n\- \ └────────────────────────┘ \n\- \ \n\- \ \n\- \ ... but the list concatenation operator is actually ❰#❱: \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ [1, 2, 3] # [4, 5, 6] │ Valid \n\- \ └───────────────────────┘ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided this argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which does not have type ❰Text❱ but instead has type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (CantListAppend expr0 expr1) = ErrorMessages {..}- where- short = "❰#❱ only works on ❰List❱s"-- long =- "Explanation: The ❰#❱ operator expects two arguments that are both ❰List❱s \n\- \ \n\- \For example, this is a valid use of ❰#❱: \n\- \ \n\- \ \n\- \ ┌───────────────────────┐ \n\- \ │ [1, 2, 3] # [4, 5, 6] │ \n\- \ └───────────────────────┘ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided this argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which is not a ❰List❱ but instead has type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1--prettyTypeMessage (CantAdd expr0 expr1) =- buildNaturalOperator "+" expr0 expr1--prettyTypeMessage (CantMultiply expr0 expr1) =- buildNaturalOperator "*" expr0 expr1--prettyTypeMessage (NoDependentTypes expr0 expr1) = ErrorMessages {..}- where- short = "No dependent types"-- long =- "Explanation: The Dhall programming language does not allow functions from terms \n\- \to types. These function types are also known as “dependent function types” \n\- \because you have a type whose value “depends” on the value of a term. \n\- \ \n\- \For example, this is " <> _NOT <> " a legal function type: \n\- \ \n\- \ \n\- \ ┌─────────────┐ \n\- \ │ Bool → Type │ \n\- \ └─────────────┘ \n\- \ \n\- \ \n\- \Similarly, this is " <> _NOT <> " legal code: \n\- \ \n\- \ \n\- \ ┌───────────────────────────────────────────────────┐ \n\- \ │ λ(Vector : Natural → Type → Type) → Vector 0 Text │ \n\- \ └───────────────────────────────────────────────────┘ \n\- \ ⇧ \n\- \ Invalid dependent type \n\- \ \n\- \ \n\- \Your function type is invalid because the input has type: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... and the output has kind: \n\- \ \n\- \" <> txt1 <> "\n\- \ \n\- \... which makes this a forbidden dependent function type \n"- where- txt0 = insert expr0- txt1 = insert expr1--buildBooleanOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages-buildBooleanOperator operator expr0 expr1 = ErrorMessages {..}- where- short = "❰" <> txt2 <> "❱ only works on ❰Bool❱s"-- long =- "Explanation: The ❰" <> txt2 <> "❱ operator expects two arguments that have type ❰Bool❱\n\- \ \n\- \For example, this is a valid use of ❰" <> txt2 <> "❱: \n\- \ \n\- \ \n\- \ ┌───────────────┐ \n\- \ │ True " <> txt2 <> " False │ \n\- \ └───────────────┘ \n\- \ \n\- \ \n\- \You provided this argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which does not have type ❰Bool❱ but instead has type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1-- txt2 = pretty operator--buildNaturalOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages-buildNaturalOperator operator expr0 expr1 = ErrorMessages {..}- where- short = "❰" <> txt2 <> "❱ only works on ❰Natural❱s"-- long =- "Explanation: The ❰" <> txt2 <> "❱ operator expects two arguments that have type ❰Natural❱\n\- \ \n\- \For example, this is a valid use of ❰" <> txt2 <> "❱: \n\- \ \n\- \ \n\- \ ┌───────┐ \n\- \ │ 3 " <> txt2 <> " 5 │ \n\- \ └───────┘ \n\- \ \n\- \ \n\- \Some common reasons why you might get this error: \n\- \ \n\- \● You might have tried to use an ❰Integer❱, which is " <> _NOT <> " allowed: \n\- \ \n\- \ \n\- \ ┌─────────────────────────────────────────┐ \n\- \ │ λ(x : Integer) → λ(y : Integer) → x " <> txt2 <> " y │ Not valid \n\- \ └─────────────────────────────────────────┘ \n\- \ \n\- \ \n\- \ You can only use ❰Natural❱ numbers \n\- \ \n\- \ \n\- \● You might have mistakenly used an ❰Integer❱ literal, which is " <> _NOT <> " allowed:\n\- \ \n\- \ \n\- \ ┌─────────┐ \n\- \ │ +2 " <> txt2 <> " +2 │ Not valid \n\- \ └─────────┘ \n\- \ \n\- \ \n\- \ You need to remove the leading ❰+❱ to transform them into ❰Natural❱ literals, \n\- \ like this: \n\- \ \n\- \ \n\- \ ┌───────┐ \n\- \ │ 2 " <> txt2 <> " 2 │ Valid \n\- \ └───────┘ \n\- \ \n\- \ \n\- \────────────────────────────────────────────────────────────────────────────────\n\- \ \n\- \You provided this argument: \n\- \ \n\- \" <> txt0 <> "\n\- \ \n\- \... which does not have type ❰Natural❱ but instead has type: \n\- \ \n\- \" <> txt1 <> "\n"- where- txt0 = insert expr0- txt1 = insert expr1-- txt2 = pretty operator---- | A structured type error that includes context-data TypeError s a = TypeError- { context :: Context (Expr s a)- , current :: Expr s a- , typeMessage :: TypeMessage s a- }--instance (Eq a, Pretty s, Pretty a, ToTerm a) => Show (TypeError s a) where- show = Pretty.renderString . Pretty.layoutPretty layoutOpts . Pretty.pretty--instance (Eq a, Pretty s, Pretty a, ToTerm a, Typeable s, Typeable a) => Exception (TypeError s a)--instance (Eq a, Pretty s, Pretty a, ToTerm a) => Pretty (TypeError s a) where- pretty (TypeError ctx expr msg)- = Pretty.unAnnotate- ( "\n"- <> ( if null (Dhall.Context.toList ctx)- then ""- else prettyContext ctx <> "\n\n"- )- <> shortTypeMessage msg <> "\n"- <> source- )- where- prettyKV (key, val) =- pretty key <> " : " <> Dhall.Util.snipDoc (pretty val)-- prettyContext =- Pretty.vsep- . map prettyKV- . reverse- . Dhall.Context.toList-- source = case expr of- Note s _ -> pretty s- _ -> mempty--{-| Newtype used to wrap error messages so that they render with a more- detailed explanation of what went wrong--}-newtype DetailedTypeError s a = DetailedTypeError (TypeError s a)- deriving (Typeable)--instance (Eq a, Pretty s, Pretty a, ToTerm a) => Show (DetailedTypeError s a) where- show = Pretty.renderString . Pretty.layoutPretty layoutOpts . Pretty.pretty--instance (Eq a, Pretty s, Pretty a, ToTerm a, Typeable s, Typeable a) => Exception (DetailedTypeError s a)--instance (Eq a, Pretty s, Pretty a, ToTerm a) => Pretty (DetailedTypeError s a) where- pretty (DetailedTypeError (TypeError ctx expr msg))- = Pretty.unAnnotate- ( "\n"- <> ( if null (Dhall.Context.toList ctx)- then ""- else prettyContext ctx <> "\n\n"- )- <> longTypeMessage msg <> "\n"- <> "────────────────────────────────────────────────────────────────────────────────\n"- <> "\n"- <> source- )- where- prettyKV (key, val) =- pretty key <> " : " <> Dhall.Util.snipDoc (pretty val)-- prettyContext =- Pretty.vsep- . map prettyKV- . reverse- . Dhall.Context.toList-- source = case expr of- Note s _ -> pretty s- _ -> mempty--{-| This function verifies that a custom context is well-formed so that- type-checking will not loop-- Note that `typeWith` already calls `checkContext` for you on the `Context`- that you supply--}-checkContext :: Context (Expr s X) -> Either (TypeError s X) ()-checkContext context =- case Dhall.Context.match context of- Nothing -> do- return ()- Just (x, v, context') -> do- let shiftedV = Dhall.Core.shift (-1) (V x 0) v- let shiftedContext = fmap (Dhall.Core.shift (-1) (V x 0)) context'- _ <- typeWith shiftedContext shiftedV- return ()+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns #-}++{-# OPTIONS_GHC -Wall #-}++-- | This module contains the logic for type checking Dhall code++module Dhall.TypeCheck (+ -- * Type-checking+ typeWith+ , typeOf+ , typeWithA+ , checkContext+ , messageExpressions++ -- * Types+ , Typer+ , X+ , absurd+ , TypeError(..)+ , DetailedTypeError(..)+ , Censored(..)+ , TypeMessage(..)+ , prettyTypeMessage+ , ErrorMessages(..)+ ) where++import Control.Exception (Exception)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Writer.Strict (execWriterT, tell)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Monoid (Endo (..))+import Data.Semigroup (Max (..))+import Data.Sequence (ViewL (..))+import Data.Set (Set)+import Data.Text (Text)+import Data.Typeable (Typeable)+import Data.Void (Void, absurd)+import Dhall.Context (Context)+import Dhall.Eval+ ( Environment (..)+ , Names (..)+ , Val (..)+ , (~>)+ )+import Dhall.Pretty (Ann, UnescapedLabel (..))+import Dhall.Src (Src)+import Lens.Micro (anyOf, over)+import Prettyprinter (Doc, Pretty (..), vsep)++import Dhall.Syntax+ ( Binding (..)+ , Chunks (..)+ , Const (..)+ , Expr (..)+ , FunctionBinding (..)+ , PreferAnnotation (..)+ , RecordField (..)+ , Var (..)+ , WithComponent (..)+ )++import qualified Data.Foldable as Foldable+import qualified Data.Foldable.WithIndex as Foldable.WithIndex+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Map+import qualified Data.Sequence+import qualified Data.Set+import qualified Data.Text as Text+import qualified Data.Traversable+import qualified Dhall.Context+import qualified Dhall.Core+import qualified Dhall.Diff+import qualified Dhall.Eval as Eval+import qualified Dhall.Map+import qualified Dhall.Pretty+import qualified Dhall.Pretty.Internal+import qualified Dhall.Syntax as Syntax+import qualified Dhall.Util+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.String as Pretty++{-| A type synonym for `Void`++ This is provided for backwards compatibility, since Dhall used to use its+ own `X` type instead of @"Data.Void".`Void`@. You should use `Void` instead+ of `X` now+-}+type X = Void+{-# DEPRECATED X "Use Data.Void.Void instead" #-}++axiom :: Const -> Either (TypeError s a) Const+axiom Type = return Kind+axiom Kind = return Sort+axiom Sort = Left (TypeError Dhall.Context.empty (Const Sort) Untyped)++rule :: Const -> Const -> Const+rule Type Type = Type+rule Kind Type = Type+rule Sort Type = Type+rule Type Kind = Kind+rule Kind Kind = Kind+rule Sort Kind = Sort+rule Type Sort = Sort+rule Kind Sort = Sort+rule Sort Sort = Sort++{-| Type-check an expression and return the expression's type if type-checking+ succeeds or an error if type-checking fails++ `typeWith` does not necessarily normalize the type since full normalization+ is not necessary for just type-checking. If you actually care about the+ returned type then you may want to `Dhall.Core.normalize` it afterwards.++ The supplied `Context` records the types of the names in scope. If+ these are ill-typed, the return value may be ill-typed.+-}+typeWith :: Context (Expr s X) -> Expr s X -> Either (TypeError s X) (Expr s X)+typeWith ctx expr = do+ checkContext ctx+ typeWithA absurd ctx expr++{-| Function that converts the value inside an `Embed` constructor into a new+ expression+-}+type Typer a = forall s. a -> Expr s a++{-| Generalization of `typeWith` that allows type-checking the `Embed`+ constructor with custom logic+-}+typeWithA+ :: (Eq a, Pretty a)+ => Typer a+ -> Context (Expr s a)+ -> Expr s a+ -> Either (TypeError s a) (Expr s a)+typeWithA tpa context expression =+ fmap (Dhall.Core.renote . Eval.quote EmptyNames) (infer tpa ctx expression)+ where+ ctx = contextToCtx context++contextToCtx :: Eq a => Context (Expr s a) -> Ctx a+contextToCtx context = loop (Dhall.Context.toList context)+ where+ loop [] =+ Ctx Empty TypesEmpty++ loop ((x, t):rest) =+ Ctx (Skip vs x) (TypesBind ts x (Eval.eval vs (Dhall.Core.denote t)))+ where+ Ctx vs ts = loop rest++ctxToContext :: Eq a => Ctx a -> Context (Expr s a)+ctxToContext (Ctx {..}) = loop types+ where+ loop (TypesBind ts x t) = Dhall.Context.insert x t' (loop ts)+ where+ ns = typesToNames ts++ t' = Dhall.Core.renote (Eval.quote ns t)+ loop TypesEmpty = Dhall.Context.empty++typesToNames :: Types a -> Names+typesToNames (TypesBind ts x _) = Bind ns x+ where+ ns = typesToNames ts+typesToNames TypesEmpty = EmptyNames++data Types a = TypesEmpty | TypesBind !(Types a) {-# UNPACK #-} !Text (Val a)++data Ctx a = Ctx { values :: !(Environment a), types :: !(Types a) }++addType :: Text -> Val a -> Ctx a -> Ctx a+addType x t (Ctx vs ts) = Ctx (Skip vs x) (TypesBind ts x t)++addTypeValue :: Text -> Val a -> Val a -> Ctx a -> Ctx a+addTypeValue x t v (Ctx vs ts) = Ctx (Extend vs x v) (TypesBind ts x t)++fresh :: Ctx a -> Text -> Val a+fresh Ctx{..} x = VVar x (Eval.countNames x (Eval.envNames values))++{-| `typeWithA` is implemented internally in terms of @infer@ in order to speed+ up equivalence checking.++ Specifically, we extend the `Context` to become a @Ctx@, which can store+ the entire contents of a `let` expression (i.e. the type *and* the value+ of the bound variable). By storing this extra information in the @Ctx@ we+ no longer need to substitute `let` expressions at all (which is very+ expensive!).++ However, this means that we need to use `Dhall.Eval.conv` to perform+ equivalence checking instead of `Dhall.Core.judgmentallyEqual` since+ only `Dhall.Core.judgmentallyEqual` is unable to use the information stored+ in the extended context for accurate equivalence checking.+-}+infer+ :: forall a s+ . (Eq a, Pretty a)+ => Typer a+ -> Ctx a+ -> Expr s a+ -> Either (TypeError s a) (Val a)+infer typer = loop+ where+ {- The convention for primes (i.e. `'`s) is:++ * No primes (`x` ): An `Expr` that has not been `eval`ed yet+ * One prime (`x'` ): A `Val`+ * Two primes (`x''`): An `Expr` generated from `quote`ing a `Val`+ -}+ loop :: Ctx a -> Expr s a -> Either (TypeError s a) (Val a)+ loop ctx@Ctx{..} expression = case expression of+ Const c ->+ fmap VConst (axiom c)++ Var (V x0 n0) -> do+ let go TypesEmpty _ =+ die (UnboundVariable x0)+ go (TypesBind ts x t) n+ | x == x0 = if n == 0 then return t else go ts (n - 1)+ | otherwise = go ts n++ go types n0++ Lam _ (FunctionBinding { functionBindingVariable = x, functionBindingAnnotation = _A}) b -> do+ tA' <- loop ctx _A++ case tA' of+ VConst _ -> return ()+ _ -> die (InvalidInputType _A)++ let _A' = eval values _A++ let ctx' = addType x _A' ctx++ _B' <- loop ctx' b++ let _B'' = quote (Bind (Eval.envNames values) x) _B'++ tB' <- loop ctx' (Dhall.Core.renote _B'')++ case tB' of+ VConst _ -> return ()+ _ -> die (InvalidOutputType _B'')++ return (VHPi x _A' (\u -> Eval.eval (Extend values x u) _B''))++ Pi _ x _A _B -> do+ tA' <- loop ctx _A++ kA <- case tA' of+ VConst kA -> return kA+ _ -> die (InvalidInputType _A)++ let _A' = eval values _A++ let ctx' = addType x _A' ctx++ tB' <- loop ctx' _B++ kB <- case tB' of+ VConst kB -> return kB+ _ -> die (InvalidOutputType _B)++ return (VConst (rule kA kB))++ App f a -> do+ tf' <- loop ctx f++ case Eval.toVHPi tf' of+ Just (_x, _A₀', _B') -> do+ _A₁' <- loop ctx a++ if Eval.conv values _A₀' _A₁'+ then do+ let a' = eval values a++ return (_B' a')++ else do+ let _A₀'' = quote names _A₀'+ let _A₁'' = quote names _A₁'+ die (TypeMismatch f _A₀'' a _A₁'')+ Nothing ->+ die (NotAFunction f (quote names tf'))++ Let (Binding { value = a₀, variable = x, ..}) body -> do+ let a₀' = eval values a₀++ ctxNew <- case annotation of+ Nothing -> do+ _A' <- loop ctx a₀++ return (addTypeValue x _A' a₀' ctx)+ Just (_, _A₀) -> do+ _ <- loop ctx _A₀++ let _A₀' = eval values _A₀++ _A₁' <- loop ctx a₀++ if Eval.conv values _A₀' _A₁'+ then+ return ()++ else do+ let _A₀'' = quote names _A₀'+ let _A₁'' = quote names _A₁'+ Left (TypeError context a₀ (AnnotMismatch a₀ _A₀'' _A₁''))++ return (addTypeValue x _A₀' a₀' ctx)++ loop ctxNew body++ Annot t _T₀ -> do+ case Dhall.Core.denote _T₀ of+ Const _ -> return ()+ _ -> do+ _ <- loop ctx _T₀++ return ()++ let _T₀' = eval values _T₀++ _T₁' <- loop ctx t++ if Eval.conv values _T₀' _T₁'+ then+ return _T₁'++ else do+ let _T₀'' = quote names _T₀'+ let _T₁'' = quote names _T₁'+ die (AnnotMismatch t _T₀'' _T₁'')++ Bool ->+ return (VConst Type)++ BoolLit _ ->+ return VBool++ BoolAnd l r -> do+ tl' <- loop ctx l++ case tl' of+ VBool -> return ()+ _ -> die (CantAnd l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VBool -> return ()+ _ -> die (CantAnd r (quote names tr'))++ return VBool++ BoolOr l r -> do+ tl' <- loop ctx l++ case tl' of+ VBool -> return ()+ _ -> die (CantOr l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VBool -> return ()+ _ -> die (CantOr r (quote names tr'))++ return VBool++ BoolEQ l r -> do+ tl' <- loop ctx l++ case tl' of+ VBool -> return ()+ _ -> die (CantEQ l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VBool -> return ()+ _ -> die (CantEQ r (quote names tr'))++ return VBool++ BoolNE l r -> do+ tl' <- loop ctx l++ case tl' of+ VBool -> return ()+ _ -> die (CantNE l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VBool -> return ()+ _ -> die (CantNE r (quote names tr'))++ return VBool++ BoolIf t l r -> do+ tt' <- loop ctx t++ case tt' of+ VBool -> return ()+ _ -> die (InvalidPredicate t (quote names tt'))++ _L' <- loop ctx l++ _R' <- loop ctx r++ _ <- loop ctx (quote names _L')++ let _L'' = quote names _L'++ _ <- loop ctx (quote names _R')++ let _R'' = quote names _R'++ if Eval.conv values _L' _R'+ then return ()+ else die (IfBranchMismatch l r _L'' _R'')++ return _L'++ Bytes ->+ return (VConst Type)++ BytesLit _ ->+ return VBytes++ Natural ->+ return (VConst Type)++ NaturalLit _ ->+ return VNatural++ NaturalFold ->+ return+ ( VNatural+ ~> VHPi "natural" (VConst Type) (\natural ->+ VHPi "succ" (natural ~> natural) (\_succ ->+ VHPi "zero" natural (\_zero ->+ natural+ )+ )+ )+ )++ NaturalBuild ->+ return+ ( VHPi "natural" (VConst Type) (\natural ->+ VHPi "succ" (natural ~> natural) (\_succ ->+ VHPi "zero" natural (\_zero ->+ natural+ )+ )+ )+ ~> VNatural+ )++ NaturalIsZero ->+ return (VNatural ~> VBool)++ NaturalEven ->+ return (VNatural ~> VBool)++ NaturalOdd ->+ return (VNatural ~> VBool)++ NaturalToInteger ->+ return (VNatural ~> VInteger)++ NaturalShow ->+ return (VNatural ~> VText)++ NaturalSubtract ->+ return (VNatural ~> VNatural ~> VNatural)++ NaturalPlus l r -> do+ tl' <- loop ctx l++ case tl' of+ VNatural -> return ()+ _ -> die (CantAdd l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VNatural -> return ()+ _ -> die (CantAdd r (quote names tr'))++ return VNatural++ NaturalTimes l r -> do+ tl' <- loop ctx l++ case tl' of+ VNatural -> return ()+ _ -> die (CantMultiply l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VNatural -> return ()+ _ -> die (CantMultiply r (quote names tr'))++ return VNatural++ Integer ->+ return (VConst Type)++ IntegerLit _ ->+ return VInteger++ IntegerClamp ->+ return (VInteger ~> VNatural)++ IntegerNegate ->+ return (VInteger ~> VInteger)++ IntegerShow ->+ return (VInteger ~> VText)++ IntegerToDouble ->+ return (VInteger ~> VDouble)++ Double ->+ return (VConst Type)++ DoubleLit _ ->+ return VDouble++ DoubleShow ->+ return (VDouble ~> VText)++ Text ->+ return (VConst Type)++ TextLit (Chunks xys _) -> do+ let process (_, y) = do+ _Y' <- loop ctx y++ case _Y' of+ VText -> return ()+ _ -> die (CantInterpolate y (quote names _Y'))++ mapM_ process xys++ return VText++ TextAppend l r -> do+ tl' <- loop ctx l++ case tl' of+ VText -> return ()+ _ -> die (CantTextAppend l (quote names tl'))++ tr' <- loop ctx r++ case tr' of+ VText -> return ()+ _ -> die (CantTextAppend r (quote names tr'))++ return VText++ TextReplace ->+ return+ ( VHPi "needle" VText (\_needle ->+ VHPi "replacement" VText (\_replacement ->+ VHPi "haystack" VText (\_haystack ->+ VText+ )+ )+ )+ )+ TextShow ->+ return (VText ~> VText)++ Date ->+ return (VConst Type)++ DateLiteral _ ->+ return VDate++ DateShow ->+ return (VDate ~> VText)++ Time ->+ return (VConst Type)++ TimeLiteral _ _ ->+ return VTime++ TimeShow ->+ return (VTime ~> VText)++ TimeZone ->+ return (VConst Type)++ TimeZoneLiteral _ ->+ return VTimeZone++ TimeZoneShow ->+ return (VTimeZone ~> VText)++ List ->+ return (VConst Type ~> VConst Type)++ ListLit Nothing ts₀ ->+ case Data.Sequence.viewl ts₀ of+ t₀ :< ts₁ -> do+ _T₀' <- loop ctx t₀++ let _T₀'' = quote names _T₀'++ tT₀' <- loop ctx _T₀''++ case tT₀' of+ VConst Type -> return ()+ _ -> die (InvalidListType (App List _T₀''))++ let process i t₁ = do+ _T₁' <- loop ctx t₁++ if Eval.conv values _T₀' _T₁'+ then+ return ()++ else do+ let _T₀'' = quote names _T₀'+ let _T₁'' = quote names _T₁'++ -- Carefully note that we don't use `die`+ -- here so that the source span is narrowed+ -- to just the offending element+ let err = MismatchedListElements (i+1) _T₀'' t₁ _T₁''++ Left (TypeError context t₁ err)++ Foldable.WithIndex.itraverse_ process ts₁++ return (VList _T₀')++ _ ->+ die MissingListType++ ListLit (Just _T₀) ts ->+ if Data.Sequence.null ts+ then do+ _ <- loop ctx _T₀++ let _T₀' = eval values _T₀++ let _T₀'' = quote names _T₀'++ case _T₀' of+ VList _ -> return _T₀'+ _ -> die (InvalidListType _T₀'')++ -- See https://github.com/dhall-lang/dhall-haskell/issues/1359.+ else die ListLitInvariant++ ListAppend x y -> do+ tx' <- loop ctx x++ _A₀' <- case tx' of+ VList _A₀' -> return _A₀'+ _ -> die (CantListAppend x (quote names tx'))++ ty' <- loop ctx y++ _A₁' <- case ty' of+ VList _A₁' -> return _A₁'+ _ -> die (CantListAppend y (quote names ty'))++ if Eval.conv values _A₀' _A₁'+ then return ()+ else do+ let _A₀'' = quote names _A₀'+ let _A₁'' = quote names _A₁'+ die (ListAppendMismatch _A₀'' _A₁'')++ return (VList _A₀')++ ListBuild ->+ return+ ( VHPi "a" (VConst Type) (\a ->+ VHPi "list" (VConst Type) (\list ->+ VHPi "cons" (a ~> list ~> list) (\_cons ->+ (VHPi "nil" list (\_nil -> list))+ )+ )+ ~> VList a+ )+ )++ ListFold ->+ return+ ( VHPi "a" (VConst Type) (\a ->+ VList a+ ~> VHPi "list" (VConst Type) (\list ->+ VHPi "cons" (a ~> list ~> list) (\_cons ->+ (VHPi "nil" list (\_nil -> list))+ )+ )+ )+ )++ ListLength ->+ return (VHPi "a" (VConst Type) (\a -> VList a ~> VNatural))++ ListHead ->+ return (VHPi "a" (VConst Type) (\a -> VList a ~> VOptional a))++ ListLast ->+ return (VHPi "a" (VConst Type) (\a -> VList a ~> VOptional a))++ ListIndexed ->+ return+ ( VHPi "a" (VConst Type) (\a ->+ VList a+ ~> VList+ (VRecord+ (Dhall.Map.unorderedFromList+ [ ("index", VNatural)+ , ("value", a )+ ]+ )+ )+ )+ )+ ListReverse ->+ return (VHPi "a" (VConst Type) (\a -> VList a ~> VList a))++ Optional ->+ return (VConst Type ~> VConst Type)++ None ->+ return (VHPi "A" (VConst Type) (\_A -> VOptional _A))++ Some a -> do+ _A' <- loop ctx a++ tA' <- loop ctx (quote names _A')++ case tA' of+ VConst Type -> return ()+ _ -> do+ let _A'' = quote names _A'+ let tA'' = quote names tA'++ die (InvalidSome a _A'' tA'')++ return (VOptional _A')++ Record xTs -> do+ let process x (RecordField {recordFieldValue = _T}) = do+ tT' <- lift (loop ctx _T)++ case tT' of+ VConst c -> tell (Max c)+ _ -> lift (die (InvalidFieldType x _T))++ Max c <- execWriterT (Dhall.Map.unorderedTraverseWithKey_ process xTs)++ return (VConst c)++ RecordLit xts -> do+ let process t = do+ _T' <- loop ctx $ recordFieldValue t++ let _T'' = quote names _T'++ _ <- loop ctx _T''++ return _T'++ xTs <- traverse process (Dhall.Map.sort xts)++ return (VRecord xTs)++ Union xTs -> do+ let process _ Nothing =+ return mempty++ process x₁ (Just _T₁) = do+ tT₁' <- loop ctx _T₁++ case tT₁' of+ VConst c -> return (Max c)+ _ -> die (InvalidAlternativeType x₁ _T₁)++ Max c <- fmap Foldable.fold (Dhall.Map.unorderedTraverseWithKey process xTs)+ return (VConst c)+ Combine _ mk l r -> do+ _L' <- loop ctx l++ let l'' = quote names (eval values l)++ _R' <- loop ctx r++ let r'' = quote names (eval values r)++ xLs' <- case _L' of+ VRecord xLs' ->+ return xLs'++ _ -> do+ let _L'' = quote names _L'++ case mk of+ Nothing -> die (MustCombineARecord '∧' l'' _L'')+ Just t -> die (InvalidDuplicateField t l _L'')++ xRs' <- case _R' of+ VRecord xRs' ->+ return xRs'++ _ -> do+ let _R'' = quote names _R'++ case mk of+ Nothing -> die (MustCombineARecord '∧' r'' _R'')+ Just t -> die (InvalidDuplicateField t r _R'')++ let combineTypes xs xLs₀' xRs₀' = do+ let combine x (VRecord xLs₁') (VRecord xRs₁') =+ combineTypes (x : xs) xLs₁' xRs₁'++ combine x _ _ =+ case mk of+ Nothing -> die (FieldCollision (NonEmpty.reverse (x :| xs)))+ Just t -> die (DuplicateFieldCannotBeMerged (t :| reverse (x : xs)))++ let xEs =+ Dhall.Map.outerJoin Right Right combine xLs₀' xRs₀'++ xTs <- Dhall.Map.unorderedTraverseWithKey (\_x _E -> _E) xEs++ return (VRecord xTs)++ combineTypes [] xLs' xRs'++ CombineTypes _ l r -> do+ _L' <- loop ctx l++ let l' = eval values l++ let l'' = quote names l'++ cL <- case _L' of+ VConst cL -> return cL+ _ -> die (CombineTypesRequiresRecordType l l'')++ _R' <- loop ctx r++ let r' = eval values r++ let r'' = quote names r'++ cR <- case _R' of+ VConst cR -> return cR+ _ -> die (CombineTypesRequiresRecordType r r'')++ let c = max cL cR++ xLs' <- case l' of+ VRecord xLs' -> return xLs'+ _ -> die (CombineTypesRequiresRecordType l l'')++ xRs' <- case r' of+ VRecord xRs' -> return xRs'+ _ -> die (CombineTypesRequiresRecordType r r'')++ let combineTypes xs xLs₀' xRs₀' = do+ let combine x (VRecord xLs₁') (VRecord xRs₁') =+ combineTypes (x : xs) xLs₁' xRs₁'++ combine x _ _ =+ die (FieldTypeCollision (NonEmpty.reverse (x :| xs)))++ let mL = Dhall.Map.toMap xLs₀'+ let mR = Dhall.Map.toMap xRs₀'++ Foldable.sequence_ (Data.Map.intersectionWithKey combine mL mR)++ combineTypes [] xLs' xRs'++ return (VConst c)++ Prefer _ _ l r -> do+ _L' <- loop ctx l++ _R' <- loop ctx r++ xLs' <- case _L' of+ VRecord xLs' -> return xLs'++ _ -> do+ let _L'' = quote names _L'++ let l'' = quote names (eval values l)++ die (MustCombineARecord '⫽' l'' _L'')++ xRs' <- case _R' of+ VRecord xRs' -> return xRs'++ _ -> do+ let _R'' = quote names _R'++ let r'' = quote names (eval values r)++ die (MustCombineARecord '⫽' r'' _R'')++ return (VRecord (Dhall.Map.union xRs' xLs'))++ RecordCompletion l r -> do+ _L' <- loop ctx l++ case _L' of+ VRecord xLs'+ | not (Dhall.Map.member "default" xLs')+ -> die (InvalidRecordCompletion "default" l)+ | not (Dhall.Map.member "Type" xLs')+ -> die (InvalidRecordCompletion "Type" l)+ | otherwise+ -> loop ctx (Annot (Prefer mempty PreferFromCompletion (Field l def) r) (Field l typ))+ _ -> die (CompletionSchemaMustBeARecord l (quote names _L'))++ where+ def = Syntax.makeFieldSelection "default"+ typ = Syntax.makeFieldSelection "Type"+ Merge t u mT₁ -> do+ _T' <- loop ctx t++ yTs' <- case _T' of+ VRecord yTs' ->+ return yTs'++ _ -> do+ let _T'' = quote names _T'++ die (MustMergeARecord t _T'')++ _U' <- loop ctx u++ yUs' <- case _U' of+ VUnion yUs' ->+ return yUs'++ VOptional _O' ->+ -- This is a bit of hack, but it allows us to reuse the+ -- rather complex type-matching logic for Optionals.+ return (Dhall.Map.unorderedFromList [("None", Nothing), ("Some", Just _O')])++ _ -> do+ let _U'' = quote names _U'++ die (MustMergeUnionOrOptional u _U'')++ let ysT = Dhall.Map.keysSet yTs'+ let ysU = Dhall.Map.keysSet yUs'++ let diffT = Data.Set.difference ysT ysU+ let diffU = Data.Set.difference ysU ysT++ if Data.Set.null diffT+ then return ()+ else die (UnusedHandler diffT)++ if Data.Set.null diffU+ then return ()+ else let (exemplar,rest) = Data.Set.deleteFindMin diffU+ in die (MissingHandler exemplar rest)++ let match _y _T₀' Nothing =+ return _T₀'++ match y handler' (Just _A₁') =+ case Eval.toVHPi handler' of+ Just (x, _A₀', _T₀') ->+ if Eval.conv values _A₀' _A₁'+ then do+ let _T₁' = _T₀' (fresh ctx x)++ let _T₁'' = quote names _T₁'++ -- x appearing in _T₁'' would indicate a disallowed+ -- handler type (see+ -- https://github.com/dhall-lang/dhall-lang/issues/749).+ --+ -- If x appears in _T₁'', quote will have given it index+ -- -1. Any well-typed variable has a non-negative index,+ -- so we can simply look for negative indices to detect x.+ let containsBadVar (Var (V _ n)) =+ n < 0++ containsBadVar e =+ anyOf+ Dhall.Core.subExpressions+ containsBadVar+ e++ if containsBadVar _T₁''+ then do+ let handler'' = quote names handler'++ let outputType = Dhall.Core.shift 1 (V x (-1)) _T₁''++ die (DisallowedHandlerType y handler'' outputType x)++ else return _T₁'++ else do+ let _A₀'' = quote names _A₀'+ let _A₁'' = quote names _A₁'++ die (HandlerInputTypeMismatch y _A₁'' _A₀'')++ Nothing -> do+ let handler'' = quote names handler'++ die (HandlerNotAFunction y handler'')++ matched <-+ sequence+ (Data.Map.intersectionWithKey match (Dhall.Map.toMap yTs') (Dhall.Map.toMap yUs'))++ let checkMatched :: Data.Map.Map Text (Val a) -> Either (TypeError s a) (Maybe (Val a))+ checkMatched = fmap (fmap snd) . Foldable.foldlM go Nothing . Data.Map.toList+ where+ go Nothing (y₁, _T₁') =+ return (Just (y₁, _T₁'))++ go yT₀'@(Just (y₀, _T₀')) (y₁, _T₁') =+ if Eval.conv values _T₀' _T₁'+ then return yT₀'++ else do+ let _T₀'' = quote names _T₀'+ let _T₁'' = quote names _T₁'+ die (HandlerOutputTypeMismatch y₀ _T₀'' y₁ _T₁'')++ mT₀' <- checkMatched matched++ mT₁' <- Data.Traversable.for mT₁ $ \_T₁ -> do+ _ <- loop ctx _T₁++ return (eval values _T₁)++ case (mT₀', mT₁') of+ (Nothing, Nothing) ->+ die MissingMergeType+ (Nothing, Just _T₁') ->+ return _T₁'+ (Just _T₀', Nothing) ->+ return _T₀'+ (Just _T₀', Just _T₁') ->+ if Eval.conv values _T₀' _T₁'+ then return _T₀'++ else do+ let _T₀'' = quote names _T₀'+ let _T₁'' = quote names _T₁'+ die (AnnotMismatch (Merge t u Nothing) _T₁'' _T₀'')++ ToMap e mT₁ -> do+ _E' <- loop ctx e++ let _E'' = quote names _E'++ xTs' <- case _E' of+ VRecord xTs' -> return xTs'+ _ -> die (MustMapARecord e _E'')++ tE' <- loop ctx _E''++ let tE'' = quote names tE'++ case tE' of+ VConst Type -> return ()+ _ -> die (InvalidToMapRecordKind _E'' tE'')++ Foldable.traverse_ (loop ctx) mT₁++ let compareFieldTypes _T₀' Nothing =+ Just (Right _T₀')++ compareFieldTypes _T₀' r@(Just (Right _T₁'))+ | Eval.conv values _T₀' _T₁' = r+ | otherwise = do+ let _T₀'' = quote names _T₀'+ let _T₁'' = quote names _T₁'++ Just (die (HeterogenousRecordToMap _E'' _T₀'' _T₁''))++ compareFieldTypes _T₀' r@(Just (Left _)) =+ r++ let r = appEndo (foldMap (Endo . compareFieldTypes) xTs') Nothing++ let mT₁' = fmap (eval values) mT₁++ let mapType _T' =+ VList+ (VRecord+ (Dhall.Map.unorderedFromList+ [("mapKey", VText), ("mapValue", _T')]+ )+ )++ case (r, mT₁') of+ (Nothing, Nothing) ->+ die MissingToMapType+ (Just err@(Left _), _) ->+ err+ (Just (Right _T'), Nothing) ->+ pure (mapType _T')+ (Nothing, Just _T₁'@(VList (VRecord itemTypes)))+ | Just _T' <- Dhall.Map.lookup "mapValue" itemTypes+ , Eval.conv values (mapType _T') _T₁' ->+ pure _T₁'+ (Nothing, Just _T₁') -> do+ let _T₁'' = quote names _T₁'++ die (InvalidToMapType _T₁'')+ (Just (Right _T'), Just _T₁')+ | Eval.conv values (mapType _T') _T₁' ->+ pure (mapType _T')+ | otherwise -> do+ let _T₁'' = quote names _T₁'++ die (MapTypeMismatch (quote names (mapType _T')) _T₁'')++ ShowConstructor e -> do+ _E' <- loop ctx e+ case _E' of+ VUnion _ -> pure VText+ VOptional _ -> pure VText++ _ -> die ShowConstructorNotOnUnion++ Field e (Syntax.fieldSelectionLabel -> x) -> do+ _E' <- loop ctx e++ let _E'' = quote names _E'++ case _E' of+ VRecord xTs' ->+ case Dhall.Map.lookup x xTs' of+ Just _T' -> return _T'+ Nothing -> die (MissingField x _E'')+ _ -> do+ let e' = eval values e++ let e'' = quote names e'++ case e' of+ VUnion xTs' ->+ case Dhall.Map.lookup x xTs' of+ Just (Just _T') -> return (VHPi x _T' (\_ -> e'))+ Just Nothing -> return e'+ Nothing -> die (MissingConstructor x e)++ _ -> do+ let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabel x)++ die (CantAccess text e'' _E'')+ Project e (Left xs) -> do+ case duplicateElement xs of+ Just x -> do+ die (DuplicateProjectionLabel x)+ Nothing -> do+ return ()++ _E' <- loop ctx e++ let _E'' = quote names _E'++ case _E' of+ VRecord xTs' -> do+ let process x =+ case Dhall.Map.lookup x xTs' of+ Just _T' -> return (x, _T')+ Nothing -> die (MissingField x _E'')++ let adapt = VRecord . Dhall.Map.unorderedFromList++ fmap adapt (traverse process xs)++ _ -> do+ let text =+ Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs)++ die (CantProject text e _E'')++ Project e (Right s) -> do+ _E' <- loop ctx e++ let _E'' = quote names _E'++ case _E' of+ VRecord xEs' -> do+ _ <- loop ctx s++ let s' = eval values s++ case s' of+ VRecord xSs' -> do+ let actualSubset =+ quote names (VRecord (Dhall.Map.intersection xEs' xSs'))++ let expectedSubset = s++ let process x _S' = do+ let _S'' = quote names _S'++ case Dhall.Map.lookup x xEs' of+ Nothing ->+ die (MissingField x _E'')++ Just _E' ->+ if Eval.conv values _E' _S'+ then return ()+ else die (ProjectionTypeMismatch x _E'' _S'' expectedSubset actualSubset)++ Dhall.Map.unorderedTraverseWithKey_ process xSs'++ return s'++ _ ->+ die (CantProjectByExpression s)++ _ -> do+ let text = Dhall.Core.pretty s++ die (CantProject text e s)++ Assert _T -> do+ _ <- loop ctx _T++ let _T' = eval values _T++ case _T' of+ VEquivalent x' y' -> do+ let x'' = quote names x'+ let y'' = quote names y'++ if Eval.conv values x' y'+ then return _T'+ else die (AssertionFailed x'' y'')++ _ ->+ die (NotAnEquivalence _T)++ Equivalent _ x y -> do+ _A₀' <- loop ctx x++ let _A₀'' = quote names _A₀'++ tA₀' <- loop ctx _A₀''++ case tA₀' of+ VConst Type -> return ()+ _ -> die (IncomparableExpression x)++ _A₁' <- loop ctx y++ let _A₁'' = quote names _A₁'++ tA₁' <- loop ctx _A₁''++ case tA₁' of+ VConst Type -> return ()+ _ -> die (IncomparableExpression y)++ if Eval.conv values _A₀' _A₁'+ then return ()+ else die (EquivalenceTypeMismatch x _A₀'' y _A₁'')++ return (VConst Type)++ With e₀ ks₀ v₀ -> do+ tE₀' <- loop ctx e₀++ -- The purpose of this inner loop is to ensure that we only need to+ -- typecheck the record once++ let with tE' ks v = case tE' of+ VRecord kTs' ->+ case ks of+ WithLabel k :| [] -> do+ tV' <- loop ctx v++ return (VRecord (Dhall.Map.insert k tV' kTs'))+ WithLabel k₀ :| k₁ : ks' -> do+ let _T =+ case Dhall.Map.lookup k₀ kTs' of+ Just _T' -> _T'+ Nothing -> VRecord mempty++ tV' <- with _T (k₁ :| ks') v++ return (VRecord (Dhall.Map.insert k₀ tV' kTs'))+ WithQuestion :| _ -> do+ die NotALabelPath++ VOptional _O' -> do+ case ks of++ -- (Some x) with ? = v is valid iff the type of x is the same as the type of v.+ WithQuestion :| [] -> do+ tV' <- loop ctx v+ if Eval.conv values _O' tV'+ then return (VOptional _O')+ else die OptionalWithTypeMismatch++ -- (Some x) with ?.a.b = v is valid iff the type of x.a.b is the same as the type of v.+ WithQuestion :| k₁ : ks' -> do+ tV' <- with _O' (k₁ :| ks') v+ if Eval.conv values _O' tV'+ then return (VOptional _O')+ else die OptionalWithTypeMismatch++ WithLabel k :| _ -> die (NotAQuestionPath k)++ _ -> die (NotWithARecord e₀ (quote names tE')) -- TODO: NotWithARecordOrOptional++ with tE₀' ks₀ v₀++ Note s e ->+ case loop ctx e of+ Left (TypeError ctx' (Note s' e') m) ->+ Left (TypeError ctx' (Note s' e') m)+ Left (TypeError ctx' e' m) ->+ Left (TypeError ctx' (Note s e') m)+ Right r ->+ Right r++ ImportAlt l _r ->+ loop ctx l++ Embed p ->+ return (eval values (typer p))+ where+ die err = Left (TypeError context expression err)++ context = ctxToContext ctx++ names = typesToNames types++ eval vs e = Eval.eval vs (Dhall.Core.denote e)++ quote ns value = Dhall.Core.renote (Eval.quote ns value)++{-| `typeOf` is the same as `typeWith` with an empty context, meaning that the+ expression must be closed (i.e. no free variables), otherwise type-checking+ will fail.+-}+typeOf :: Expr s X -> Either (TypeError s X) (Expr s X)+typeOf = typeWith Dhall.Context.empty++-- | The specific type error+data TypeMessage s a+ = UnboundVariable Text+ | InvalidInputType (Expr s a)+ | InvalidOutputType (Expr s a)+ | NotAFunction (Expr s a) (Expr s a)+ | TypeMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)+ | AnnotMismatch (Expr s a) (Expr s a) (Expr s a)+ | Untyped+ | MissingListType+ | MismatchedListElements Int (Expr s a) (Expr s a) (Expr s a)+ | InvalidListType (Expr s a)+ | ListLitInvariant+ | InvalidSome (Expr s a) (Expr s a) (Expr s a)+ | InvalidPredicate (Expr s a) (Expr s a)+ | IfBranchMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)+ | InvalidFieldType Text (Expr s a)+ | InvalidAlternativeType Text (Expr s a)+ | ListAppendMismatch (Expr s a) (Expr s a)+ | MustCombineARecord Char (Expr s a) (Expr s a)+ | InvalidDuplicateField Text (Expr s a) (Expr s a)+ | InvalidRecordCompletion Text (Expr s a)+ | CompletionSchemaMustBeARecord (Expr s a) (Expr s a)+ | CombineTypesRequiresRecordType (Expr s a) (Expr s a)+ | DuplicateFieldCannotBeMerged (NonEmpty Text)+ | FieldCollision (NonEmpty Text)+ | FieldTypeCollision (NonEmpty Text)+ | MustMergeARecord (Expr s a) (Expr s a)+ | MustMergeUnionOrOptional (Expr s a) (Expr s a)+ | MustMapARecord (Expr s a) (Expr s a)+ | InvalidToMapRecordKind (Expr s a) (Expr s a)+ | HeterogenousRecordToMap (Expr s a) (Expr s a) (Expr s a)+ | InvalidToMapType (Expr s a)+ | MapTypeMismatch (Expr s a) (Expr s a)+ | MissingToMapType+ | UnusedHandler (Set Text)+ | MissingHandler Text (Set Text)+ | HandlerInputTypeMismatch Text (Expr s a) (Expr s a)+ | DisallowedHandlerType Text (Expr s a) (Expr s a) Text+ | HandlerOutputTypeMismatch Text (Expr s a) Text (Expr s a)+ | MissingMergeType+ | HandlerNotAFunction Text (Expr s a)+ | CantAccess Text (Expr s a) (Expr s a)+ | CantProject Text (Expr s a) (Expr s a)+ | CantProjectByExpression (Expr s a)+ | DuplicateProjectionLabel Text+ | MissingField Text (Expr s a)+ | MissingConstructor Text (Expr s a)+ | ProjectionTypeMismatch Text (Expr s a) (Expr s a) (Expr s a) (Expr s a)+ | AssertionFailed (Expr s a) (Expr s a)+ | NotAnEquivalence (Expr s a)+ | IncomparableExpression (Expr s a)+ | EquivalenceTypeMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)+ | NotWithARecord (Expr s a) (Expr s a)+ | CantAnd (Expr s a) (Expr s a)+ | CantOr (Expr s a) (Expr s a)+ | CantEQ (Expr s a) (Expr s a)+ | CantNE (Expr s a) (Expr s a)+ | CantInterpolate (Expr s a) (Expr s a)+ | CantTextAppend (Expr s a) (Expr s a)+ | CantListAppend (Expr s a) (Expr s a)+ | CantAdd (Expr s a) (Expr s a)+ | CantMultiply (Expr s a) (Expr s a)+ | OptionalWithTypeMismatch+ | NotALabelPath+ | NotAQuestionPath Text+ | ShowConstructorNotOnUnion+ deriving (Show)++formatHints :: [Doc Ann] -> Doc Ann+formatHints hints = vsep (map format hints)+ where+ format hint = "\n\n\ESC[1;33mHint\ESC[0m: " <> hint++shortTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> Doc Ann+shortTypeMessage msg =+ "\ESC[1;31mError\ESC[0m: " <> short <> formatHints hints <> "\n"+ where+ ErrorMessages {..} = prettyTypeMessage msg++longTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> Doc Ann+longTypeMessage msg =+ "\ESC[1;31mError\ESC[0m: " <> short <> formatHints hints <> "\n"+ <> "\n"+ <> long+ where+ ErrorMessages {..} = prettyTypeMessage msg++{-| Output of `prettyTypeMessage`, containing short- and long-form error+ messages+-}+data ErrorMessages = ErrorMessages+ { short :: Doc Ann+ -- ^ Default succinct 1-line explanation of what went wrong+ , hints :: [Doc Ann]+ -- ^ Possibly-empty hints based on specific types involved in the error+ , long :: Doc Ann+ -- ^ Longer and more detailed explanation of the error+ }++_NOT :: Doc ann+_NOT = "\ESC[1mnot\ESC[0m"++insert :: Pretty a => a -> Doc Ann+insert = Dhall.Util.insert++emptyRecordTypeHint :: (Eq a, Pretty a) => Expr s a -> [Doc Ann]+emptyRecordTypeHint expr =+ if Eval.judgmentallyEqual expr (Record mempty) then+ ["{} is the empty record type, use {=} for the empty record value"]+ else []++-- | Convert a `TypeMessage` to short- and long-form `ErrorMessages`+prettyTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> ErrorMessages+prettyTypeMessage (UnboundVariable x) = ErrorMessages {..}+ -- We do not need to print variable name here. For the discussion see:+ -- https://github.com/dhall-lang/dhall-haskell/pull/116+ where+ short = "Unbound variable: " <> Pretty.pretty x++ hints = []++ long =+ "Explanation: Expressions can only reference previously introduced (i.e. “bound”)\n\+ \variables that are still “in scope” \n\+ \ \n\+ \For example, the following valid expressions introduce a “bound” variable named \n\+ \❰x❱: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ λ(x : Bool) → x │ Anonymous functions introduce “bound” variables \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This is the bound variable \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ let x = 1 in x │ ❰let❱ expressions introduce “bound” variables \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This is the bound variable \n\+ \ \n\+ \ \n\+ \However, the following expressions are not valid because they all reference a \n\+ \variable that has not been introduced yet (i.e. an “unbound” variable): \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ λ(x : Bool) → y │ The variable ❰y❱ hasn't been introduced yet \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This is the unbound variable \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────┐ \n\+ \ │ (let x = True in x) && x │ ❰x❱ is undefined outside the parentheses \n\+ \ └──────────────────────────┘ \n\+ \ ⇧ \n\+ \ This is the unbound variable \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ let x = x in x │ The definition for ❰x❱ cannot reference itself \n\+ \ └────────────────┘ \n\+ \ ⇧ \n\+ \ This is the unbound variable \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You misspell a variable name, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────────────┐ \n\+ \ │ λ(empty : Bool) → if emty then \"Empty\" else \"Full\" │ \n\+ \ └────────────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Typo \n\+ \ \n\+ \ \n\+ \● You misspell a reserved identifier, like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────┐ \n\+ \ │ foral (a : Type) → a → a │ \n\+ \ └──────────────────────────┘ \n\+ \ ⇧ \n\+ \ Typo \n\+ \ \n\+ \ \n\+ \● You tried to define a recursive value, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ let x = x + 1 in x │ \n\+ \ └────────────────────┘ \n\+ \ ⇧ \n\+ \ Recursive definitions are not allowed \n\+ \ \n\+ \ \n\+ \● You accidentally forgot a ❰λ❱ or ❰∀❱/❰forall❱ \n\+ \ \n\+ \ \n\+ \ Unbound variable \n\+ \ ⇩ \n\+ \ ┌─────────────────┐ \n\+ \ │ (x : Bool) → x │ \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ A ❰λ❱ here would transform this into a valid anonymous function \n\+ \ \n\+ \ \n\+ \ Unbound variable \n\+ \ ⇩ \n\+ \ ┌────────────────────┐ \n\+ \ │ (x : Bool) → Bool │ \n\+ \ └────────────────────┘ \n\+ \ ⇧ \n\+ \ A ❰∀❱ or ❰forall❱ here would transform this into a valid function type \n\+ \ \n\+ \ \n\+ \● You forgot to prefix a file path with ❰./❱: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ path/to/file.dhall │ \n\+ \ └────────────────────┘ \n\+ \ ⇧ \n\+ \ This should be ❰./path/to/file.dhall❱ \n"++prettyTypeMessage (InvalidInputType expr) = ErrorMessages {..}+ where+ short = "Invalid function input"++ hints = []++ long =+ "Explanation: A function can accept an input “term” that has a given “type”, like\n\+ \this: \n\+ \ \n\+ \ \n\+ \ This is the input term that the function accepts \n\+ \ ⇩ \n\+ \ ┌───────────────────────┐ \n\+ \ │ ∀(x : Natural) → Bool │ This is the type of a function that accepts an \n\+ \ └───────────────────────┘ input term named ❰x❱ that has type ❰Natural❱ \n\+ \ ⇧ \n\+ \ This is the type of the input term \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ Bool → Natural │ This is the type of a function that accepts an anonymous\n\+ \ └────────────────┘ input term that has type ❰Bool❱ \n\+ \ ⇧ \n\+ \ This is the type of the input term \n\+ \ \n\+ \ \n\+ \... or a function can accept an input “type” that has a given “kind”, like this:\n\+ \ \n\+ \ \n\+ \ This is the input type that the function accepts \n\+ \ ⇩ \n\+ \ ┌────────────────────┐ \n\+ \ │ ∀(a : Type) → Type │ This is the type of a function that accepts an input\n\+ \ └────────────────────┘ type named ❰a❱ that has kind ❰Type❱ \n\+ \ ⇧ \n\+ \ This is the kind of the input type \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────┐ \n\+ \ │ (Type → Type) → Type │ This is the type of a function that accepts an \n\+ \ └──────────────────────┘ anonymous input type that has kind ❰Type → Type❱ \n\+ \ ⇧ \n\+ \ This is the kind of the input type \n\+ \ \n\+ \ \n\+ \Other function inputs are " <> _NOT <> " valid, like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────┐ \n\+ \ │ ∀(x : 1) → x │ ❰1❱ is a “term” and not a “type” nor a “kind” so ❰x❱ \n\+ \ └──────────────┘ cannot have “type” ❰1❱ or “kind” ❰1❱ \n\+ \ ⇧ \n\+ \ This is not a type or kind \n\+ \ \n\+ \ \n\+ \ ┌──────────┐ \n\+ \ │ True → x │ ❰True❱ is a “term” and not a “type” nor a “kind” so the \n\+ \ └──────────┘ anonymous input cannot have “type” ❰True❱ or “kind” ❰True❱ \n\+ \ ⇧ \n\+ \ This is not a type or kind \n\+ \ \n\+ \ \n\+ \You annotated a function input with the following expression: \n\+ \ \n\+ \" <> txt <> "\n\+ \ \n\+ \... which is neither a type nor a kind \n"+ where+ txt = insert expr++prettyTypeMessage (InvalidOutputType expr) = ErrorMessages {..}+ where+ short = "Invalid function output"++ hints = []++ long =+ "Explanation: A function can return an output “term” that has a given “type”, \n\+ \like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ ∀(x : Text) → Bool │ This is the type of a function that returns an \n\+ \ └────────────────────┘ output term that has type ❰Bool❱ \n\+ \ ⇧ \n\+ \ This is the type of the output term \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ Bool → Natural │ This is the type of a function that returns an output \n\+ \ └────────────────┘ term that has type ❰Natural❱ \n\+ \ ⇧ \n\+ \ This is the type of the output term \n\+ \ \n\+ \ \n\+ \... or a function can return an output “type” that has a given “kind”, like \n\+ \this: \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ ∀(a : Type) → Type │ This is the type of a function that returns an \n\+ \ └────────────────────┘ output type that has kind ❰Type❱ \n\+ \ ⇧ \n\+ \ This is the kind of the output type \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────┐ \n\+ \ │ (Type → Type) → Type │ This is the type of a function that returns an \n\+ \ └──────────────────────┘ output type that has kind ❰Type❱ \n\+ \ ⇧ \n\+ \ This is the kind of the output type \n\+ \ \n\+ \ \n\+ \Other outputs are " <> _NOT <> " valid, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ ∀(x : Bool) → x │ ❰x❱ is a “term” and not a “type” nor a “kind” so the \n\+ \ └─────────────────┘ output cannot have “type” ❰x❱ or “kind” ❰x❱ \n\+ \ ⇧ \n\+ \ This is not a type or kind \n\+ \ \n\+ \ \n\+ \ ┌─────────────┐ \n\+ \ │ Text → True │ ❰True❱ is a “term” and not a “type” nor a “kind” so the \n\+ \ └─────────────┘ output cannot have “type” ❰True❱ or “kind” ❰True❱ \n\+ \ ⇧ \n\+ \ This is not a type or kind \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You use ❰∀❱ instead of ❰λ❱ by mistake, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ ∀(x: Bool) → x │ \n\+ \ └────────────────┘ \n\+ \ ⇧ \n\+ \ Using ❰λ❱ here instead of ❰∀❱ would transform this into a valid function \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You specified that your function outputs a: \n\+ \ \n\+ \" <> txt <> "\n\+ \ \n\+ \... which is neither a type nor a kind: \n"+ where+ txt = insert expr++prettyTypeMessage (NotAFunction expr0 expr1) = ErrorMessages {..}+ where+ short = "Not a function"++ hints = []++ long =+ "Explanation: Expressions separated by whitespace denote function application, \n\+ \like this: \n\+ \ \n\+ \ \n\+ \ ┌─────┐ \n\+ \ │ f x │ This denotes the function ❰f❱ applied to an argument named ❰x❱ \n\+ \ └─────┘ \n\+ \ \n\+ \ \n\+ \A function is a term that has type ❰a → b❱ for some ❰a❱ or ❰b❱. For example, \n\+ \the following expressions are all functions because they have a function type: \n\+ \ \n\+ \ \n\+ \ The function's input type is ❰Bool❱ \n\+ \ ⇩ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ λ(x : Bool) → x : Bool → Bool │ User-defined anonymous function \n\+ \ └───────────────────────────────┘ \n\+ \ ⇧ \n\+ \ The function's output type is ❰Bool❱ \n\+ \ \n\+ \ \n\+ \ The function's input type is ❰Natural❱ \n\+ \ ⇩ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ Natural/even : Natural → Bool │ Built-in function \n\+ \ └───────────────────────────────┘ \n\+ \ ⇧ \n\+ \ The function's output type is ❰Bool❱ \n\+ \ \n\+ \ \n\+ \ The function's input kind is ❰Type❱ \n\+ \ ⇩ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ λ(a : Type) → a : Type → Type │ Type-level functions are still functions \n\+ \ └───────────────────────────────┘ \n\+ \ ⇧ \n\+ \ The function's output kind is ❰Type❱ \n\+ \ \n\+ \ \n\+ \ The function's input kind is ❰Type❱ \n\+ \ ⇩ \n\+ \ ┌────────────────────┐ \n\+ \ │ List : Type → Type │ Built-in type-level function \n\+ \ └────────────────────┘ \n\+ \ ⇧ \n\+ \ The function's output kind is ❰Type❱ \n\+ \ \n\+ \ \n\+ \ Function's input has kind ❰Type❱ \n\+ \ ⇩ \n\+ \ ┌─────────────────────────────────────────────────┐ \n\+ \ │ List/head : ∀(a : Type) → (List a → Optional a) │ A function can return \n\+ \ └─────────────────────────────────────────────────┘ another function \n\+ \ ⇧ \n\+ \ Function's output has type ❰List a → Optional a❱\n\+ \ \n\+ \ \n\+ \ The function's input type is ❰List Text❱ \n\+ \ ⇩ \n\+ \ ┌────────────────────────────────────────────┐ \n\+ \ │ List/head Text : List Text → Optional Text │ A function applied to an \n\+ \ └────────────────────────────────────────────┘ argument can be a function \n\+ \ ⇧ \n\+ \ The function's output type is ❰Optional Text❱\n\+ \ \n\+ \ \n\+ \An expression is not a function if the expression's type is not of the form \n\+ \❰a → b❱. For example, these are " <> _NOT <> " functions: \n\+ \ \n\+ \ \n\+ \ ┌─────────────┐ \n\+ \ │ 1 : Natural │ ❰1❱ is not a function because ❰Natural❱ is not the type of \n\+ \ └─────────────┘ a function \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ Natural/even 2 : Bool │ ❰Natural/even 2❱ is not a function because \n\+ \ └───────────────────────┘ ❰Bool❱ is not the type of a function \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ List Text : Type │ ❰List Text❱ is not a function because ❰Type❱ is not \n\+ \ └──────────────────┘ the type of a function \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You tried to add two ❰Natural❱s without a space around the ❰+❱, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────┐ \n\+ \ │ 2+2 │ \n\+ \ └─────┘ \n\+ \ \n\+ \ \n\+ \ The above code is parsed as: \n\+ \ \n\+ \ \n\+ \ ┌────────┐ \n\+ \ │ 2 (+2) │ \n\+ \ └────────┘ \n\+ \ ⇧ \n\+ \ The compiler thinks that this ❰2❱ is a function whose argument is ❰+2❱ \n\+ \ \n\+ \ \n\+ \ This is because the ❰+❱ symbol has two meanings: you use ❰+❱ to add two \n\+ \ numbers, but you also can prefix ❰Natural❱ literals with a ❰+❱ to turn them \n\+ \ into ❰Integer❱ literals (like ❰+2❱) \n\+ \ \n\+ \ To fix the code, you need to put spaces around the ❰+❱, like this: \n\+ \ \n\+ \ \n\+ \ ┌───────┐ \n\+ \ │ 2 + 2 │ \n\+ \ └───────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to use the following expression as a function: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... but this expression's type is: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which is not a function type \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (TypeMismatch expr0 expr1 expr2 expr3) = ErrorMessages {..}+ where+ short = "Wrong type of function argument\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr3)++ hints = emptyRecordTypeHint expr2++ long =+ "Explanation: Every function declares what type or kind of argument to accept \n\+ \ \n\+ \For example: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ λ(x : Bool) → x : Bool → Bool │ This anonymous function only accepts \n\+ \ └───────────────────────────────┘ arguments that have type ❰Bool❱ \n\+ \ ⇧ \n\+ \ The function's input type \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ Natural/even : Natural → Bool │ This built-in function only accepts \n\+ \ └───────────────────────────────┘ arguments that have type ❰Natural❱ \n\+ \ ⇧ \n\+ \ The function's input type \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ λ(a : Type) → a : Type → Type │ This anonymous function only accepts \n\+ \ └───────────────────────────────┘ arguments that have kind ❰Type❱ \n\+ \ ⇧ \n\+ \ The function's input kind \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ List : Type → Type │ This built-in function only accepts arguments that \n\+ \ └────────────────────┘ have kind ❰Type❱ \n\+ \ ⇧ \n\+ \ The function's input kind \n\+ \ \n\+ \ \n\+ \For example, the following expressions are valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────┐ \n\+ \ │ (λ(x : Bool) → x) True │ ❰True❱ has type ❰Bool❱, which matches the type \n\+ \ └────────────────────────┘ of argument that the anonymous function accepts \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ Natural/even 2 │ ❰2❱ has type ❰Natural❱, which matches the type of \n\+ \ └────────────────┘ argument that the ❰Natural/even❱ function accepts, \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────┐ \n\+ \ │ (λ(a : Type) → a) Bool │ ❰Bool❱ has kind ❰Type❱, which matches the kind \n\+ \ └────────────────────────┘ of argument that the anonymous function accepts \n\+ \ \n\+ \ \n\+ \ ┌───────────┐ \n\+ \ │ List Text │ ❰Text❱ has kind ❰Type❱, which matches the kind of argument \n\+ \ └───────────┘ that that the ❰List❱ function accepts \n\+ \ \n\+ \ \n\+ \However, you can " <> _NOT <> " apply a function to the wrong type or kind of argument\n\+ \ \n\+ \For example, the following expressions are not valid: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ (λ(x : Bool) → x) \"A\" │ ❰\"A\"❱ has type ❰Text❱, but the anonymous function\n\+ \ └───────────────────────┘ expects an argument that has type ❰Bool❱ \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ Natural/even \"A\" │ ❰\"A\"❱ has type ❰Text❱, but the ❰Natural/even❱ function\n\+ \ └──────────────────┘ expects an argument that has type ❰Natural❱ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────┐ \n\+ \ │ (λ(a : Type) → a) True │ ❰True❱ has type ❰Bool❱, but the anonymous \n\+ \ └────────────────────────┘ function expects an argument of kind ❰Type❱ \n\+ \ \n\+ \ \n\+ \ ┌────────┐ \n\+ \ │ List 1 │ ❰1❱ has type ❰Natural❱, but the ❰List❱ function expects an \n\+ \ └────────┘ argument that has kind ❰Type❱ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You omit a function argument by mistake: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ List/head [1, 2, 3] │ \n\+ \ └───────────────────────┘ \n\+ \ ⇧ \n\+ \ ❰List/head❱ is missing the first argument, \n\+ \ which should be: ❰Natural❱ \n\+ \ \n\+ \ \n\+ \● You supply an ❰Integer❱ literal to a function that expects a ❰Natural❱ \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ Natural/even +2 │ \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This should be ❰2❱ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to invoke the following function: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which expects an argument of type or kind: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... on the following argument: \n\+ \ \n\+ \" <> txt2 <> "\n\+ \ \n\+ \... which has a different type or kind: \n\+ \ \n\+ \" <> txt3 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1+ txt2 = insert expr2+ txt3 = insert expr3++prettyTypeMessage (AnnotMismatch expr0 expr1 expr2) = ErrorMessages {..}+ where+ short = "Expression doesn't match annotation\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr2)++ hints = []++ long =+ "Explanation: You can annotate an expression with its type or kind using the \n\+ \❰:❱ symbol, like this: \n\+ \ \n\+ \ \n\+ \ ┌───────┐ \n\+ \ │ x : t │ ❰x❱ is an expression and ❰t❱ is the annotated type or kind of ❰x❱\n\+ \ └───────┘ \n\+ \ \n\+ \The type checker verifies that the expression's type or kind matches the \n\+ \provided annotation \n\+ \ \n\+ \For example, all of the following are valid annotations that the type checker \n\+ \accepts: \n\+ \ \n\+ \ \n\+ \ ┌─────────────┐ \n\+ \ │ 1 : Natural │ ❰1❱ is an expression that has type ❰Natural❱, so the type \n\+ \ └─────────────┘ checker accepts the annotation \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ Natural/even 2 : Bool │ ❰Natural/even 2❱ has type ❰Bool❱, so the type \n\+ \ └───────────────────────┘ checker accepts the annotation \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ List : Type → Type │ ❰List❱ is an expression that has kind ❰Type → Type❱,\n\+ \ └────────────────────┘ so the type checker accepts the annotation \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ List Text : Type │ ❰List Text❱ is an expression that has kind ❰Type❱, so \n\+ \ └──────────────────┘ the type checker accepts the annotation \n\+ \ \n\+ \ \n\+ \However, the following annotations are " <> _NOT <> " valid and the type checker will\n\+ \reject them: \n\+ \ \n\+ \ \n\+ \ ┌──────────┐ \n\+ \ │ 1 : Text │ The type checker rejects this because ❰1❱ does not have type \n\+ \ └──────────┘ ❰Text❱ \n\+ \ \n\+ \ \n\+ \ ┌─────────────┐ \n\+ \ │ List : Type │ ❰List❱ does not have kind ❰Type❱ \n\+ \ └─────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● The Haskell Dhall interpreter implicitly inserts a top-level annotation \n\+ \ matching the expected type \n\+ \ \n\+ \ For example, if you run the following Haskell code: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────┐ \n\+ \ │ >>> input auto \"1\" :: IO Text │ \n\+ \ └───────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ... then the interpreter will actually type check the following annotated \n\+ \ expression: \n\+ \ \n\+ \ \n\+ \ ┌──────────┐ \n\+ \ │ 1 : Text │ \n\+ \ └──────────┘ \n\+ \ \n\+ \ \n\+ \ ... and then type-checking will fail \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You or the interpreter annotated this expression: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... with this type or kind: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but the inferred type or kind of the expression is actually: \n\+ \ \n\+ \" <> txt2 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1+ txt2 = insert expr2++prettyTypeMessage Untyped = ErrorMessages {..}+ where+ short = "❰Sort❱ has no type, kind, or sort"++ hints = []++ long =+ "Explanation: There are five levels of expressions that form a hierarchy: \n\+ \ \n\+ \● terms \n\+ \● types \n\+ \● kinds \n\+ \● sorts \n\+ \● orders \n\+ \ \n\+ \The following example illustrates this hierarchy: \n\+ \ \n\+ \ ┌───────────────────────────────────┐ \n\+ \ │ \"ABC\" : Text : Type : Kind : Sort │ \n\+ \ └───────────────────────────────────┘ \n\+ \ ⇧ ⇧ ⇧ ⇧ ⇧ \n\+ \ term type kind sort order \n\+ \ \n\+ \There is nothing above ❰Sort❱ in this hierarchy, so if you try to type check any\n\+ \expression containing ❰Sort❱ anywhere in the expression then type checking fails\n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You supplied a sort where a kind was expected \n\+ \ \n\+ \ For example, the following expression will fail to type check: \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ f : Type -> Kind │ \n\+ \ └──────────────────┘ \n\+ \ ⇧ \n\+ \ ❰Kind❱ is a sort, not a kind \n"++prettyTypeMessage (InvalidPredicate expr0 expr1) = ErrorMessages {..}+ where+ short = "Invalid predicate for ❰if❱: "+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized Bool expr1)++ hints = []++ long =+ "Explanation: Every ❰if❱ expression begins with a predicate which must have type \n\+ \❰Bool❱ \n\+ \ \n\+ \For example, these are valid ❰if❱ expressions: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────┐ \n\+ \ │ if True then \"Yes\" else \"No\" │ \n\+ \ └──────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Predicate \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────┐ \n\+ \ │ λ(x : Bool) → if x then False else True │ \n\+ \ └─────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Predicate \n\+ \ \n\+ \ \n\+ \... but these are " <> _NOT <> " valid ❰if❱ expressions: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────┐ \n\+ \ │ if 0 then \"Yes\" else \"No\" │ ❰0❱ does not have type ❰Bool❱ \n\+ \ └───────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ if \"\" then False else True │ ❰\"\"❱ does not have type ❰Bool❱ \n\+ \ └────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You might be used to other programming languages that accept predicates other \n\+ \ than ❰Bool❱ \n\+ \ \n\+ \ For example, some languages permit ❰0❱ or ❰\"\"❱ as valid predicates and treat\n\+ \ them as equivalent to ❰False❱. However, the Dhall language does not permit \n\+ \ this \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \Your ❰if❱ expression begins with the following predicate: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... that has type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but the predicate must instead have type ❰Bool❱ \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (IfBranchMismatch expr0 expr1 expr2 expr3) =+ ErrorMessages {..}+ where+ short = "❰if❱ branches must have matching types\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr3)++ hints = []++ long =+ "Explanation: Every ❰if❱ expression has a ❰then❱ and ❰else❱ branch, each of which\n\+ \is an expression: \n\+ \ \n\+ \ \n\+ \ Expression for ❰then❱ branch \n\+ \ ⇩ \n\+ \ ┌────────────────────────────────┐ \n\+ \ │ if True then \"Hello, world!\" │ \n\+ \ │ else \"Goodbye, world!\" │ \n\+ \ └────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Expression for ❰else❱ branch \n\+ \ \n\+ \ \n\+ \These two expressions must have the same type. For example, the following ❰if❱ \n\+ \expressions are all valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ λ(b : Bool) → if b then 0 else 1 │ Both branches have type ❰Natural❱ \n\+ \ └──────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ λ(b : Bool) → │ \n\+ \ │ if b then Natural/even │ Both branches have type ❰Natural → Bool❱ \n\+ \ │ else Natural/odd │ \n\+ \ └────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \However, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ This branch has type ❰Natural❱ \n\+ \ ⇩ \n\+ \ ┌────────────────────────┐ \n\+ \ │ if True then 0 │ \n\+ \ │ else \"ABC\" │ \n\+ \ └────────────────────────┘ \n\+ \ ⇧ \n\+ \ This branch has type ❰Text❱ \n\+ \ \n\+ \ \n\+ \The ❰then❱ and ❰else❱ branches must have matching types, even if the predicate \n\+ \is always ❰True❱ or ❰False❱ \n\+ \ \n\+ \Your ❰if❱ expression has the following ❰then❱ branch: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which has type: \n\+ \ \n\+ \" <> txt2 <> "\n\+ \ \n\+ \... and the following ❰else❱ branch: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which has a different type: \n\+ \ \n\+ \" <> txt3 <> "\n\+ \ \n\+ \Fix your ❰then❱ and ❰else❱ branches to have matching types \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1+ txt2 = insert expr2+ txt3 = insert expr3++prettyTypeMessage (ListLitInvariant) = ErrorMessages {..}+ where+ short = "Internal error: A non-empty list literal violated an internal invariant"++ hints = []++ long =+ "Explanation: Internal error: A non-empty list literal violated an internal \n\+ \invariant. \n\+ \ \n\+ \A non-empty list literal must always be represented as \n\+ \ \n\+ \ ListLit Nothing [x, y, ...] \n\+ \ \n\+ \Please file a bug report at https://github.com/dhall-lang/dhall-haskell/issues, \n\+ \ideally including the offending source code. \n"++prettyTypeMessage (InvalidListType expr0) = ErrorMessages {..}+ where+ short = "Invalid type for ❰List❱"++ hints = []++ long =+ "Explanation: ❰List❱s can optionally document their type with a type annotation, \n\+ \like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────┐ \n\+ \ │ [1, 2, 3] : List Natural │ A ❰List❱ of three ❰Natural❱ numbers \n\+ \ └──────────────────────────┘ \n\+ \ ⇧ \n\+ \ The type of the ❰List❱'s elements, which are ❰Natural❱ \n\+ \ numbers \n\+ \ \n\+ \ \n\+ \ ┌───────────────────┐ \n\+ \ │ [] : List Natural │ An empty ❰List❱ \n\+ \ └───────────────────┘ \n\+ \ ⇧ \n\+ \ You must specify the type when the ❰List❱ is empty \n\+ \ \n\+ \ \n\+ \The type must be of the form ❰List ...❱ and not something else. For example, \n\+ \the following type annotation is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────┐ \n\+ \ │ ... : Bool │ \n\+ \ └────────────┘ \n\+ \ ⇧ \n\+ \ This type does not have the form ❰List ...❱ \n\+ \ \n\+ \ \n\+ \The element type must be a type and not something else. For example, the \n\+ \following element types are " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────┐ \n\+ \ │ ... : List 1 │ \n\+ \ └──────────────┘ \n\+ \ ⇧ \n\+ \ This is a ❰Natural❱ number and not a ❰Type❱ \n\+ \ \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ ... : List Type │ \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This is a ❰Kind❱ and not a ❰Type❱ \n\+ \ \n\+ \ \n\+ \You declared that the ❰List❱ should have type: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a valid list type \n"+ where+ txt0 = insert expr0++prettyTypeMessage MissingListType =+ ErrorMessages {..}+ where+ short = "An empty list requires a type annotation"++ hints = []++ long =+ "Explanation: Lists do not require a type annotation if they have at least one \n\+ \element: \n\+ \ \n\+ \ \n\+ \ ┌───────────┐ \n\+ \ │ [1, 2, 3] │ The compiler can infer that this list has type ❰List Natural❱\n\+ \ └───────────┘ \n\+ \ \n\+ \ \n\+ \However, empty lists still require a type annotation: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────┐ \n\+ \ │ [] : List Natural │ This type annotation is mandatory \n\+ \ └───────────────────┘ \n\+ \ \n\+ \ \n\+ \You cannot supply an empty list without a type annotation \n"++prettyTypeMessage (MismatchedListElements i expr0 _expr1 expr2) =+ ErrorMessages {..}+ where+ short = "List elements should all have the same type\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr2)++ hints = []++ long =+ "Explanation: Every element in a list must have the same type \n\+ \ \n\+ \For example, this is a valid ❰List❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────┐ \n\+ \ │ [1, 2, 3] │ Every element in this ❰List❱ is a ❰Natural❱ number \n\+ \ └───────────┘ \n\+ \ \n\+ \ \n\+ \.. but this is " <> _NOT <> " a valid ❰List❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────────┐ \n\+ \ │ [1, \"ABC\", 3] │ The first and second element have different types \n\+ \ └───────────────┘ \n\+ \ \n\+ \ \n\+ \Your first ❰List❱ element has this type: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... but the element at index #" <> txt1 <> " has this type instead: \n\+ \ \n\+ \" <> txt3 <> "\n"+ where+ txt0 = insert expr0+ txt1 = pretty i+ txt3 = insert expr2++prettyTypeMessage (InvalidSome expr0 expr1 expr2) = ErrorMessages {..}+ where+ short = "❰Some❱ argument has the wrong type"++ hints = []++ long =+ "Explanation: The ❰Some❱ constructor expects an argument that is a term, where \n\+ \the type of the type of a term must be ❰Type❱ \n\+ \ \n\+ \For example, this is a valid use of ❰Some❱: \n\+ \ \n\+ \ \n\+ \ ┌────────┐ \n\+ \ │ Some 1 │ ❰1❱ is a valid term because ❰1 : Natural : Type❱ \n\+ \ └────────┘ \n\+ \ \n\+ \ \n\+ \... but this is " <> _NOT <> " a valid ❰Optional❱ value: \n\+ \ \n\+ \ \n\+ \ ┌───────────┐ \n\+ \ │ Some Text │ ❰Text❱ is not a valid term because ❰Text : Type : Kind ❱ \n\+ \ └───────────┘ \n\+ \ \n\+ \ \n\+ \The ❰Some❱ argument you provided: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... has this type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but the type of that type is: \n\+ \ \n\+ \" <> txt2 <> "\n\+ \ \n\+ \... which is not ❰Type❱ \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1+ txt2 = insert expr2++prettyTypeMessage (InvalidFieldType k expr0) = ErrorMessages {..}+ where+ short = "Invalid field type"++ hints = []++ long =+ "Explanation: Every record type annotates each field with a ❰Type❱, a ❰Kind❱, or \n\+ \a ❰Sort❱ like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────────┐ \n\+ \ │ { foo : Natural, bar : Integer, baz : Text } │ Every field is annotated \n\+ \ └──────────────────────────────────────────────┘ with a ❰Type❱ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ { foo : Type, bar : Type } │ Every field is annotated \n\+ \ └────────────────────────────┘ with a ❰Kind❱ \n\+ \ \n\+ \ \n\+ \However, the types of fields may " <> _NOT <> " be term-level values: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ { foo : Natural, bar : 1 } │ Invalid record type \n\+ \ └────────────────────────────┘ \n\+ \ ⇧ \n\+ \ ❰1❱ is a ❰Natural❱ number and not a ❰Type❱, \n\+ \ ❰Kind❱, or ❰Sort❱ \n\+ \ \n\+ \ \n\+ \You provided a record type with a field named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... annotated with the following expression: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which is neither a ❰Type❱, a ❰Kind❱, nor a ❰Sort❱ \n"+ where+ txt0 = insert k+ txt1 = insert expr0++prettyTypeMessage (InvalidAlternativeType k expr0) = ErrorMessages {..}+ where+ short = "Invalid alternative type"++ hints = []++ long =+ "Explanation: Every union type specifies the type of each alternative, like this:\n\+ \ \n\+ \ \n\+ \ The type of the first alternative is ❰Bool❱ \n\+ \ ⇩ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ < Left : Bool, Right : Natural > │ A union type with two alternatives \n\+ \ └──────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ The type of the second alternative is ❰Natural❱ \n\+ \ \n\+ \ \n\+ \However, these alternatives can only be annotated with ❰Type❱s, ❰Kind❱s, or \n\+ \❰Sort❱s. For example, the following union types are " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ < Left : Bool, Right : 1 > │ Invalid union type \n\+ \ └────────────────────────────┘ \n\+ \ ⇧ \n\+ \ This is a ❰Natural❱ and not a ❰Type❱, ❰Kind❱, or \n\+ \ ❰Sort❱ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You accidentally typed ❰:❱ instead of ❰=❱ for a union literal with one \n\+ \ alternative: \n\+ \ \n\+ \ ┌─────────────────┐ \n\+ \ │ < Example : 1 > │ \n\+ \ └─────────────────┘ \n\+ \ ⇧ \n\+ \ This could be ❰=❱ instead \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided a union type with an alternative named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... annotated with the following expression which is not a ❰Type❱, ❰Kind❱, or \n\+ \❰Sort❱: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert k+ txt1 = insert expr0++prettyTypeMessage (ListAppendMismatch expr0 expr1) = ErrorMessages {..}+ where+ short = "You can only append ❰List❱s with matching element types\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)++ hints = []++ long =+ "Explanation: You can append two ❰List❱s using the ❰#❱ operator, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ [1, 2, 3] # [4, 5] │ \n\+ \ └────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot append two ❰List❱s if they have different element types. \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ These elements have type ❰Natural❱ \n\+ \ ⇩ \n\+ \ ┌───────────────────────────┐ \n\+ \ │ [1, 2, 3] # [True, False] │ Invalid: the element types don't match \n\+ \ └───────────────────────────┘ \n\+ \ ⇧ \n\+ \ These elements have type ❰Bool❱ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to append a ❰List❱ thas has elements of type: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... with another ❰List❱ that has elements of type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... and those two types do not match \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (CompletionSchemaMustBeARecord expr0 expr1) = ErrorMessages {..}+ where+ short = "The completion schema must be a record"++ hints = []++ long =+ "Explanation: You can complete records using the ❰::❱ operator: \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────────┐ \n\+ \ │ {Type = {foo : Bool, bar : Natural}, default = {bar = 2}::{foo = True}} │ \n\+ \ └─────────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \... The left-hand side of :: must be a record with 'Type' and 'default' keys \n\+ \ \n\+ \You tried to record complete the following value: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a record. It is: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (InvalidRecordCompletion fieldName expr0) = ErrorMessages {..}+ where+ short = "Completion schema is missing a field: " <> pretty fieldName++ hints = []++ long =+ "Explanation: You can complete records using the ❰::❱ operator like this:\n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────────┐ \n\+ \ │ {Type = {foo : Bool, bar : Natural}, default = {bar = 2}::{foo = True}} │ \n\+ \ └─────────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \... but you need to have both Type and default fields in the completion schema \n\+ \ (the record on the left of the the ::). \n\+ \ \n\+ \You tried to do record completion using the schema: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is missing the key: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = pretty fieldName++prettyTypeMessage (MustCombineARecord c expression typeExpression) =+ ErrorMessages {..}+ where+ action = case c of+ '∧' -> "combine"+ _ -> "override"++ short = "You can only " <> action <> " records"++ hints = emptyRecordTypeHint expression++ long =+ "Explanation: You can " <> action <> " records using the ❰" <> op <> "❱ operator, like this:\n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } " <> op <> " { baz = True } │ \n\+ \ └───────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────┐ \n\+ \ │ λ(r : { foo : Bool }) → r " <> op <> " { bar = \"ABC\" } │ \n\+ \ └─────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot " <> action <> " values that are not records. \n\+ \ \n\+ \For example, the following expressions are " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } " <> op <> " 1 │ \n\+ \ └──────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: Not a record \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } " <> op <> " { baz : Bool } │ \n\+ \ └───────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: This is a record type and not a record\n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } " <> op <> " < baz : Bool > │ \n\+ \ └───────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: This is a union type and not a record \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You supplied this expression as one of the arguments: \n\+ \ \n\+ \" <> insert expression <> "\n\+ \ \n\+ \... which is not a record, but is actually a: \n\+ \ \n\+ \" <> insert typeExpression <> "\n"+ where+ op = pretty c++prettyTypeMessage (InvalidDuplicateField k expr0 expr1) =+ ErrorMessages {..}+ where+ short = "Invalid duplicate field: " <> Dhall.Pretty.Internal.prettyLabel k++ hints = []++ long =+ "Explanation: You can specify a field twice if both fields are themselves \n\+ \records, like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────────────────────┐ \n\+ \ │ { ssh = { enable = True }, ssh = { forwardX11 = True } } │ \n\+ \ └──────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... because the language automatically merges two occurrences of a field using \n\+ \the ❰∧❱ operator, and the above example is equivalent to: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────┐ \n\+ \ │ { ssh = { enable = True } ∧ { forwardX11 = True } } │ \n\+ \ └─────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... which is in turn equivalent to: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────────┐ \n\+ \ │ { ssh = { enable = True, forwardX11 = True } } │ \n\+ \ └────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \However, this implies that both fields must be records since the ❰∧❱ operator \n\+ \cannot merge non-record values. For example, these expressions are not valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ { x = 0, x = 0 } │ Invalid: Neither field is a record \n\+ \ └──────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────┐ \n\+ \ │ { x = 0, x = { y = 0 } } │ Invalid: The first ❰x❱ field is not a record \n\+ \ └──────────────────────────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You specified more than one field named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... but one of the fields had this value: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... with this type: \n\+ \ \n\+ \" <> txt2 <> "\n\+ \ \n\+ \... which is not a record type \n"+ where+ txt0 = insert (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome k)+ txt1 = insert expr0+ txt2 = insert expr1++prettyTypeMessage (CombineTypesRequiresRecordType expr0 expr1) =+ ErrorMessages {..}+ where+ short = "❰⩓❱ requires arguments that are record types"++ hints = []++ long =+ "Explanation: You can only use the ❰⩓❱ operator on arguments that are record type\n\+ \literals, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────┐ \n\+ \ │ { age : Natural } ⩓ { name : Text } │ \n\+ \ └─────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot use the ❰⩓❱ operator on any other type of arguments. For \n\+ \example, you cannot use variable arguments: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────┐ \n\+ \ │ λ(t : Type) → t ⩓ { name : Text } │ Invalid: ❰t❱ might not be a record \n\+ \ └───────────────────────────────────┘ type \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to supply the following argument: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which normalized to: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which is not a record type literal \n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (DuplicateFieldCannotBeMerged ks) = ErrorMessages {..}+ where+ short = "Duplicate field cannot be merged: " <> pretty (toPath ks)++ hints = []++ long =+ "Explanation: Duplicate fields are only allowed if they are both records and if \n\+ \the two records can be recursively merged without collisions. \n\+ \ \n\+ \Specifically, an expression like: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ { x = a, x = b } │ \n\+ \ └──────────────────┘ \n\+ \ \n\+ \ \n\+ \... is syntactic sugar for: \n\+ \ \n\+ \ \n\+ \ ┌───────────────┐ \n\+ \ │ { x = a ∧ b } │ \n\+ \ └───────────────┘ \n\+ \ \n\+ \ \n\+ \... which is rejected if ❰a ∧ b❱ does not type-check. One way this can happen \n\+ \is if ❰a❱ and ❰b❱ share a field in common that is not a record, which is known \n\+ \as a \"collision\". \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ { x = { y = 0 }, x = { y = 1 } } │ Invalid: The two ❰x.y❱ fields \"collide\"\n\+ \ └──────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... whereas the following expression is valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ { x = { y = 0 }, x = { z = 1 } } │ Valid: the two ❰x❱ fields don't collide\n\+ \ └──────────────────────────────────┘ because they can be recursively merged \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You specified the same field twice by mistake \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You specified the following field twice: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which collided on the following path: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome (NonEmpty.head ks))++ txt1 = insert (toPath ks)++prettyTypeMessage (FieldCollision ks) = ErrorMessages {..}+ where+ short = "Field collision on: " <> pretty (toPath ks)++ hints = []++ long =+ "Explanation: You can recursively merge records using the ❰∧❱ operator: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ { x = a } ∧ { y = b } │ \n\+ \ └───────────────────────┘ \n\+ \ \n\+ \... but two records cannot be merged in this way if they share a field that is \n\+ \not a record. \n\+ \ \n\+ \For example, the following expressions are " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────┐ \n\+ \ │ { x = 1 } ∧ { x = True } │ Invalid: The ❰x❱ fields \"collide\" because they\n\+ \ └──────────────────────────┘ are not records that can be merged \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ { x = 1 } ∧ { x = { y = True } } │ Invalid: One of the two ❰x❱ fields is \n\+ \ └──────────────────────────────────┘ still not a record \n\+ \ \n\+ \ \n\+ \... but the following expression is valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ Valid: The two ❰x❱ fields \n\+ \ │ { x = { y = True } } ∧ { x = { z = 1 } } │ don't collide because they can\n\+ \ └──────────────────────────────────────────┘ be recursively merged \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You tried to use ❰∧❱ to update a field's value, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } ∧ { foo = 2 } │ \n\+ \ └────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid attempt to update ❰foo❱'s value to ❰2❱\n\+ \ \n\+ \ \n\+ \ You probably meant to use ❰⫽❱ / ❰//❱ instead: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = \"ABC\" } ⫽ { foo = 2 } │ \n\+ \ └────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to merge two records which collided on the following path: \n\+ \ \n\+ \" <> txt0 <> "\n"+ where+ txt0 = insert (toPath ks)++prettyTypeMessage (FieldTypeCollision ks) = ErrorMessages {..}+ where+ short = "Field type collision on: " <> pretty (toPath ks)++ hints = []++ long =+ "Explanation: You can recursively merge record types using the ❰⩓❱ operator, like\n\+ \this: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ { x : A } ⩓ { y : B } │ \n\+ \ └───────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot merge record types if two field types collide that are not \n\+ \both record types. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────┐ \n\+ \ │ { x : Natural } ⩓ { x : Bool } │ Invalid: The ❰x❱ fields \"collide\" \n\+ \ └────────────────────────────────┘ because they cannot be merged \n\+ \ \n\+ \ \n\+ \... but the following expression is valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────────┐ Valid: The ❰x❱ field \n\+ \ │ { x : { y : Bool } } ⩓ { x : { z : Natural } } │ types don't collide and \n\+ \ └────────────────────────────────────────────────┘ can be merged \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to merge two record types which collided on the following path: \n\+ \ \n\+ \" <> txt0 <> "\n"+ where+ txt0 = insert (toPath ks)++prettyTypeMessage (MustMergeARecord expr0 expr1) = ErrorMessages {..}+ where+ short = "❰merge❱ expects a record of handlers"++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ in let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the first argument to ❰merge❱ must be a record and not some other type. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────┐ \n\+ \ │ let handler = λ(x : Bool) → x │ \n\+ \ │ in merge handler (< Foo : Bool >.Foo True) │ \n\+ \ └─────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: ❰handler❱ isn't a record \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You accidentally provide an empty record type instead of an empty record when \n\+ \ you ❰merge❱ an empty union: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ λ(x : <>) → λ(a : Type) → merge {} x : a │ \n\+ \ └──────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ This should be ❰{=}❱ instead \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided the following handler: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a record, but is actually a value of type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (MustMergeUnionOrOptional expr0 expr1) = ErrorMessages {..}+ where+ short = "❰merge❱ expects a union or an ❰Optional❱"++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... or this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────┐ \n\+ \ │ let optional = None Bool │ \n\+ \ │ let handlers = { None = False, Some = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers optional │ \n\+ \ └─────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the second argument to ❰merge❱ must not be some other type. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ let handlers = { Foo = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers True │ \n\+ \ └──────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: ❰True❱ isn't a union or an ❰Optional❱ \n\+ \ \n\+ \ \n\+ \You tried to ❰merge❱ this expression: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a union or an ❰Optional❱, but is actually a value of type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (UnusedHandler ks) = ErrorMessages {..}+ where+ short = "Unused handler"++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you must provide exactly one handler per alternative in the union. You \n\+ \cannot supply extra handlers \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural >.Left 2 │ The ❰Right❱ alternative is \n\+ \ │ let handlers = │ missing \n\+ \ │ { Left = Natural/even │ \n\+ \ │ , Right = λ(x : Bool) → x │ Invalid: ❰Right❱ handler isn't\n\+ \ │ } │ used \n\+ \ │ in merge handlers union │ \n\+ \ └──────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \You provided the following handlers: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which had no matching alternatives in the union you tried to ❰merge❱ \n"+ where+ txt0 = insert (Text.intercalate ", " (Data.Set.toList ks))++prettyTypeMessage (MissingHandler exemplar ks) = ErrorMessages {..}+ where+ short = case Data.Set.toList ks of+ [] -> "Missing handler: " <> Dhall.Pretty.Internal.prettyLabel exemplar+ xs@(_:_) -> "Missing handlers: " <> (Pretty.hsep . Pretty.punctuate Pretty.comma+ . map Dhall.Pretty.Internal.prettyLabel $ exemplar:xs)++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you must provide exactly one handler per alternative in the union. You \n\+ \cannot omit any handlers \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ Invalid: Missing ❰Right❱ handler \n\+ \ ⇩ \n\+ \ ┌──────────────────────────────────────────────────────────────┐ \n\+ \ │ let handlers = { Left = Natural/even } │ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ in merge handlers union │ \n\+ \ └──────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \Note that you need to provide handlers for other alternatives even if those \n\+ \alternatives are never used \n\+ \ \n\+ \You need to supply the following handlers: \n\+ \ \n\+ \" <> txt0 <> "\n"+ where+ txt0 = insert (Text.intercalate ", " (exemplar : Data.Set.toList ks))++prettyTypeMessage MissingMergeType =+ ErrorMessages {..}+ where+ short = "An empty ❰merge❱ requires a type annotation"++ hints = []++ long =+ "Explanation: A ❰merge❱ does not require a type annotation if the union has at \n\+ \least one alternative, like this \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \However, you must provide a type annotation when merging an empty union: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────┐ \n\+ \ │ λ(a : <>) → merge {=} a : Bool │ \n\+ \ └────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ This can be any type \n\+ \ \n\+ \ \n\+ \You can provide any type at all as the annotation, since merging an empty \n\+ \union can produce any type of output \n"++prettyTypeMessage (HandlerInputTypeMismatch expr0 expr1 expr2) =+ ErrorMessages {..}+ where+ short = "Wrong handler input type\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr1 expr2)++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... as long as the input type of each handler function matches the type of the \n\+ \corresponding alternative: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────────────────────┐ \n\+ \ │ union : < Left : Natural | Right : Bool > │ \n\+ \ └───────────────────────────────────────────────────────────┘ \n\+ \ ⇧ ⇧ \n\+ \ These must match These must match \n\+ \ ⇩ ⇩ \n\+ \ ┌───────────────────────────────────────────────────────────┐ \n\+ \ │ handlers : { Left : Natural → Bool, Right : Bool → Bool } │ \n\+ \ └───────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ Invalid: Doesn't match the type of the ❰Right❱ alternative \n\+ \ ⇩ \n\+ \ ┌──────────────────────────────────────────────────────────────────┐ \n\+ \ │ let handlers = { Left = Natural/even | Right = λ(x : Text) → x } │ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ in merge handlers union │ \n\+ \ └──────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \Your handler for the following alternative: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... needs to accept an input value of type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but actually accepts an input value of a different type: \n\+ \ \n\+ \" <> txt2 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1+ txt2 = insert expr2++prettyTypeMessage (DisallowedHandlerType label handlerType handlerOutputType variable) =+ ErrorMessages {..}+ where+ short = "Disallowed handler type"++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the output type of a handler may not depend on the input value. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ Invalid: The output type is ❰Optional A❱, which references the input \n\+ \ value ❰A❱. \n\+ \ ⇩ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ merge { x = None } (< x : Type >.x Bool) │ \n\+ \ └──────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \Your handler for the following alternative: \n\+ \ \n\+ \" <> insert label <> "\n\+ \ \n\+ \... has type: \n\+ \ \n\+ \" <> insert handlerType <> "\n\+ \ \n\+ \... where the output type: \n\+ \ \n\+ \" <> insert handlerOutputType <> "\n\+ \ \n\+ \... references the handler's input value: \n\+ \ \n\+ \" <> insert variable <> "\n"++prettyTypeMessage (HandlerOutputTypeMismatch key0 expr0 key1 expr1) =+ ErrorMessages {..}+ where+ short = "Handlers should have the same output type\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... as long as the output type of each handler function is the same: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────────────────────┐ \n\+ \ │ handlers : { Left : Natural → Bool, Right : Bool → Bool } │ \n\+ \ └───────────────────────────────────────────────────────────┘ \n\+ \ ⇧ ⇧ \n\+ \ These output types both match \n\+ \ \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────┐ \n\+ \ │ let Union = < Left : Natural | Right : Bool > │ \n\+ \ │ let handlers = │ \n\+ \ │ { Left = λ(x : Natural) → x │ This outputs ❰Natural❱ \n\+ \ │ , Right = λ(x : Bool ) → x │ This outputs ❰Bool❱ \n\+ \ │ } │ \n\+ \ │ in merge handlers (Union.Left 2) │ \n\+ \ └─────────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: The handlers in this record don't have matching outputs\n\+ \ \n\+ \ \n\+ \The handler for the ❰" <> txt0 <> "❱ alternative has this output type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but the handler for the ❰" <> txt2 <> "❱ alternative has this output type instead:\n\+ \ \n\+ \" <> txt3 <> "\n"+ where+ txt0 = pretty key0+ txt1 = insert expr0+ txt2 = pretty key1+ txt3 = insert expr1++prettyTypeMessage (HandlerNotAFunction k expr0) = ErrorMessages {..}+ where+ short = "Handler for "<> Dhall.Pretty.Internal.prettyLabel k <> " is not a function"++ hints = []++ long =+ "Explanation: You can ❰merge❱ the alternatives of a union or an ❰Optional❱ using \n\+ \a record with one handler per alternative, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────┐ \n\+ \ │ let union = < Left : Natural | Right : Bool >.Left 2 │ \n\+ \ │ let handlers = { Left = Natural/even, Right = λ(x : Bool) → x } │ \n\+ \ │ in merge handlers union │ \n\+ \ └─────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... as long as each handler is a function -- FIXME \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────────┐ \n\+ \ │ merge { Foo = True } (< Foo : Natural >.Foo 1) │ \n\+ \ └────────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: Not a function \n\+ \ \n\+ \ \n\+ \Your handler for this alternative: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... has the following type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which is not the type of a function \n"+ where+ txt0 = insert k+ txt1 = insert expr0++prettyTypeMessage (MustMapARecord provided _providedType) = ErrorMessages {..}+ where+ short = "❰toMap❱ expects a record value"++ hints = emptyRecordTypeHint provided++ long =+ "Explanation: You can apply ❰toMap❱ to any homogenous record, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ let record = { one = 1, two = 2 } │ \n\+ \ │ in toMap record : List { mapKey : Text, mapValue : Natural} │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the argument to ❰toMap❱ must be a record and not some other type. \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You accidentally provide an empty record type instead of an empty record when \n\+ \ using ❰toMap❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────────────────┐ \n\+ \ │ toMap {} : List { mapKey : Text, mapValue : Natural } │ \n\+ \ └───────────────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ This should be ❰{=}❱ instead \n"++prettyTypeMessage (InvalidToMapRecordKind type_ kind) = ErrorMessages {..}+ where+ short = "❰toMap❱ expects a record of kind ❰Type❱"++ hints = []++ long =+ "Explanation: You can apply ❰toMap❱ to any homogenous record of kind ❰Type❱, like\n\+ \ this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ let record = { one = 1, two = 2 } │ \n\+ \ │ in toMap record : List { mapKey : Text, mapValue : Natural} │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but records of kind ❰Kind❱ or ❰Sort❱ cannot be turned into ❰List❱s. \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You applied ❰toMap❱ to a record of the following type: \n\+ \ \n\+ \" <> insert type_ <> "\n\+ \ \n\+ \... which has kind \n\+ \ \n\+ \" <> insert kind <> "\n"++prettyTypeMessage (HeterogenousRecordToMap _expr0 _expr1 _expr2) = ErrorMessages {..}+ where+ short = "❰toMap❱ expects a homogenous record"++ hints = []++ long =+ "Explanation: You can apply ❰toMap❱ to any homogenous record, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ let record = { one = 1, two = 2 } │ \n\+ \ │ in toMap record : List { mapKey : Text, mapValue : Natural} │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but every field of the record must have the same type. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────┐ \n\+ \ │ toMap { Foo = True, Bar = 0 } │ \n\+ \ └─────────────────────────────────────────┘ \n\+ \ ⇧ ⇧ \n\+ \ Bool Natural \n"++prettyTypeMessage (MapTypeMismatch expr0 expr1) = ErrorMessages {..}+ where+ short = "❰toMap❱ result type doesn't match annotation"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)++ hints = []++ long =+ "Explanation: a ❰toMap❱ application has been annotated with a type that doesn't \n\+ \match its inferred type. \n"++prettyTypeMessage (InvalidToMapType expr) =+ ErrorMessages {..}+ where+ short = "An empty ❰toMap❱ was annotated with an invalid type"+ <> "\n"+ <> insert expr++ hints = []++ long =+ "Explanation: A ❰toMap❱ applied to an empty record must have a type annotation: \n\+ \that matches a list of key-value pairs, like this \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ toMap {=} : List { mapKey : Text, mapValue : Natural} │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \The type you have provided doesn't match the expected form. \n\+ \ \n"++prettyTypeMessage MissingToMapType =+ ErrorMessages {..}+ where+ short = "An empty ❰toMap❱ requires a type annotation"++ hints = []++ long =+ "Explanation: A ❰toMap❱ does not require a type annotation if the record has at \n\+ \least one field, like this \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ let record = { one = 1, two = 2 } │ \n\+ \ │ in toMap record │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \However, you must provide a type annotation with an empty record: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────────────────────┐ \n\+ \ │ toMap {=} : List { mapKey : Text, mapValue : Natural} │ \n\+ \ └─────────────────────────────────────────────────────────────────────┘ \n\+ \ \n"++prettyTypeMessage (CantAccess lazyText0 expr0 expr1) = ErrorMessages {..}+ where+ short = "Not a record or a union"++ hints = []++ long =+ "Explanation: You can only access fields on records or unions, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ { foo = True, bar = \"ABC\" }.foo │ This is valid ... \n\+ \ └─────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────┐ \n\+ \ │ λ(r : { foo : Bool, bar : Text }) → r.foo │ ... and so is this \n\+ \ └───────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ < foo : Bool | bar : Text >.foo │ ... and so is this \n\+ \ └─────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────┐ \n\+ \ │ λ(r : < foo : Bool | bar : Text >) → r.foo │ ... and so is this \n\+ \ └────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot access fields on non-record expressions \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌───────┐ \n\+ \ │ 1.foo │ \n\+ \ └───────┘ \n\+ \ ⇧ \n\+ \ Invalid: Not a record \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to access the field: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... on the following expression which is not a record nor a union type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but is actually an expression of type: \n\+ \ \n\+ \" <> txt2 <> "\n"+ where+ txt0 = insert lazyText0+ txt1 = insert expr0+ txt2 = insert expr1++prettyTypeMessage (CantProject lazyText0 expr0 expr1) = ErrorMessages {..}+ where+ short = "Not a record"++ hints = []++ long =+ "Explanation: You can only project fields on records, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────────────┐ \n\+ \ │ { foo = True, bar = \"ABC\", baz = 1 }.{ foo, bar } │ This is valid ... \n\+ \ └─────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────────────────────────────────────┐ \n\+ \ │ λ(r : { foo : Bool, bar : Text , baz : Natural }) → r.{ foo, bar } │ ... and so is this \n\+ \ └────────────────────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot project fields on non-record expressions \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ 1.{ foo, bar } │ \n\+ \ └────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: Not a record \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You accidentally try to project fields of a union instead of a record, like \n\+ \ this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────────┐ \n\+ \ │ < foo : a | bar : b >.{ foo, bar } │ \n\+ \ └────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ This is a union, not a record \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to access the fields: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... on the following expression which is not a record: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but is actually an expression of type: \n\+ \ \n\+ \" <> txt2 <> "\n"+ where+ txt0 = insert lazyText0+ txt1 = insert expr0+ txt2 = insert expr1++prettyTypeMessage (CantProjectByExpression expr) = ErrorMessages {..}+ where+ short = "Selector is not a record type"++ hints = []++ long =+ "Explanation: You can project by an expression if that expression is a record \n\+ \type: \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ { foo = True }.({ foo : Bool }) │ This is valid ... \n\+ \ └─────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ λ(r : { foo : Bool }) → r.{ foo : Bool } │ ... and so is this \n\+ \ └──────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot project by any other type of expression: \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ { foo = True }.(True) │ \n\+ \ └───────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: Not a record type \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You accidentally try to project by a record value instead of a record type, \n\+ \ like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ let T = { foo : Bool } │ \n\+ \ │ │ \n\+ \ │ let x = { foo = True , bar = 1} │ \n\+ \ │ │ \n\+ \ │ let y = { foo = False, bar = 2} │ \n\+ \ │ │ \n\+ \ │ in x.(y) │ \n\+ \ └─────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ The user might have meant ❰T❱ here \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to project out the following type: \n\+ \ \n\+ \" <> txt <> "\n\+ \ \n\+ \... which is not a record type \n"+ where+ txt = insert expr++prettyTypeMessage (DuplicateProjectionLabel k) = ErrorMessages {..}+ where+ short = "Duplicate projection label: " <> Dhall.Pretty.Internal.prettyLabel k++ hints = []++ long =+ "Explanation: You can only specify a label once when projecting a record's fields\n\+ \by label. For example, this is valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────┐ \n\+ \ │ { x = 1.1, y = 2.4, z = -0.3 }.{ x, y } │ \n\+ \ └─────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but this is not valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────┐ \n\+ \ │ { x = 1.1, y = 2.4, z = -0.3 }.{ y, y } │ \n\+ \ └─────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: the label ❰y❱ appears twice \n\+ \ \n\+ \ \n\+ \You tried to project the following field twice: \n\+ \ \n\+ \" <> txt0 <> "\n"+ where+ txt0 = insert k++prettyTypeMessage (MissingField k expr0) = ErrorMessages {..}+ where+ short = "Missing record field: " <> Dhall.Pretty.Internal.prettyLabel k++ hints = []++ long =+ "Explanation: You can only access fields on records, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ { foo = True, bar = \"ABC\" }.foo │ This is valid ... \n\+ \ └─────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────┐ \n\+ \ │ λ(r : { foo : Bool, bar : Text }) → r.foo │ ... and so is this \n\+ \ └───────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you can only access fields if they are present \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────┐ \n\+ \ │ { foo = True, bar = \"ABC\" }.qux │ \n\+ \ └─────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: the record has no ❰qux❱ field \n\+ \ \n\+ \ \n\+ \You tried to access a field named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... but the field is missing because the record only defines the following \n\+ \fields: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert k+ txt1 = insert expr0++prettyTypeMessage (MissingConstructor k expr0) = ErrorMessages {..}+ where+ short = "Missing constructor: " <> Dhall.Pretty.Internal.prettyLabel k++ hints = []++ long =+ "Explanation: You can access constructors from unions, like this: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────┐ \n\+ \ │ < Foo | Bar >.Foo │ This is valid ... \n\+ \ └───────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you can only access constructors if they match an union alternative of \n\+ \the same name. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────┐ \n\+ \ │ < Foo | Bar >.Baz │ \n\+ \ └───────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: the union has no ❰Baz❱ alternative \n\+ \ \n\+ \ \n\+ \You tried to access a constructor named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... but the constructor is missing because the union only defines the following \n\+ \alternatives: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert k+ txt1 = insert expr0++prettyTypeMessage (ProjectionTypeMismatch k expr0 expr1 expr2 expr3) = ErrorMessages {..}+ where+ short = "Projection type mismatch\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr2 expr3)++ hints = []++ long =+ "Explanation: You can project a subset of fields from a record by specifying the \n\+ \desired type of the final record, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = True }.({ foo : Natural }) │ This is valid \n\+ \ └─────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the expected type for each desired field must match the actual type of \n\+ \the corresponding field in the original record. \n\+ \ \n\+ \For example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ Invalid: The ❰foo❱ field contains ❰1❱, which has type ❰Natural❱...\n\+ \ ⇩ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ { foo = 1, bar = True }.({ foo : Text }) │ \n\+ \ └──────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ ... but we requested that the ❰foo❱ field\n\+ \ must contain a value of type ❰Text❱ \n\+ \ \n\+ \ \n\+ \You tried to project out a field named: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... that should have type: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but that field instead had a value of type: \n\+ \ \n\+ \" <> txt2 <> "\n"+ where+ txt0 = insert k+ txt1 = insert expr0+ txt2 = insert expr1++prettyTypeMessage (AssertionFailed expr0 expr1) = ErrorMessages {..}+ where+ short = "Assertion failed\n"+ <> "\n"+ <> Dhall.Diff.doc (Dhall.Diff.diffNormalized expr0 expr1)++ hints = []++ long =+ "Explanation: You can assert at type-checking time that two terms are equal if \n\+ \they have the same normal form, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ assert : 2 + 2 ≡ 4 │ This is valid \n\+ \ └────────────────────┘ \n\+ \ \n\+ \ \n\+ \... and an assertion still succeeds if the normal forms only differ by renaming \n\+ \bound variables, like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────────────────┐ \n\+ \ │ assert : λ(n : Natural) → n + 0 ≡ λ(m : Natural) → m │ This is also valid\n\+ \ └──────────────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \However, an assertion fails if the normal forms differ in any other way. For \n\+ \example, the following assertion is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ assert : 0 ≡ 1 │ Invalid: ❰0❱ does not equal ❰1❱ \n\+ \ └────────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You might have tried to ❰assert❱ a precondition on a function's input, like \n\+ \ this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────────────────────────────────────┐ \n\+ \ │ λ(n : Natural) → let _ = assert : Natural/isZero n ≡ False in n │ \n\+ \ └──────────────────────────────────────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: This assertion will always fail\n\+ \ \n\+ \ \n\+ \ This will not work. Such an assertion is checking all possible inputs to the \n\+ \ function, before you've even used the function at all. \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You tried to assert that this expression: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... is the same as this other expression: \n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... but they differ\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (NotAnEquivalence expr) = ErrorMessages {..}+ where+ short = "Not an equivalence\n"++ hints = []++ long =+ "Explanation: The type annotation for an ❰assert❱ must evaluate to an equivalence\n\+ \of the form ❰x ≡ y❱, like this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ assert : 2 + 2 ≡ 4 │ This is valid \n\+ \ └────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but any other type is not a valid annotation. For example, the following \n\+ \assertion is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌───────────────┐ \n\+ \ │ assert : True │ Invalid: ❰True❱ is not an equivalence \n\+ \ └───────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You tried to supply an expression of type ❰Bool❱ to the assertion, rather than\n\+ \ two separate expressions to compare, like this: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────┐ \n\+ \ │ assert : Natural/isZero 0 │ Invalid: A boolean expression is not the \n\+ \ └───────────────────────────┘ same thing as a type-level equivalence \n\+ \ \n\+ \ \n\+ \ You have to explicitly compare two expressions, even if that just means \n\+ \ comparing the expression to ❰True❱, like this: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ assert : Natural/isZero 0 ≡ True │ Valid: You can assert that two boolean\n\+ \ └──────────────────────────────────┘ expressions are equivalent \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided the following type annotation for an ❰assert❱: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not an equivalence\n"+ where+ txt0 = insert expr++prettyTypeMessage (IncomparableExpression expr) = ErrorMessages {..}+ where+ short = "Incomparable expression\n"++ hints = []++ long =+ "Explanation: You can use an ❰assert❱ to compare two terms for equivalence, like \n\+ \this: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────┐ \n\+ \ │ assert : 2 + 2 ≡ 4 │ This is valid because ❰2 + 2❱ and ❰4❱ are both terms\n\+ \ └────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot compare expressions, that are not terms, such as types. For \n\+ \example, the following equivalence is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ assert : Natural ≡ Natural │ Invalid: ❰Natural❱ is a type, not a term \n\+ \ └────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \You tried to compare the following expression: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a term\n"+ where+ txt0 = insert expr++prettyTypeMessage (EquivalenceTypeMismatch l _L r _R) = ErrorMessages {..}+ where+ short = "The two sides of the equivalence have different types"++ hints = []++ long =+ "Explanation: You can use ❰≡❱ to compare two terms of the same type for \n\+ \equivalence, like this: \n\+ \ \n\+ \ \n\+ \ ┌───────────┐ \n\+ \ │ 2 + 2 ≡ 4 │ This is valid because ❰2 + 2❱ and ❰4❱ have the same type \n\+ \ └───────────┘ \n\+ \ \n\+ \ \n\+ \... but you cannot compare expressions, that have different types. For example,\n\+ \the following assertion is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────┐ \n\+ \ │ 1 ≡ True │ Invalid: ❰1❱ has type ❰Natural❱, ❰True❱ has type ❰Bool❱ \n\+ \ └──────────┘ \n\+ \ \n\+ \ \n\+ \You tried to compare the following expressions: \n\+ \ \n\+ \" <> insert l <> "\n\+ \ \n\+ \... which has type\n\+ \ \n\+ \" <> insert _L <> "\n\+ \ \n\+ \... and\n\+ \ \n\+ \" <> insert r <> "\n\+ \ \n\+ \... which has type\n\+ \ \n\+ \" <> insert _R <> "\n"++prettyTypeMessage (NotWithARecord expr0 expr1) = ErrorMessages {..}+ where+ short = "❰with❱ only works on records"++ hints = []++ long =+ "Explanation: You can use ❰with❱ to update a record, like this: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────┐ \n\+ \ │ { a = 5 } with b = 10 │ This is valid because ❰{ a = 5}❱ is a record \n\+ \ └────────────────────────┘ \n\+ \ \n\+ \ ┌──────────────────────────────────────────┐ \n\+ \ │ λ(r : { a : Natural }) → r with b = 10 │ This is also valid because \n\+ \ └──────────────────────────────────────────┘ ❰r❱ is a record \n\+ \ \n\+ \ \n\+ \... but you cannot use ❰with❱ to update an expression that is not a record. For\n\+ \example, the following expression is " <> _NOT <> " valid: \n\+ \ \n\+ \ \n\+ \ ┌───────────────┐ \n\+ \ │ 1 with b = 10 │ Invalid: ❰1❱ is not a record \n\+ \ └───────────────┘ \n\+ \ \n\+ \ \n\+ \You tried to update the following expressions: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which has type\n\+ \ \n\+ \" <> txt1 <> "\n\+ \ \n\+ \... which is not a record type\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (CantAnd expr0 expr1) =+ buildBooleanOperator "&&" expr0 expr1++prettyTypeMessage (CantOr expr0 expr1) =+ buildBooleanOperator "||" expr0 expr1++prettyTypeMessage (CantEQ expr0 expr1) =+ buildBooleanOperator "==" expr0 expr1++prettyTypeMessage (CantNE expr0 expr1) =+ buildBooleanOperator "!=" expr0 expr1++prettyTypeMessage (CantInterpolate expr0 expr1) = ErrorMessages {..}+ where+ short = "You can only interpolate ❰Text❱"++ hints = []++ long =+ "Explanation: Text interpolation only works on expressions of type ❰Text❱ \n\+ \ \n\+ \For example, these are all valid uses of string interpolation: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────┐ \n\+ \ │ \"ABC${\"DEF\"}GHI\" │ \n\+ \ └──────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────┐ \n\+ \ │ λ(x : Text) → \"ABC${x}GHI\" │ \n\+ \ └────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────────────────────────────┐ \n\+ \ │ λ(age : Natural) → \"Age: ${Natural/show age}\" │ \n\+ \ └───────────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You might have thought that string interpolation automatically converts the \n\+ \ interpolated value to a ❰Text❱ representation of that value: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────────────────┐ \n\+ \ │ λ(age : Natural) → \"Age: ${age}\" │ \n\+ \ └──────────────────────────────────┘ \n\+ \ ⇧ \n\+ \ Invalid: ❰age❱ has type ❰Natural❱ \n\+ \ \n\+ \ \n\+ \● You might have forgotten to escape a string interpolation that you wanted \n\+ \ Dhall to ignore and pass through: \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ \"echo ${HOME}\" │ \n\+ \ └────────────────┘ \n\+ \ ⇧ \n\+ \ ❰HOME❱ is not in scope and this might have meant to use ❰\\${HOME}❱\n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You interpolated this expression: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which does not have type ❰Text❱ but instead has type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (CantTextAppend expr0 expr1) = ErrorMessages {..}+ where+ short = "❰++❱ only works on ❰Text❱"++ hints = []++ long =+ "Explanation: The ❰++❱ operator expects two arguments that have type ❰Text❱ \n\+ \ \n\+ \For example, this is a valid use of ❰++❱: \n\+ \ \n\+ \ \n\+ \ ┌────────────────┐ \n\+ \ │ \"ABC\" ++ \"DEF\" │ \n\+ \ └────────────────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You might have thought that ❰++❱ was the operator to combine two lists: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────┐ \n\+ \ │ [1, 2, 3] ++ [4, 5, 6] │ Not valid \n\+ \ └────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ... but the list concatenation operator is actually ❰#❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ [1, 2, 3] # [4, 5, 6] │ Valid \n\+ \ └───────────────────────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided this argument: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which does not have type ❰Text❱ but instead has type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (CantListAppend expr0 expr1) = ErrorMessages {..}+ where+ short = "❰#❱ only works on ❰List❱s"++ hints = []++ long =+ "Explanation: The ❰#❱ operator expects two arguments that are both ❰List❱s \n\+ \ \n\+ \For example, this is a valid use of ❰#❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────────┐ \n\+ \ │ [1, 2, 3] # [4, 5, 6] │ \n\+ \ └───────────────────────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided this argument: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which is not a ❰List❱ but instead has type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++prettyTypeMessage (CantAdd expr0 expr1) =+ buildNaturalOperator "+" expr0 expr1++prettyTypeMessage (CantMultiply expr0 expr1) =+ buildNaturalOperator "*" expr0 expr1++prettyTypeMessage OptionalWithTypeMismatch = ErrorMessages {..}+ where+ short = "❰with❱ cannot change the type of an ❰Optional❱ value"+ hints = []+ long =+ "Explanation: The ❰with❱ keyword cannot change the type of a value stored inside \n\+ \of a ❰Some❱ constructor \n\+ \ \n\+ \For example, this is a valid use of ❰with❱: \n\+ \ \n\+ \ \n\+ \ The old value has type ❰Natural❱ \n\+ \ ⇩ \n\+ \ ┌───────────────────┐ \n\+ \ │ Some 1 with ? = 2 │ \n\+ \ └───────────────────┘ \n\+ \ ⇧ \n\+ \ ... which matches the type of the new value, which is also\n\+ \ ❰Natural❱ \n\+ \ \n\+ \ \n\+ \... but the following example is not valid: \n\+ \ \n\+ \ \n\+ \ The old value has type ❰Natural❱ \n\+ \ ⇩ \n\+ \ ┌──────────────────────┐ \n\+ \ │ Some 1 with ? = True │ \n\+ \ └──────────────────────┘ \n\+ \ ⇧ \n\+ \ ... but the new value has type ❰Bool❱, which does not \n\+ \ match \n"++prettyTypeMessage NotALabelPath = ErrorMessages {..}+ where+ short = "Use a label to update a record"+ hints = []+ long =+ "Explanation: The ❰with❱ keyword supports updating records by naming the field(s)\n\+ \to update, but you provided a path component of ❰?❱, which only works on \n\+ \❰Optional❱ values and not records. \n\+ \ \n\+ \For example, these are valid uses of ❰with❱ to update a record: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────┐ \n\+ \ │ { x = 1 } with x = 2 │ \n\+ \ └──────────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────────────┐ \n\+ \ │ { x = { y = 1 } } with x.y = 2 │ \n\+ \ └────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the following example is not valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────┐ \n\+ \ │ { x = 1 } with ? = 2 │ \n\+ \ └──────────────────────┘ \n\+ \ ⇧ \n\+ \ This path component is reserved for updating ❰Optional❱ \n\+ \ values and not records \n\+ \ \n\+ \Note that you can update a field named ❰?❱ if you escape the path component, \n\+ \though: \n\+ \ \n\+ \ \n\+ \ ┌────────────────────────┐ \n\+ \ │ { ? = 1 } with `?` = 2 │ \n\+ \ └────────────────────────┘ \n"++prettyTypeMessage (NotAQuestionPath k) = ErrorMessages {..}+ where+ short = "Use ❰?❱ to update an ❰Optional❱ value"+ hints = []+ long =+ "Explanation: The ❰with❱ keyword supports updating ❰Optional❱ values using a path\n\+ \component of ❰?❱, but you provided a path component other than ❰?❱. \n\+ \ \n\+ \For example, these are valid uses of ❰with❱ to update an ❰Optional❱ value: \n\+ \ \n\+ \ \n\+ \ ┌───────────────────┐ \n\+ \ │ Some 1 with ? = 2 │ \n\+ \ └───────────────────┘ \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────┐ \n\+ \ │ { x = Some 1 } with x.? = 2 │ \n\+ \ └─────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \... but the following example is not valid: \n\+ \ \n\+ \ \n\+ \ ┌──────────────────────┐ \n\+ \ │ Some 1 with x = True │ \n\+ \ └──────────────────────┘ \n\+ \ ⇧ \n\+ \ This path component should have been ❰?❱ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided this path component: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which perhaps should have been ❰?❱. \n"+ where+ txt0 = insert k++prettyTypeMessage ShowConstructorNotOnUnion = ErrorMessages {..}+ where+ short = "ShowConstructorNotOnUnion"+ hints = []+ long = ""++buildBooleanOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages+buildBooleanOperator operator expr0 expr1 = ErrorMessages {..}+ where+ short = "❰" <> txt2 <> "❱ only works on ❰Bool❱s"++ hints = []++ long =+ "Explanation: The ❰" <> txt2 <> "❱ operator expects two arguments that have type ❰Bool❱\n\+ \ \n\+ \For example, this is a valid use of ❰" <> txt2 <> "❱: \n\+ \ \n\+ \ \n\+ \ ┌───────────────┐ \n\+ \ │ True " <> txt2 <> " False │ \n\+ \ └───────────────┘ \n\+ \ \n\+ \ \n\+ \You provided this argument: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which does not have type ❰Bool❱ but instead has type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++ txt2 = pretty operator++buildNaturalOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages+buildNaturalOperator operator expr0 expr1 = ErrorMessages {..}+ where+ short = "❰" <> txt2 <> "❱ only works on ❰Natural❱s"++ hints = []++ long =+ "Explanation: The ❰" <> txt2 <> "❱ operator expects two arguments that have type ❰Natural❱\n\+ \ \n\+ \For example, this is a valid use of ❰" <> txt2 <> "❱: \n\+ \ \n\+ \ \n\+ \ ┌───────┐ \n\+ \ │ 3 " <> txt2 <> " 5 │ \n\+ \ └───────┘ \n\+ \ \n\+ \ \n\+ \Some common reasons why you might get this error: \n\+ \ \n\+ \● You might have tried to use an ❰Integer❱, which is " <> _NOT <> " allowed: \n\+ \ \n\+ \ \n\+ \ ┌─────────────────────────────────────────┐ \n\+ \ │ λ(x : Integer) → λ(y : Integer) → x " <> txt2 <> " y │ Not valid \n\+ \ └─────────────────────────────────────────┘ \n\+ \ \n\+ \ \n\+ \ You can only use ❰Natural❱ numbers \n\+ \ \n\+ \ \n\+ \● You might have mistakenly used an ❰Integer❱ literal, which is " <> _NOT <> " allowed:\n\+ \ \n\+ \ \n\+ \ ┌─────────┐ \n\+ \ │ +2 " <> txt2 <> " +2 │ Not valid \n\+ \ └─────────┘ \n\+ \ \n\+ \ \n\+ \ You need to remove the leading ❰+❱ to transform them into ❰Natural❱ literals, \n\+ \ like this: \n\+ \ \n\+ \ \n\+ \ ┌───────┐ \n\+ \ │ 2 " <> txt2 <> " 2 │ Valid \n\+ \ └───────┘ \n\+ \ \n\+ \ \n\+ \────────────────────────────────────────────────────────────────────────────────\n\+ \ \n\+ \You provided this argument: \n\+ \ \n\+ \" <> txt0 <> "\n\+ \ \n\+ \... which does not have type ❰Natural❱ but instead has type: \n\+ \ \n\+ \" <> txt1 <> "\n"+ where+ txt0 = insert expr0+ txt1 = insert expr1++ txt2 = pretty operator++-- | A structured type error that includes context+data TypeError s a = TypeError+ { context :: Context (Expr s a)+ , current :: Expr s a+ , typeMessage :: TypeMessage s a+ }++instance (Eq a, Pretty s, Pretty a) => Show (TypeError s a) where+ show = Pretty.renderString . Dhall.Pretty.layout . prettyTypeError++instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (TypeError s a)++instance (Eq a, Pretty s, Pretty a) => Pretty (TypeError s a) where+ pretty = Pretty.unAnnotate . prettyTypeError++prettyTypeError :: (Eq a, Pretty s, Pretty a) => TypeError s a -> Doc Ann+prettyTypeError (TypeError _ expr msg) =+ ( "\n"+ <> shortTypeMessage msg <> "\n"+ <> source+ )+ where+ source = case expr of+ Note s _ -> pretty s+ _ -> mempty++{-| Wrap a type error in this exception type to censor source code and+ `Dhall.Syntax.Text` literals from the error message+-}+data Censored+ = CensoredDetailed (DetailedTypeError Src X)+ | Censored (TypeError Src X)++instance Show Censored where+ show = Pretty.renderString . Dhall.Pretty.layout . Pretty.pretty++instance Exception Censored++instance Pretty Censored where+ pretty (CensoredDetailed (DetailedTypeError e)) =+ pretty (DetailedTypeError (censorTypeError e))+ pretty (Censored e) = pretty (censorTypeError e)++censorTypeError :: TypeError Src a -> TypeError Src a+censorTypeError (TypeError c e m) = TypeError c' e' m'+ where+ c' = fmap Dhall.Core.censorExpression c++ e' = Dhall.Core.censorExpression e++ m' = over messageExpressions Dhall.Core.censorExpression m++-- | @Traversal@ that traverses every `Expr` in a `TypeMessage`+messageExpressions+ :: Applicative f+ => (Expr s a -> f (Expr t b)) -> TypeMessage s a -> f (TypeMessage t b)+messageExpressions f m = case m of+ UnboundVariable a ->+ UnboundVariable <$> pure a+ InvalidInputType a ->+ InvalidInputType <$> f a+ InvalidOutputType a ->+ InvalidOutputType <$> f a+ NotAFunction a b ->+ NotAFunction <$> f a <*> f b+ TypeMismatch a b c d ->+ TypeMismatch <$> f a <*> f b <*> f c <*> f d+ AnnotMismatch a b c ->+ AnnotMismatch <$> f a <*> f b <*> f c+ Untyped ->+ pure Untyped+ MissingListType ->+ pure MissingListType+ MismatchedListElements a b c d ->+ MismatchedListElements <$> pure a <*> f b <*> f c <*> f d+ InvalidListType a ->+ InvalidListType <$> f a+ ListLitInvariant ->+ pure ListLitInvariant+ InvalidSome a b c ->+ InvalidSome <$> f a <*> f b <*> f c+ InvalidPredicate a b ->+ InvalidPredicate <$> f a <*> f b+ IfBranchMismatch a b c d ->+ IfBranchMismatch <$> f a <*> f b <*> f c <*> f d+ InvalidFieldType a b ->+ InvalidFieldType <$> pure a <*> f b+ InvalidAlternativeType a b ->+ InvalidAlternativeType <$> pure a <*> f b+ ListAppendMismatch a b ->+ ListAppendMismatch <$> f a <*> f b+ InvalidDuplicateField a b c ->+ InvalidDuplicateField a <$> f b <*> f c+ MustCombineARecord a b c ->+ MustCombineARecord <$> pure a <*> f b <*> f c+ InvalidRecordCompletion a l ->+ InvalidRecordCompletion a <$> f l+ CompletionSchemaMustBeARecord l r ->+ CompletionSchemaMustBeARecord <$> f l <*> f r+ CombineTypesRequiresRecordType a b ->+ CombineTypesRequiresRecordType <$> f a <*> f b+ DuplicateFieldCannotBeMerged a ->+ pure (DuplicateFieldCannotBeMerged a)+ FieldCollision a ->+ pure (FieldCollision a)+ FieldTypeCollision a ->+ pure (FieldTypeCollision a)+ MustMergeARecord a b ->+ MustMergeARecord <$> f a <*> f b+ MustMergeUnionOrOptional a b ->+ MustMergeUnionOrOptional <$> f a <*> f b+ MustMapARecord a b ->+ MustMapARecord <$> f a <*> f b+ InvalidToMapRecordKind a b ->+ InvalidToMapRecordKind <$> f a <*> f b+ HeterogenousRecordToMap a b c ->+ HeterogenousRecordToMap <$> f a <*> f b <*> f c+ InvalidToMapType a ->+ InvalidToMapType <$> f a+ MapTypeMismatch a b ->+ MapTypeMismatch <$> f a <*> f b+ MissingToMapType ->+ pure MissingToMapType+ UnusedHandler a ->+ UnusedHandler <$> pure a+ MissingHandler e a ->+ MissingHandler <$> pure e <*> pure a+ HandlerInputTypeMismatch a b c ->+ HandlerInputTypeMismatch <$> pure a <*> f b <*> f c+ DisallowedHandlerType a b c d ->+ DisallowedHandlerType <$> pure a <*> f b <*> f c <*> pure d+ HandlerOutputTypeMismatch a b c d ->+ HandlerOutputTypeMismatch <$> pure a <*> f b <*> pure c <*> f d+ MissingMergeType ->+ pure MissingMergeType+ HandlerNotAFunction a b ->+ HandlerNotAFunction <$> pure a <*> f b+ CantAccess a b c ->+ CantAccess <$> pure a <*> f b <*> f c+ CantProject a b c ->+ CantProject <$> pure a <*> f b <*> f c+ CantProjectByExpression a ->+ CantProjectByExpression <$> f a+ DuplicateProjectionLabel a ->+ pure (DuplicateProjectionLabel a)+ MissingField a b ->+ MissingField <$> pure a <*> f b+ MissingConstructor a b ->+ MissingConstructor <$> pure a <*> f b+ ProjectionTypeMismatch a b c d e ->+ ProjectionTypeMismatch <$> pure a <*> f b <*> f c <*> f d <*> f e+ AssertionFailed a b ->+ AssertionFailed <$> f a <*> f b+ NotAnEquivalence a ->+ NotAnEquivalence <$> f a+ IncomparableExpression a ->+ IncomparableExpression <$> f a+ EquivalenceTypeMismatch a b c d ->+ EquivalenceTypeMismatch <$> f a <*> f b <*> f c <*> f d+ NotWithARecord a b ->+ NotWithARecord <$> f a <*> f b+ CantAnd a b ->+ CantAnd <$> f a <*> f b+ CantOr a b ->+ CantOr <$> f a <*> f b+ CantEQ a b ->+ CantEQ <$> f a <*> f b+ CantNE a b ->+ CantNE <$> f a <*> f b+ CantInterpolate a b ->+ CantInterpolate <$> f a <*> f b+ CantTextAppend a b ->+ CantTextAppend <$> f a <*> f b+ CantListAppend a b ->+ CantListAppend <$> f a <*> f b+ CantAdd a b ->+ CantAdd <$> f a <*> f b+ CantMultiply a b ->+ CantMultiply <$> f a <*> f b+ OptionalWithTypeMismatch ->+ pure OptionalWithTypeMismatch+ NotALabelPath ->+ pure NotALabelPath+ NotAQuestionPath k ->+ pure (NotAQuestionPath k)+ ShowConstructorNotOnUnion ->+ pure ShowConstructorNotOnUnion++{-| Newtype used to wrap error messages so that they render with a more+ detailed explanation of what went wrong+-}+newtype DetailedTypeError s a = DetailedTypeError (TypeError s a)+ deriving (Typeable)++instance (Eq a, Pretty s, Pretty a) => Show (DetailedTypeError s a) where+ show = Pretty.renderString . Dhall.Pretty.layout . prettyDetailedTypeError++instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (DetailedTypeError s a)++instance (Eq a, Pretty s, Pretty a) => Pretty (DetailedTypeError s a) where+ pretty = Pretty.unAnnotate . prettyDetailedTypeError++prettyDetailedTypeError :: (Eq a, Pretty s, Pretty a) => DetailedTypeError s a -> Doc Ann+prettyDetailedTypeError (DetailedTypeError (TypeError ctx expr msg)) =+ ( "\n"+ <> ( if null (Dhall.Context.toList ctx)+ then ""+ else prettyContext ctx <> "\n\n"+ )+ <> longTypeMessage msg <> "\n"+ <> "────────────────────────────────────────────────────────────────────────────────\n"+ <> "\n"+ <> source+ )+ where+ prettyKV (key, val) =+ Dhall.Util.snipDoc+ (Dhall.Pretty.Internal.prettyLabel key <> " : " <> Dhall.Pretty.prettyExpr val)++ prettyContext =+ Pretty.vsep+ . map prettyKV+ . reverse+ . Dhall.Context.toList++ source = case expr of+ Note s _ -> pretty s+ _ -> mempty++{-| This function verifies that a custom context is well-formed so that+ type-checking will not loop++ Note that `typeWith` already calls `checkContext` for you on the `Context`+ that you supply+-}+checkContext :: Context (Expr s X) -> Either (TypeError s X) ()+checkContext context =+ case Dhall.Context.match context of+ Nothing ->+ return ()+ Just (x, v, context') -> do+ let shiftedV = Dhall.Core.shift (-1) (V x 0) v+ let shiftedContext = fmap (Dhall.Core.shift (-1) (V x 0)) context'+ _ <- typeWith shiftedContext shiftedV+ return ()++toPath :: (Functor list, Foldable list) => list Text -> Text+toPath ks =+ Text.intercalate "."+ (Foldable.toList (fmap (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome) ks))++duplicateElement :: Ord a => [a] -> Maybe a+duplicateElement = go Data.Set.empty+ where+ go _ [] = Nothing+ go found (x : xs)+ | Data.Set.member x found = Just x+ | otherwise = go (Data.Set.insert x found) xs
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Dhall.URL where++import Data.Text (Text)++import Dhall.Syntax (Directory (..), File (..), Scheme (..), URL (..))++renderComponent :: Text -> Text+renderComponent component = "/" <> component++renderQuery :: Text -> Text+renderQuery query = "?" <> query++renderURL :: URL -> Text+renderURL url =+ schemeText+ <> authority+ <> pathText+ <> queryText+ where+ URL {..} = url++ File {..} = path++ Directory {..} = directory++ schemeText = case scheme of+ HTTP -> "http://"+ HTTPS -> "https://"++ pathText =+ foldMap renderComponent (reverse components)+ <> renderComponent file++ queryText = foldMap renderQuery query
@@ -1,4 +1,6 @@+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} -- | Shared utility functions @@ -7,18 +9,47 @@ , snipDoc , insert , _ERROR+ , _WARNING+ , printWarning+ , Censor(..)+ , Input(..)+ , Transitivity(..)+ , OutputMode(..)+ , Output(..)+ , getExpression+ , getExpressionAndHeader+ , getExpressionAndHeaderFromStdinText+ , Header(..)+ , CheckFailed(..)+ , MultipleCheckFailed(..)+ , handleMultipleChecksFailed+ , renderExpression ) where -import Data.Monoid ((<>))-import Data.String (IsString)-import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, Pretty)-import Dhall.Pretty (Ann)+import Control.Exception (Exception (..))+import Control.Monad.IO.Class (MonadIO (..))+import Data.Bifunctor (first)+import Data.Either (lefts)+import Data.Foldable (toList)+import Data.List.NonEmpty (NonEmpty (..))+import Data.String (IsString)+import Data.Text (Text)+import Dhall.Parser (Header (..), ParseError)+import Dhall.Pretty (Ann, CharacterSet)+import Dhall.Src (Src)+import Dhall.Syntax (Expr, Import)+import Prettyprinter (Doc, Pretty) +import qualified Control.Exception import qualified Data.Text-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty+import qualified Data.Text.IO+import qualified Dhall.Parser import qualified Dhall.Pretty+import qualified Prettyprinter as Pretty+import qualified Prettyprinter.Render.Terminal as Pretty.Terminal+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified System.Console.ANSI as ANSI+import qualified System.IO as IO -- | Utility function to cut out the interior of a large text block snip :: Text -> Text@@ -50,7 +81,7 @@ preview = Data.Text.unlines header- <> separator <> "\n"+ <> Data.Text.take 80 separator <> "\n" <> Data.Text.unlines footer {-| Like `snip`, but for `Doc`s@@ -61,11 +92,11 @@ snipDoc :: Doc Ann -> Doc a snipDoc doc = Pretty.align (Pretty.pretty (snip text)) where- stream = Pretty.layoutSmart Dhall.Pretty.layoutOpts doc+ stream = Dhall.Pretty.layout doc ansiStream = fmap Dhall.Pretty.annToAnsiStyle stream - text = Pretty.renderStrict ansiStream+ text = Pretty.Terminal.renderStrict ansiStream takeEnd :: Int -> [a] -> [a] takeEnd n l = go (drop n l) l@@ -81,3 +112,180 @@ -- | Prefix used for error messages _ERROR :: IsString string => string _ERROR = "\ESC[1;31mError\ESC[0m"++-- | Prefix used for error messages+_WARNING :: IsString string => string+_WARNING = "\ESC[1;33mWarning\ESC[0m"++-- | Output a warning message on stderr.+printWarning :: (MonadIO m) => String -> m ()+printWarning message = do+ let warning =+ "\n"+ <> _WARNING+ <> ": "+ <> message++ liftIO $ IO.hPutStrLn IO.stderr warning++get+ :: (String -> Text -> Either ParseError a)+ -> Censor+ -> InputOrTextFromStdin+ -> IO a+get parser censor input = do+ inText <-+ case input of+ Input_ (InputFile file) -> Data.Text.IO.readFile file+ Input_ StandardInput -> Data.Text.IO.getContents+ StdinText _ text -> pure text++ let name =+ case input of+ Input_ (InputFile file) -> file+ Input_ StandardInput -> "(input)"+ StdinText inputName _ -> inputName++ let result = parser name inText++ let censoredResult =+ case censor of+ NoCensor -> result+ Censor -> first Dhall.Parser.censor result++ throws censoredResult++{-| Convenience utility for converting `Either`-based exceptions to `IO`-based+ exceptions+-}+throws :: (Exception e, MonadIO io) => Either e a -> io a+throws (Left e) = liftIO (Control.Exception.throwIO e)+throws (Right r) = return r++-- | Set to `Censor` if you want to censor error text that might include secrets+data Censor = NoCensor | Censor++-- | Path to input+data Input = StandardInput | InputFile FilePath deriving (Eq)++-- | Path to input or raw input text, necessary since we can't read STDIN twice+data InputOrTextFromStdin+ = Input_ Input+ | StdinText String Text+ -- ^ @StdinText name text@ where name is a user-friendly name describing the+ -- input expression, used in parsing error messages++{-| Specifies whether or not an input's transitive dependencies should also be+ processed. Transitive dependencies are restricted to relative file imports.+-}+data Transitivity+ = NonTransitive+ -- ^ Do not process transitive dependencies+ | Transitive+ -- ^ Process transitive dependencies in the same way++-- | Path to output+data Output = StandardOutput | OutputFile FilePath++{-| Some command-line subcommands can either `Write` their input or `Check`+ that the input has already been modified. This type is shared between them+ to record that choice.+-}+data OutputMode = Write | Check++-- | A check failure corresponding to a single input.+-- This type is intended to be used with 'MultipleCheckFailed' for error+-- reporting.+newtype CheckFailed = CheckFailed { input :: Input }++-- | Exception thrown when the @--check@ flag to a command-line subcommand fails+data MultipleCheckFailed = MultipleCheckFailed+ { command :: Text+ , modified :: Text+ , inputs :: NonEmpty Input+ }++instance Exception MultipleCheckFailed++instance Show MultipleCheckFailed where+ show MultipleCheckFailed{..} =+ _ERROR <> ": ❰dhall " <> command_ <> " --check❱ failed on:\n\+ \\n" <> files <>+ "\n\+ \You ran ❰dhall " <> command_ <> " --check❱, but the input appears to have not\n\+ \been " <> modified_ <> " before, or was changed since the last time the input\n\+ \was " <> modified_ <> ".\n"+ where+ modified_ = Data.Text.unpack modified++ command_ = Data.Text.unpack command++ files = unlines . map format $ toList inputs++ format input = case input of+ StandardInput -> "↳ (stdin)"+ InputFile file -> "↳ " <> file++-- | Run IO for multiple inputs, then collate all the check failures before+-- throwing if there was any failure+handleMultipleChecksFailed+ :: (Foldable t, Traversable t)+ => Text+ -> Text+ -> (a -> IO (Either CheckFailed ()))+ -> t a+ -> IO ()+handleMultipleChecksFailed command modified f xs = post =<< mapM f xs+ where+ post results =+ case lefts (toList results) of+ [] -> pure ()+ cf:cfs -> Control.Exception.throwIO $ MultipleCheckFailed+ { command+ , modified+ , inputs = fmap input (cf:|cfs)+ }++-- | Convenient utility for retrieving an expression+getExpression :: Censor -> Input -> IO (Expr Src Import)+getExpression censor = get Dhall.Parser.exprFromText censor . Input_++-- | Convenient utility for retrieving an expression along with its header+getExpressionAndHeader :: Censor -> Input -> IO (Header, Expr Src Import)+getExpressionAndHeader censor =+ get Dhall.Parser.exprAndHeaderFromText censor . Input_++-- | Convenient utility for retrieving an expression along with its header from+-- | text already read from STDIN (so it's not re-read)+getExpressionAndHeaderFromStdinText+ :: Censor -> String -> Text -> IO (Header, Expr Src Import)+getExpressionAndHeaderFromStdinText censor inputName =+ get Dhall.Parser.exprAndHeaderFromText censor . StdinText inputName++{-| Convenient utility to output an expression either to a file+ or to stdout.+-}+renderExpression :: Pretty a => CharacterSet -> Bool -> Maybe FilePath -> Expr Src a -> IO ()+renderExpression characterSet plain output expression = do+ let document = Dhall.Pretty.prettyCharacterSet characterSet expression++ let stream = Dhall.Pretty.layout document++ case output of+ Nothing -> do+ supportsANSI <- ANSI.hSupportsANSI IO.stdout++ let ansiStream =+ if supportsANSI && not plain+ then fmap Dhall.Pretty.annToAnsiStyle stream+ else Pretty.unAnnotateS stream++ Pretty.Terminal.renderIO IO.stdout ansiStream++ Data.Text.IO.putStrLn ""++ Just file_ ->+ IO.withFile file_ IO.WriteMode $ \h -> do+ Pretty.Text.renderIO h stream++ Data.Text.IO.hPutStrLn h ""
@@ -0,0 +1,17 @@+{-| Utilities for getting the current version of the Haskell implementation of+ Dhall+-}+module Dhall.Version ( dhallVersion+ , dhallVersionString+ ) where++import qualified Data.Version as V+import qualified Paths_dhall as P++-- | The current `V.Version` of the Haskell implementation+dhallVersion :: V.Version+dhallVersion = P.version++-- | The current version `String` for the Haskell implementation+dhallVersionString :: String+dhallVersionString = V.showVersion dhallVersion
@@ -1,101 +1,178 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Dhall.Test.Dhall where -import Control.Exception (SomeException, try)-import Data.Text (Text)-import Dhall (Inject, Interpret)-import Dhall.Core (Expr(..))-import GHC.Generics (Generic)-import Numeric.Natural (Natural)+import Control.Exception (SomeException, throwIO, try)+import Data.Either.Validation (validationToEither)+import Data.Fix (Fix (..))+import Data.Functor.Classes (Eq1 (..), Show1 (..))+import Data.List.NonEmpty (NonEmpty (..))+import Data.Maybe (isJust)+import Data.Scientific (Scientific)+import Data.Sequence (Seq)+import Data.Text (Text)+import Data.Vector (Vector)+import Data.Void (Void)+import Dhall (FromDhall, ToDhall)+import Dhall.Core (Expr (..))+import GHC.Generics (Generic, Rep)+import Numeric.Natural (Natural)+import System.Timeout (timeout) import Test.Tasty import Test.Tasty.HUnit +import qualified Data.Functor.Classes as Classes+import qualified Data.Text.Lazy import qualified Dhall import qualified Dhall.Core import qualified Dhall.Import import qualified Dhall.Map import qualified Dhall.Parser +data ExprF expr+ = LitF Natural+ | AddF expr expr+ | MulF expr expr+ deriving (Eq, Functor, Generic, FromDhall, ToDhall, Show)++instance Eq1 ExprF where+ liftEq _ (LitF aL) (LitF aR) = aL == aR+ liftEq eq (AddF aL bL) (AddF aR bR) = (aL `eq` aR) && (bL `eq` bR)+ liftEq eq (MulF aL bL) (MulF aR bR) = (aL `eq` aR) && (bL `eq` bR)+ liftEq _ _ _ = False++instance Show1 ExprF where+ liftShowsPrec _ _ d (LitF a) = showsPrec d a+ liftShowsPrec sp _ d (AddF a b) = Classes.showsBinaryWith sp sp "AddF" d a b+ liftShowsPrec sp _ d (MulF a b) = Classes.showsBinaryWith sp sp "MulF" d a b+ tests :: TestTree tests = testGroup "Input" [ shouldShowDetailedTypeError- , shouldHandleBothUnionLiterals+ , shouldHandleUnionLiteral+ , shouldHaveWorkingRecursiveFromDhall , shouldHaveWorkingGenericAuto , shouldHandleUnionsCorrectly , shouldTreatAConstructorStoringUnitAsEmptyAlternative+ , shouldConvertDhallToHaskellCorrectly+ , shouldConvertHaskellToDhallCorrectly+ , shouldShowCorrectErrorForInvalidDecoderInUnion ] data MyType = MyType { foo :: String , bar :: Natural } -wrongDhallType :: Dhall.Type MyType -wrongDhallType = Dhall.Type { .. }- where expected =+wrongDhallType :: Dhall.Decoder MyType+wrongDhallType = Dhall.Decoder {..}+ where expected = pure $ Dhall.Core.Record ( Dhall.Map.fromList- [ ( "bar", Dhall.Core.Natural)- , ( "foo", Dhall.Core.Text )+ [ ( "bar", Dhall.Core.makeRecordField Dhall.Core.Natural)+ , ( "foo", Dhall.Core.makeRecordField Dhall.Core.Text ) ] )- extract _ = Nothing+ extract expr = Dhall.typeError expected expr shouldShowDetailedTypeError :: TestTree shouldShowDetailedTypeError = testCase "detailed TypeError" $ do inputEx :: Either SomeException MyType <-- try ( Dhall.input wrongDhallType "{ bar = 0, foo = \"foo\" }") + try ( Dhall.input wrongDhallType "{ bar = 0, foo = \"foo\" }") let expectedMsg =- "\ESC[1;31mError\ESC[0m: Invalid Dhall.Type \n\+ "\ESC[1;31mError\ESC[0m: Invalid Dhall.Decoder \n\ \ \n\- \Every Type must provide an extract function that succeeds if an expression \n\- \matches the expected type. You provided a Type that disobeys this contract \n\+ \Every Decoder must provide an extract function that does not fail with a type \n\+ \error if an expression matches the expected type. You provided a Decoder that \n\+ \disobeys this contract \n\ \ \n\- \The Type provided has the expected dhall type: \n\+ \The Decoder provided has the expected dhall type: \n\ \ \n\ \↳ { bar : Natural, foo : Text }\n\ \ \n\- \and it couldn't extract a value from the well-typed expression: \n\+ \and it threw a type error during extraction from the well-typed expression: \n\ \ \n\ \↳ { bar = 0, foo = \"foo\" }\n\ \ \n" let assertMsg = "The exception message did not match the expected output"- + case inputEx of Left ex -> assertEqual assertMsg expectedMsg (show ex)- Right _ -> fail "The extraction using a wrong type succeded"+ Right _ -> fail "The extraction using a wrong type succeeded" -- https://github.com/dhall-lang/dhall-haskell/issues/915-shouldHandleBothUnionLiterals :: TestTree-shouldHandleBothUnionLiterals = testCase "Marshal union literals" $ do- let example :: Dhall.Type Bool+shouldHandleUnionLiteral :: TestTree+shouldHandleUnionLiteral = testCase "Marshal union literals" $ do+ let example :: Dhall.Decoder Bool example = Dhall.union (Dhall.constructor "Test" Dhall.bool) _ <- Dhall.input example "< Test : Bool >.Test True"- _ <- Dhall.input example "< Test = True >" return () shouldTreatAConstructorStoringUnitAsEmptyAlternative :: TestTree shouldTreatAConstructorStoringUnitAsEmptyAlternative = testCase "Handle unit constructors" $ do- let exampleType :: Dhall.Type ()+ let exampleType :: Dhall.Decoder () exampleType = Dhall.union (Dhall.constructor "A" Dhall.unit) () <- Dhall.input exampleType "< A >.A" - let exampleInputType :: Dhall.InputType ()- exampleInputType = Dhall.inputUnion (Dhall.inputConstructor "A")+ let exampleEncoder :: Dhall.Encoder ()+ exampleEncoder = Dhall.unionEncoder (Dhall.encodeConstructor "A") - Dhall.embed exampleInputType () @=? Field (Union (Dhall.Map.singleton "A" Nothing)) "A"+ let a = Dhall.Core.makeFieldSelection "A"+ Dhall.embed exampleEncoder () @=? Field (Union (Dhall.Map.singleton "A" Nothing)) a +newtype RecursiveType a = RecursiveType (RecursiveType a)+ deriving Generic++instance FromDhall (RecursiveType a)++shouldHaveWorkingRecursiveFromDhall :: TestTree+shouldHaveWorkingRecursiveFromDhall = testGroup "recursive FromDhall instance"+ [ testCase "works for a recursive expression" $ do+ actual <- Dhall.input Dhall.auto "./tests/recursive/expr0.dhall"++ expected @=? actual+ , testCase "roundtrips (one-way)" $ do+ let expr = Dhall.embed Dhall.inject expected+ actual <- either throwIO pure . validationToEither . Dhall.extract Dhall.auto $ expr++ expected @=? actual+ , testCase "passes a shadowing sanity check" $ do+ actual <- Dhall.input Dhall.auto "./tests/recursive/expr1.dhall"++ expected @=? actual+ , testCase "terminate if type is recursive (monomorphic)" $ do+ actual <- timeout (1 * 1000000) $ do+ !typ <- return $ Dhall.expected (Dhall.auto :: Dhall.Decoder (RecursiveType Void))+ return typ+ assertBool "Does not terminate!" $ isJust actual+ , testCase "terminate if type is recursive (polymorphic)" $ do+ actual <- timeout (1 * 1000000) $ do+ !typ <- return $ Dhall.expected (Dhall.auto :: Dhall.Decoder (RecursiveType a))+ return typ+ assertBool "Does not terminate!" $ isJust actual+ ]+ where+ expected =+ Fix+ (AddF+ (Fix (MulF (Fix (LitF 3)) (Fix (LitF 7))))+ (Fix (AddF (Fix (LitF 1)) (Fix (LitF 2))))+ )+ data CompilerFlavor3 = GHC3 | GHCJS3 | Helium3 deriving (Generic, Show, Eq)@@ -117,85 +194,305 @@ ] data NonEmptyUnion = N0 Bool | N1 Natural | N2 Text- deriving (Eq, Generic, Inject, Interpret, Show)+ deriving (Eq, Generic, ToDhall, FromDhall, Show) data Enum = E0 | E1 | E2- deriving (Eq, Generic, Inject, Interpret, Show)+ deriving (Eq, Generic, ToDhall, FromDhall, Show) -data Mixed = M0 Bool | M1 | M2 ()- deriving (Eq, Generic, Inject, Interpret, Show)+data Records+ = R0 {}+ | R1 { a :: () }+ | R2 { x :: Double }+ | R3 { a :: (), b :: () }+ | R4 { x :: Double, y :: Double }+ deriving (Eq, Generic, ToDhall, FromDhall, Show) -deriving instance Interpret ()+data Products = P0 | P1 () | P2 Double | P3 () () | P4 Double Double+ deriving (Eq, Generic, ToDhall, FromDhall, Show) shouldHandleUnionsCorrectly :: TestTree shouldHandleUnionsCorrectly = testGroup "Handle union literals" [ "λ(x : < N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >) → x"- `shouldPassThrough` [ N0 True, N1 5, N2 "ABC" ]+ `shouldPassThroughWrapped` [ N0 True, N1 5, N2 "ABC" ] , "λ(x : < E0 | E1 | E2 >) → x"- `shouldPassThrough` [ E0, E1, E2 ]- , "λ(x : < M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >) → x"- `shouldPassThrough` [ M0 True, M1, M2 () ]+ `shouldPassThroughWrapped` [ E0, E1, E2 ]+ , "λ(x : < R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >) → x"+ `shouldPassThroughWrapped` [ R0 {}, R1 { a = () }, R2 { x = 1.0 }, R3 { a = (), b = () }, R4 { x = 1.0, y = 2.0 } ]+ , "λ(x : < P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >) → x"+ `shouldPassThroughWrapped` [ P0 , P1 (), P2 1.0, P3 () (), P4 1.0 2.0 ] + , "λ(x : < N0 : Bool | N1 : Natural | N2 : Text >) → x"+ `shouldPassThroughSmart` [ N0 True, N1 5, N2 "ABC" ]+ , "λ(x : < R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >) → x"+ `shouldPassThroughSmart` [ R0 {}, R1 { a = () }, R2 { x = 1.0 }, R3 { a = (), b = () }, R4 { x = 1.0, y = 2.0 } ]+ , "λ(x : < P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >) → x"+ `shouldPassThroughSmart` [ P0 , P1 (), P2 1.0, P3 () (), P4 1.0 2.0 ]+ , "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N0 { _1 = True }"- `shouldMarshalInto` N0 True+ `shouldMarshalIntoWrapped` N0 True , "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N1 { _1 = 5 }"- `shouldMarshalInto` N1 5+ `shouldMarshalIntoWrapped` N1 5 , "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N2 { _1 = \"ABC\" }"- `shouldMarshalInto` N2 "ABC" - , "< N0 = { _1 = True } | N1 : { _1 : Natural } | N2 : { _1 : Text } >"- `shouldMarshalInto` N0 True- , "< N0 : { _1 : Bool } | N1 = { _1 = 5 } | N2 : { _1 : Text } >"- `shouldMarshalInto` N1 5- , "< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 = { _1 = \"ABC\" } >"- `shouldMarshalInto` N2 "ABC"+ `shouldMarshalIntoWrapped` N2 "ABC" - , "(< E0 | E1 | E2>).E0" `shouldMarshalInto` E0- , "(< E0 | E1 | E2>).E1" `shouldMarshalInto` E1- , "(< E0 | E1 | E2>).E2" `shouldMarshalInto` E2+ , "(< N0 : Bool | N1 : Natural | N2 : Text >).N0 True"+ `shouldMarshalIntoSmart` N0 True+ , "(< N0 : Bool | N1 : Natural | N2 : Text >).N1 5"+ `shouldMarshalIntoSmart` N1 5+ , "(< N0 : Bool | N1 : Natural | N2 : Text >).N2 \"ABC\""+ `shouldMarshalIntoSmart` N2 "ABC" - , "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M0 { _1 = True }"- `shouldMarshalInto` M0 True- , "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M1"- `shouldMarshalInto` M1- , "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M2 { _1 = {=} }"- `shouldMarshalInto` M2 ()+ , "(< E0 | E1 | E2>).E0" `shouldMarshalIntoWrapped` E0+ , "(< E0 | E1 | E2>).E1" `shouldMarshalIntoWrapped` E1+ , "(< E0 | E1 | E2>).E2" `shouldMarshalIntoWrapped` E2 - , "< M0 = { _1 = True } | M1 | M2 : { _1 : {} } >"- `shouldMarshalInto` M0 True+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R0"+ `shouldMarshalIntoWrapped` R0+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R1 { a = {=} }"+ `shouldMarshalIntoWrapped` R1 { a = () }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R2 { x = 1.0 }"+ `shouldMarshalIntoWrapped` R2 { x = 1.0 }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R3 { a = {=}, b = {=} }"+ `shouldMarshalIntoWrapped` R3 { a = (), b = () }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R4 { x = 1.0, y = 2.0 }"+ `shouldMarshalIntoWrapped` R4 { x = 1.0, y = 2.0 } + , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R0"+ `shouldMarshalIntoSmart` R0+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R1 { a = {=} }"+ `shouldMarshalIntoSmart` R1 { a = () }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R2 { x = 1.0 }"+ `shouldMarshalIntoSmart` R2 { x = 1.0 }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R3 { a = {=}, b = {=} }"+ `shouldMarshalIntoSmart` R3 { a = (), b = () }+ , "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R4 { x = 1.0, y = 2.0 }"+ `shouldMarshalIntoSmart` R4 { x = 1.0, y = 2.0 }++ , "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P0"+ `shouldMarshalIntoWrapped` P0+ , "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P1 { _1 = {=} }"+ `shouldMarshalIntoWrapped` P1 ()+ , "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P2 { _1 = 1.0 }"+ `shouldMarshalIntoWrapped` P2 1.0+ , "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P3 { _1 = {=}, _2 = {=} }"+ `shouldMarshalIntoWrapped` P3 () ()+ , "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P4 { _1 = 1.0, _2 = 2.0 }"+ `shouldMarshalIntoWrapped` P4 1.0 2.0++ , "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P0"+ `shouldMarshalIntoSmart` P0+ , "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P1"+ `shouldMarshalIntoSmart` P1 ()+ , "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P2 1.0"+ `shouldMarshalIntoSmart` P2 1.0+ , "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P3 { _1 = {=}, _2 = {=} }"+ `shouldMarshalIntoSmart` P3 () ()+ , "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P4 { _1 = 1.0, _2 = 2.0 }"+ `shouldMarshalIntoSmart` P4 1.0 2.0+ , N0 True- `shouldInjectInto`+ `shouldEmbedAsWrapped` "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N0 { _1 = True }" , N1 5- `shouldInjectInto`+ `shouldEmbedAsWrapped` "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N1 { _1 = 5 }" , N2 "ABC"- `shouldInjectInto`+ `shouldEmbedAsWrapped` "(< N0 : { _1 : Bool } | N1 : { _1 : Natural } | N2 : { _1 : Text } >).N2 { _1 = \"ABC\" }" - , E0 `shouldInjectInto` "< E0 | E1 | E2 >.E0"- , E1 `shouldInjectInto` "< E0 | E1 | E2 >.E1"- , E2 `shouldInjectInto` "< E0 | E1 | E2 >.E2"+ , N0 True+ `shouldEmbedAsSmart`+ "(< N0 : Bool | N1 : Natural | N2 : Text >).N0 True"+ , N1 5+ `shouldEmbedAsSmart`+ "(< N0 : Bool | N1 : Natural | N2 : Text >).N1 5"+ , N2 "ABC"+ `shouldEmbedAsSmart`+ "(< N0 : Bool | N1 : Natural | N2 : Text >).N2 \"ABC\"" - , M0 True `shouldInjectInto` "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M0 { _1 = True }"- , M1 `shouldInjectInto` "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M1"- , M2 () `shouldInjectInto` "(< M0 : { _1 : Bool } | M1 | M2 : { _1 : {} } >).M2 { _1 = {=} }"+ , E0 `shouldEmbedAsWrapped` "< E0 | E1 | E2 >.E0"+ , E1 `shouldEmbedAsWrapped` "< E0 | E1 | E2 >.E1"+ , E2 `shouldEmbedAsWrapped` "< E0 | E1 | E2 >.E2"++ , R0 `shouldEmbedAsWrapped` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R0"+ , R1 { a = () } `shouldEmbedAsWrapped` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R1 { a = {=} }"+ , R2 { x = 1.0 } `shouldEmbedAsWrapped` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R2 { x = 1.0}"+ , R3 { a = (), b = () } `shouldEmbedAsWrapped` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R3 { a = {=}, b = {=} }"+ , R4 { x = 1.0, y = 2.0 } `shouldEmbedAsWrapped` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R4 { x = 1.0, y = 2.0 }"++ , R0 `shouldEmbedAsSmart` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R0"+ , R1 { a = () } `shouldEmbedAsSmart` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R1 { a = {=} }"+ , R2 { x = 1.0 } `shouldEmbedAsSmart` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R2 { x = 1.0}"+ , R3 { a = (), b = () } `shouldEmbedAsSmart` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R3 { a = {=}, b = {=} }"+ , R4 { x = 1.0, y = 2.0 } `shouldEmbedAsSmart` "< R0 | R1 : { a : {} } | R2 : { x : Double } | R3 : { a : {}, b : {} } | R4 : { x : Double, y : Double } >.R4 { x = 1.0, y = 2.0 }"++ , P0 `shouldEmbedAsWrapped` "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P0"+ , P1 () `shouldEmbedAsWrapped` "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P1 { _1 = {=} }"+ , P2 1.0 `shouldEmbedAsWrapped` "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P2 { _1 = 1.0 }"+ , P3 () () `shouldEmbedAsWrapped` "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P3 { _1 = {=}, _2 = {=} }"+ , P4 1.0 2.0 `shouldEmbedAsWrapped` "< P0 | P1 : { _1 : {} } | P2 : { _1 : Double } | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P4 { _1 = 1.0, _2 = 2.0 }"++ , P0 `shouldEmbedAsSmart` "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P0"+ , P1 () `shouldEmbedAsSmart` "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P1"+ , P2 1.0 `shouldEmbedAsSmart` "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P2 1.0"+ , P3 () () `shouldEmbedAsSmart` "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P3 { _1 = {=}, _2 = {=} }"+ , P4 1.0 2.0 `shouldEmbedAsSmart` "< P0 | P1 | P2 : Double | P3 : { _1 : {}, _2 : {} } | P4 : { _1 : Double, _2 : Double } >.P4 { _1 = 1.0, _2 = 2.0 }" ] where- code `shouldPassThrough` values = testCase "Pass through" $ do- f <- Dhall.input Dhall.auto code+ smartOptions =+ Dhall.defaultInterpretOptions+ { Dhall.singletonConstructors = Dhall.Smart } + wrappedOptions =+ Dhall.defaultInterpretOptions+ { Dhall.singletonConstructors = Dhall.Wrapped }++ functionWithOptions+ :: ( Generic a+ , Dhall.GenericToDhall (Rep a)+ , Generic b+ , Dhall.GenericFromDhall b (Rep b)+ )+ => Dhall.InterpretOptions -> Dhall.Decoder (a -> b)+ functionWithOptions options =+ Dhall.function (Dhall.genericToDhallWith options) (Dhall.genericAutoWith options)++ code `shouldPassThroughWrapped` values = testCase "Pass through" $ do+ f <- Dhall.input (functionWithOptions wrappedOptions) code+ values @=? map f values - code `shouldMarshalInto` expectedValue = testCase "Marshal" $ do- actualValue <- Dhall.input Dhall.auto code+ code `shouldPassThroughSmart` values = testCase "Pass through" $ do+ f <- Dhall.input (functionWithOptions smartOptions) code++ values @=? map f values++ code `shouldMarshalIntoWrapped` expectedValue = testCase "Marshal" $ do+ actualValue <- Dhall.input (Dhall.genericAutoWith wrappedOptions) code+ expectedValue @=? actualValue - value `shouldInjectInto` expectedCode = testCase "Inject" $ do+ code `shouldMarshalIntoSmart` expectedValue = testCase "Marshal" $ do+ actualValue <- Dhall.input (Dhall.genericAutoWith smartOptions) code++ expectedValue @=? actualValue++ value `shouldEmbedAsWrapped` expectedCode = testCase "ToDhall" $ do parsedExpression <- Dhall.Core.throws (Dhall.Parser.exprFromText "(test)" expectedCode) resolvedExpression <- Dhall.Import.assertNoImports parsedExpression - Dhall.Core.denote resolvedExpression @=? Dhall.embed Dhall.inject value+ Dhall.Core.denote resolvedExpression @=? Dhall.embed (Dhall.genericToDhallWith wrappedOptions) value++ value `shouldEmbedAsSmart` expectedCode = testCase "ToDhall" $ do+ parsedExpression <- Dhall.Core.throws (Dhall.Parser.exprFromText "(test)" expectedCode)++ resolvedExpression <- Dhall.Import.assertNoImports parsedExpression++ Dhall.Core.denote resolvedExpression @=? Dhall.embed (Dhall.genericToDhallWith smartOptions) value++shouldConvertDhallToHaskellCorrectly :: TestTree+shouldConvertDhallToHaskellCorrectly =+ testGroup+ "Marshall Dhall code to Haskell"+ [ "True" `correspondsTo` True+ , "False" `correspondsTo` False+ , "2" `correspondsTo` (2 :: Natural)+ , "+2" `correspondsTo` (2 :: Integer)+ , "2.0" `correspondsTo` (2.0 :: Double)+ , "2.0" `correspondsTo` (2.0 :: Scientific)+ , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Text)+ , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Lazy.Text)+ , "\"ABC\"" `correspondsTo` ("ABC" :: String)+ , "Some 2" `correspondsTo` (Just 2 :: Maybe Natural)+ , "None Natural" `correspondsTo` (Nothing :: Maybe Natural)+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Seq Natural)+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: [Natural])+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Vector Natural)+ , "[] : List Natural" `correspondsTo` ([] :: [Natural])+ , "{=}" `correspondsTo` ()+ , "{ _1 = True, _2 = {=} }" `correspondsTo` (True, ())+ ]+ where+ correspondsTo :: (Eq a, FromDhall a, Show a) => Text -> a -> TestTree+ dhallCode `correspondsTo` expectedHaskellValue =+ testCase "Marshall Dhall code to Haskell" $ do+ actualHaskellValue <- Dhall.input Dhall.auto dhallCode++ expectedHaskellValue @=? actualHaskellValue++shouldConvertHaskellToDhallCorrectly :: TestTree+shouldConvertHaskellToDhallCorrectly =+ testGroup+ "Marshall Haskell to Dhall code"+ [ "True" `correspondsTo` True+ , "False" `correspondsTo` False+ , "2" `correspondsTo` (2 :: Natural)+ , "+2" `correspondsTo` (2 :: Integer)+ , "2.0" `correspondsTo` (2.0 :: Double)+ , "2.0" `correspondsTo` (2.0 :: Scientific)+ , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Text)+ , "\"ABC\"" `correspondsTo` ("ABC" :: Data.Text.Lazy.Text)+ , "\"ABC\"" `correspondsTo` ("ABC" :: String)+ , "Some 2" `correspondsTo` (Just 2 :: Maybe Natural)+ , "None Natural" `correspondsTo` (Nothing :: Maybe Natural)+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Seq Natural)+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: [Natural])+ , "[ 2, 3, 5 ]" `correspondsTo` ([ 2, 3, 5 ] :: Vector Natural)+ , "[] : List Natural" `correspondsTo` ([] :: [Natural])+ , "{=}" `correspondsTo` ()+ , "{ _1 = True, _2 = {=} }" `correspondsTo` (True, ())+ ]+ where+ correspondsTo :: ToDhall a => Text -> a -> TestTree+ expectedDhallCode `correspondsTo` haskellValue =+ testCase "Marshall Haskell to Dhall code" $ do+ let actualDhallCode =+ Dhall.Core.pretty (Dhall.embed Dhall.inject haskellValue)++ expectedDhallCode @=? actualDhallCode++-- https://github.com/dhall-lang/dhall-haskell/issues/1711+data Issue1711+ = A Bad+ | B+ | C+ | D+ deriving (Generic, Show, FromDhall)++newtype Bad = Bad Text+ deriving (Show)++issue1711Msg :: Text+issue1711Msg = "Issue 1711"++instance FromDhall Bad where+ autoWith _ =+ Dhall.Decoder+ (const (Dhall.extractError issue1711Msg))+ (Dhall.expected Dhall.strictText)++type DhallExtractErrors = Dhall.ExtractErrors Dhall.Parser.Src Void++-- https://github.com/dhall-lang/dhall-haskell/issues/1711+shouldShowCorrectErrorForInvalidDecoderInUnion :: TestTree+shouldShowCorrectErrorForInvalidDecoderInUnion =+ testCase "Correct error is thrown for invalid decoder in union" $ do+ let value = "< B | D | C | A : Text >.A \"\""++ inputEx :: Either DhallExtractErrors Issue1711 <- try (Dhall.input Dhall.auto value)++ let expectedMsg = issue1711Msg++ let assertMsg = "The exception message did not match the expected output"++ case inputEx of+ Left (Dhall.DhallErrors errs) -> case errs of+ (err :| []) -> case err of+ Dhall.TypeMismatch {} -> fail "The extraction using an invalid decoder failed with a type mismatch"+ Dhall.ExpectedTypeError _ -> fail "An error occurred while determining the expected Dhall type"+ Dhall.ExtractError extractError -> assertEqual assertMsg expectedMsg extractError+ _ -> fail "The extraction using an invalid decoder failed with multiple errors"+ Right _ -> fail "The extraction using an invalid decoder succeeded"
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Diff where++import Data.Text (Text)+import Test.Tasty (TestTree)++import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Diff as Diff+import qualified Dhall.Parser as Parser+import qualified Dhall.Pretty+import qualified Dhall.Test.Util as Test.Util+import qualified Prettyprinter.Render.Text as Pretty.Text+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++diffDirectory :: FilePath+diffDirectory = "./tests/diff"++getTests :: IO TestTree+getTests = do+ diffTests <- Test.Util.discover (Turtle.chars <* "A.dhall") diffTest (Turtle.lstree diffDirectory)++ let testTree = Tasty.testGroup "diff tests" [ diffTests ]++ return testTree++diffTest :: Text -> TestTree+diffTest prefix =+ Tasty.HUnit.testCase (Text.unpack prefix) $ do+ let leftFile = Text.unpack (prefix <> "A.dhall")+ let rightFile = Text.unpack (prefix <> "B.dhall")+ let diffFile = Text.unpack (prefix <> ".txt")++ let toInput file = do+ text <- Text.IO.readFile file+ Core.throws (Parser.exprFromText mempty text)++ leftInput <- toInput leftFile+ rightInput <- toInput rightFile++ expectedDiffText <- Text.IO.readFile diffFile++ let actualDiffDocument =+ Diff.doc (Diff.diffNormalized leftInput rightInput) <> "\n"++ let actualDiffText = Pretty.Text.renderStrict+ (Dhall.Pretty.layout actualDiffDocument)++ let message = "The diffed expressions did not match the expected output"++ Tasty.HUnit.assertEqual message expectedDiffText actualDiffText
@@ -0,0 +1,149 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.DirectoryTree (tests) where++import Control.Monad+import Data.Either (partitionEithers)+import Data.Either.Validation+import Dhall.DirectoryTree+import Lens.Micro (set)+import System.FilePath ((</>))+import Test.Tasty+import Test.Tasty.HUnit++import qualified Data.List+import qualified Data.Text.IO+import qualified Dhall+import qualified Dhall.Core+import qualified System.Directory as Directory+import qualified System.FilePath as FilePath+import qualified System.PosixCompat.Files as Files++tests :: TestTree+tests = testGroup "to-directory-tree"+ [ testGroup "fixpointed"+ [ fixpointedType+ , fixpointedEmpty+ , fixpointedSimple+ , fixpointedAllowPathSeparators+#ifndef mingw32_HOST_OS+ , fixpointedPermissions+ , fixpointedUserGroup+#endif+ ]+ ]++fixpointedType :: TestTree+fixpointedType = testCase "Type is as expected" $ do+ let file = "./tests/to-directory-tree/type.dhall"+ ref <- Dhall.inputExpr file+ expected' <- case directoryTreeType of+ Failure e -> assertFailure $ show e+ Success expr -> return expr+ assertBool "Type mismatch" $ expected' `Dhall.Core.judgmentallyEqual` ref++fixpointedEmpty :: TestTree+fixpointedEmpty = testCase "empty" $ do+ let outDir = "./tests/to-directory-tree/fixpoint-empty.out"+ path = "./tests/to-directory-tree/fixpoint-empty.dhall"+ entries <- runDirectoryTree False outDir path+ entries @?= [Directory outDir]++fixpointedSimple :: TestTree+fixpointedSimple = testCase "simple" $ do+ let outDir = "./tests/to-directory-tree/fixpoint-simple.out"+ path = "./tests/to-directory-tree/fixpoint-simple.dhall"+ entries <- runDirectoryTree False outDir path+ entries @?= Data.List.sort+ [ Directory outDir+ , File $ outDir </> "file"+ , Directory $ outDir </> "directory"+ ]++fixpointedAllowPathSeparators :: TestTree+fixpointedAllowPathSeparators = testCase "allow-path-separators" $ do+ let outDir = "./tests/to-directory-tree/fixpoint-allow-path-separators.out"+ path = "./tests/to-directory-tree/fixpoint-allow-path-separators.dhall"+ entries <- runDirectoryTree True outDir path+ entries @?= Data.List.sort+ [ Directory outDir+ , Directory $ outDir </> "non-existent-1"+ , File $ outDir </> "non-existent-1" </> "file"+ , Directory $ outDir </> "non-existent-2"+ , Directory $ outDir </> "non-existent-2" </> "directory"+ ]++{-+This test is disabled on Windows as it fails due to limitations of the :+ expected: 448+ but got: 438+-}+fixpointedPermissions :: TestTree+fixpointedPermissions = testCase "permissions" $ do+ let outDir = "./tests/to-directory-tree/fixpoint-permissions.out"+ path = "./tests/to-directory-tree/fixpoint-permissions.dhall"+ entries <- runDirectoryTree False outDir path+ entries @?=+ [ Directory outDir+ , File $ outDir </> "file"+ ]+ s <- Files.getFileStatus $ outDir </> "file"+ let mode = Files.fileMode s `Files.intersectFileModes` Files.accessModes+ prettyFileMode mode @?= prettyFileMode Files.ownerModes++fixpointedUserGroup :: TestTree+fixpointedUserGroup = testCase "user and group" $ do+ let file = "./tests/to-directory-tree/fixpoint-usergroup.dhall"+ expr <- Dhall.inputExpr file+ entries <- decodeDirectoryTree expr+ entries @?=+ [ TextFileEntry $ Entry+ { entryName = "ids"+ , entryContent = ""+ , entryUser = Just (UserId 0)+ , entryGroup = Just (GroupId 0)+ , entryMode = Nothing+ }+ , TextFileEntry $ Entry+ { entryName = "names"+ , entryContent = ""+ , entryUser = Just (UserName "user")+ , entryGroup = Just (GroupName "group")+ , entryMode = Nothing+ }+ ]++runDirectoryTree :: Bool -> FilePath -> FilePath -> IO [WalkEntry]+runDirectoryTree allowSeparators outDir path = do+ doesOutDirExist <- Directory.doesDirectoryExist outDir+ when doesOutDirExist $+ Directory.removeDirectoryRecursive outDir+ Directory.createDirectoryIfMissing True outDir++ text <- Data.Text.IO.readFile path+ let inputSettings+ = set Dhall.rootDirectory (FilePath.takeDirectory path)+ . set Dhall.sourceName path+ $ Dhall.defaultInputSettings+ expr <- Dhall.inputExprWithSettings inputSettings text++ toDirectoryTree allowSeparators outDir $ Dhall.Core.denote expr++ Data.List.sort <$> walkFsTree outDir++data WalkEntry+ = Directory FilePath+ | File FilePath+ deriving (Eq, Ord, Show)++walkFsTree :: FilePath -> IO [WalkEntry]+walkFsTree dir = do+ entries <- Directory.listDirectory dir+ (ds, fs) <- fmap partitionEithers $ forM entries $ \path -> do+ let path' = dir </> path+ isDirectory <- Directory.doesDirectoryExist path'+ return $ if isDirectory then Left path' else Right (File path')+ entries' <- traverse walkFsTree ds+ return $ Directory dir : fs <> concat entries'
@@ -2,22 +2,21 @@ module Dhall.Test.Format where -import Data.Monoid (mempty, (<>))-import Data.Text (Text)-import Dhall.Pretty (CharacterSet(..))-import Test.Tasty (TestTree)+import Data.Text (Text)+import Dhall.Parser (Header (..))+import Dhall.Pretty (CharacterSet (..))+import Test.Tasty (TestTree) -import qualified Control.Monad as Monad-import qualified Data.Text as Text-import qualified Data.Text.IO as Text.IO-import qualified Data.Text.Prettyprint.Doc as Doc-import qualified Data.Text.Prettyprint.Doc.Render.Text as Doc.Render.Text-import qualified Dhall.Core as Core-import qualified Dhall.Parser as Parser-import qualified Dhall.Pretty as Pretty-import qualified Dhall.Test.Util as Test.Util-import qualified Test.Tasty as Tasty-import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Parser as Parser+import qualified Dhall.Pretty as Pretty+import qualified Dhall.Test.Util as Test.Util+import qualified Prettyprinter as Doc+import qualified Prettyprinter.Render.Text as Doc.Render.Text+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.Silver as Tasty.Silver import qualified Turtle getTests :: IO TestTree@@ -27,7 +26,7 @@ let skip = [ "./tests/format/asciiA.dhall" ] - Monad.guard (path `notElem` skip)+ path `Test.Util.pathNotIn` skip return path @@ -43,23 +42,26 @@ return testTree -formatTest :: CharacterSet -> Text -> TestTree-formatTest characterSet prefix =- Tasty.HUnit.testCase (Text.unpack prefix) $ do- let inputFile = Text.unpack (prefix <> "A.dhall")- let outputFile = Text.unpack (prefix <> "B.dhall")-- inputText <- Text.IO.readFile inputFile+format :: CharacterSet -> (Header, Core.Expr Parser.Src Core.Import) -> Text+format characterSet (Header header, expr) =+ let doc = Doc.pretty header+ <> Pretty.prettyCharacterSet characterSet expr+ <> "\n" - expr <- Core.throws (Parser.exprFromText mempty inputText)+ docStream = Pretty.layout doc+ in+ Doc.Render.Text.renderStrict docStream - let doc = Pretty.prettyCharacterSet characterSet expr- let docStream = Doc.layoutSmart Pretty.layoutOpts doc- let actualText = Doc.Render.Text.renderStrict docStream+formatTest :: CharacterSet -> Text -> TestTree+formatTest characterSet prefix =+ let inputFile = Text.unpack (prefix <> "A.dhall")+ outputFile = Text.unpack (prefix <> "B.dhall") - expectedText <- Text.IO.readFile outputFile+ action = do+ inputText <- Text.IO.readFile inputFile - let message =- "The formatted expression did not match the expected output"+ headerAndExpr <- Core.throws (Parser.exprAndHeaderFromText mempty inputText) - Tasty.HUnit.assertEqual message expectedText actualText+ return (format characterSet headerAndExpr)+ in+ Tasty.Silver.goldenVsAction (Text.unpack prefix) outputFile action id
@@ -0,0 +1,59 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Freeze where++import Data.Text (Text)+import Dhall.Freeze (Intent (..), Scope (..))+import Test.Tasty (TestTree)++import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Freeze as Freeze+import qualified Dhall.Parser as Parser+import qualified Dhall.Test.Util as Test.Util+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++freezeDirectoryCached :: FilePath+freezeDirectoryCached = "./tests/freeze/cached"++freezeDirectorySecure :: FilePath+freezeDirectorySecure = "./tests/freeze/secure"++getTests :: IO TestTree+getTests = do+ freezeCachedTests <- Test.Util.discover (Turtle.chars <* "A.dhall")+ (freezeTest freezeDirectoryCached Cache)+ (Turtle.lstree freezeDirectoryCached)+ freezeSecureTests <- Test.Util.discover (Turtle.chars <* "A.dhall")+ (freezeTest freezeDirectorySecure Secure)+ (Turtle.lstree freezeDirectorySecure)++ let testTree = Tasty.testGroup "freeze tests"+ [ Tasty.testGroup "cached" [freezeCachedTests]+ , Tasty.testGroup "secure" [freezeSecureTests]+ ]++ return testTree++freezeTest :: FilePath -> Intent -> Text -> TestTree+freezeTest dir intent prefix =+ Tasty.HUnit.testCase (Text.unpack prefix) $ do+ let inputFile = Text.unpack (prefix <> "A.dhall")+ let outputFile = Text.unpack (prefix <> "B.dhall")++ inputText <- Text.IO.readFile inputFile++ parsedInput <- Core.throws (Parser.exprFromText mempty inputText)++ actualExpression <- Freeze.freezeExpression dir AllImports intent parsedInput++ let actualText = Core.pretty actualExpression <> "\n"++ expectedText <- Text.IO.readFile outputFile++ let message = "The linted expression did not match the expected output"++ Tasty.HUnit.assertEqual message expectedText actualText
@@ -1,16 +1,16 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-} module Dhall.Test.Import where -import Control.Exception (catch)-import Data.Monoid ((<>))-import Data.Text (Text)-import Dhall.Import (MissingImports(..))-import Dhall.Parser (SourcedException(..))-import Prelude hiding (FilePath)-import Test.Tasty (TestTree)-import Turtle (FilePath, (</>))+import Control.Exception (SomeException)+import Data.Text (Text)+import Data.Void (Void)+import System.FilePath ((</>))+import Test.Tasty (TestTree) +import qualified Control.Exception as Exception import qualified Control.Monad.Trans.State.Strict as State import qualified Data.Text as Text import qualified Data.Text.IO as Text.IO@@ -19,19 +19,87 @@ import qualified Dhall.Parser as Parser import qualified Dhall.Test.Util as Test.Util import qualified System.FilePath as FilePath+import qualified System.IO.Temp as Temp import qualified Test.Tasty as Tasty import qualified Test.Tasty.HUnit as Tasty.HUnit import qualified Turtle +#if defined(WITH_HTTP) && defined(NETWORK_TESTS)+import qualified Network.HTTP.Client as HTTP+import qualified Network.HTTP.Client.TLS as HTTP+#endif++ importDirectory :: FilePath importDirectory = "./dhall-lang/tests/import" getTests :: IO TestTree getTests = do- successTests <- Test.Util.discover (Turtle.chars <> "A.dhall") successTest (Turtle.lstree (importDirectory </> "success"))+ let flakyTests =+ [ -- This test is flaky, occasionally failing with:+ --+ -- Error: Remote host not found+ --+ -- URL: https://test.dhall-lang.org/Bool/package.dhall+ importDirectory </> "success/headerForwardingA.dhall"+ , importDirectory </> "success/unit/RemoteAsTextA.dhall"+ , importDirectory </> "success/unit/SimpleRemoteA.dhall"+ , importDirectory </> "success/unit/asLocation/RemoteChain1A.dhall"+ , importDirectory </> "success/unit/asLocation/RemoteChain2A.dhall"+ , importDirectory </> "success/unit/asLocation/RemoteChain3A.dhall"+ , importDirectory </> "success/unit/asLocation/RemoteChainMissingA.dhall" - failureTests <- Test.Util.discover (Turtle.chars <> ".dhall") failureTest (Turtle.lstree (importDirectory </> "failure"))+ -- Skip all tests that reference httpbin.org to avoid clobbering+ -- their servers. These should eventually be replaced by tests+ -- that depend on an equivalent endpoint on test.dhall-lang.org+ -- instead of httpbin.org.+ , importDirectory </> "failure/customHeadersUsingBoundVariable.dhall"+ , importDirectory </> "failure/originHeadersFromRemote.dhall"+ , importDirectory </> "failure/originHeadersFromRemoteENV.dhall"+ , importDirectory </> "success/customHeadersA.dhall"+ , importDirectory </> "success/noHeaderForwardingA.dhall"+ , importDirectory </> "success/success/originHeadersA.dhall"+ , importDirectory </> "success/originHeadersENV.dhall"+ , importDirectory </> "success/originHeadersImportA.dhall"+ , importDirectory </> "success/originHeadersImportENV.dhall"+ , importDirectory </> "success/originHeadersImportFromEnvA.dhall"+ , importDirectory </> "success/originHeadersImportFromEnvENV.dhall"+ , importDirectory </> "success/originHeadersOverrideA.dhall"+ , importDirectory </> "success/originHeadersOverrideENV.dhall"+ ] + successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest (do+ path <- Turtle.lstree (importDirectory </> "success")++ path `Test.Util.pathNotIn` flakyTests++ return path )++ failureTests <- Test.Util.discover (Turtle.chars <* ".dhall") failureTest (do+ path <- Turtle.lstree (importDirectory </> "failure")++ let expectedSuccesses =+ [ importDirectory </> "failure/unit/DontRecoverCycle.dhall"+ , importDirectory </> "failure/unit/DontRecoverTypeError.dhall"+#if !(defined(WITH_HTTP) && defined(NETWORK_TESTS))+ -- We attempt to simulate test.dhall-lang.org, but even so+ -- some tests unexpectedly succeed due to the inadequacy of+ -- the simulation+ , importDirectory </> "failure/unit/cors/OnlySelf.dhall"+ , importDirectory </> "failure/unit/cors/OnlyOther.dhall"+ , importDirectory </> "failure/unit/cors/Null.dhall"+ , importDirectory </> "failure/unit/cors/TwoHops.dhall"+ , importDirectory </> "failure/unit/cors/Empty.dhall"+ , importDirectory </> "failure/unit/cors/NoCORS.dhall"+ , importDirectory </> "failure/originHeadersFromRemote.dhall"+#endif+ ]++ path `Test.Util.pathNotIn` expectedSuccesses+ "ENV.dhall" `Test.Util.pathNotSuffixOf` path++ return path )+ let testTree = Tasty.testGroup "import tests" [ successTests@@ -41,32 +109,131 @@ return testTree successTest :: Text -> TestTree-successTest path = do- let pathString = Text.unpack path+successTest prefix = do+ let inputPath = Text.unpack (prefix <> "A.dhall") - let directoryString = FilePath.takeDirectory pathString+ let expectedPath = Text.unpack (prefix <> "B.dhall") - Tasty.HUnit.testCase pathString (do+ let directoryString = FilePath.takeDirectory inputPath - text <- Text.IO.readFile pathString+ let expectedFailures =+ [+ -- Importing relative to the home directory works, but I'm too+ -- lazy to mock the home directory for testing purposes+ importDirectory </> "success/unit/ImportRelativeToHome"+#if !(defined(WITH_HTTP) && defined(NETWORK_TESTS))+ , importDirectory </> "success/originHeadersImportFromEnv"+ , importDirectory </> "success/originHeadersImport"+ , importDirectory </> "success/originHeadersOverride"+ , importDirectory </> "success/unit/asLocation/RemoteChainEnv"+#endif+ ] + Test.Util.testCase prefix expectedFailures (do++ text <- Text.IO.readFile inputPath++ expectedText <- Text.IO.readFile expectedPath+ actualExpr <- Core.throws (Parser.exprFromText mempty text) - _ <- State.evalStateT (Import.loadWith actualExpr) (Import.emptyStatus directoryString)+ expectedExpr <- Core.throws (Parser.exprFromText mempty expectedText) - return () )+ let originalCache = "dhall-lang/tests/import/cache" +#if defined(WITH_HTTP) && defined(NETWORK_TESTS)+ let httpManager =+ HTTP.newManager+ HTTP.tlsManagerSettings+ { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro (120 * 1000 * 1000) }++ let status =+ Import.makeEmptyStatus+ httpManager+ (pure Import.envOriginHeaders)+ directoryString+#else+ let status = Import.emptyStatus directoryString+#endif++ let load =+ State.evalStateT+ (Test.Util.loadWith actualExpr)+ status++ let usesCache = [ "hashFromCache"+ , "unit/asLocation/Hash"+ , "unit/IgnorePoisonedCache"+ , "unit/DontCacheIfHash"+ ]++ let endsIn path' =+ not (null (Turtle.match (Turtle.ends path') (Test.Util.toDhallPath prefix)))++ let buildNewCache = do+ tempdir <- Turtle.managed (Temp.withSystemTempDirectory "dhall-cache")+ Turtle.liftIO (Turtle.cptree originalCache tempdir)+ return tempdir++ let cacheSetup =+ if any endsIn usesCache+ then do+ cacheDir <- buildNewCache++ let set = do+ m <- Turtle.need "XDG_CACHE_HOME"++ Turtle.export "XDG_CACHE_HOME" (Turtle.format Turtle.fp cacheDir)++ return m++ let reset Nothing = do+ Turtle.unset "XDG_CACHE_HOME"+ reset (Just x) = do+ Turtle.export "XDG_CACHE_HOME" x++ _ <- Turtle.managed (Exception.bracket set reset)+ return ()+ else pure ()++ let setup = cacheSetup >> Test.Util.managedTestEnvironment prefix++ let resolve = Turtle.with setup (const load)++ let handler :: SomeException -> IO (Core.Expr Parser.Src Void)+ handler exception = Tasty.HUnit.assertFailure (show exception)++ actualResolved <- Exception.handle handler resolve++ expectedResolved <- Import.assertNoImports expectedExpr++ let actual = Core.normalize actualResolved :: Core.Expr Void Void++ let expected = Core.normalize expectedResolved :: Core.Expr Void Void++ let message =+ "The imported expression did not match the expected output"++ Tasty.HUnit.assertEqual message expected actual)+ failureTest :: Text -> TestTree-failureTest path = do+failureTest prefix = do+ let path = prefix <> ".dhall"+ let pathString = Text.unpack path Tasty.HUnit.testCase pathString (do- text <- Text.IO.readFile pathString+ actualExpr <- do+ Core.throws (Parser.exprFromText mempty (Test.Util.toDhallPath path)) - actualExpr <- Core.throws (Parser.exprFromText mempty text)+ let setup = Test.Util.managedTestEnvironment prefix - catch- (do _ <- Import.load actualExpr+ let run = Exception.catch @SomeException+ (Test.Util.load actualExpr >> return True)+ (\_ -> return False) - fail "Import should have failed, but it succeeds")- (\(SourcedException _ (MissingImports _)) -> pure ()) )+ succeeded <- Turtle.with setup (const run)++ if succeeded+ then fail "Import should have failed, but it succeeds"+ else return () )
@@ -2,22 +2,21 @@ module Dhall.Test.Lint where -import Data.Monoid (mempty, (<>))-import Data.Text (Text)-import Dhall.Core (Expr, Import)-import Dhall.TypeCheck (X)-import Prelude hiding (FilePath)-import Test.Tasty (TestTree)-import Turtle (FilePath)+import Data.Text (Text)+import Dhall.Parser (Header (..))+import Test.Tasty (TestTree) -import qualified Data.Text as Text-import qualified Data.Text.IO as Text.IO-import qualified Dhall.Core as Core-import qualified Dhall.Lint as Lint-import qualified Dhall.Parser as Parser-import qualified Dhall.Test.Util as Test.Util-import qualified Test.Tasty as Tasty-import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Lint as Lint+import qualified Dhall.Parser as Parser+import qualified Dhall.Pretty as Pretty+import qualified Dhall.Test.Util as Test.Util+import qualified Prettyprinter as Doc+import qualified Prettyprinter.Render.Text as Doc.Render.Text+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit import qualified Turtle lintDirectory :: FilePath@@ -25,12 +24,22 @@ getTests :: IO TestTree getTests = do- formatTests <- Test.Util.discover (Turtle.chars <* "A.dhall") lintTest (Turtle.lstree lintDirectory)+ lintTests <- Test.Util.discover (Turtle.chars <* "A.dhall") lintTest (Turtle.lstree lintDirectory) - let testTree = Tasty.testGroup "format tests" [ formatTests ]+ let testTree = Tasty.testGroup "lint tests" [ lintTests ] return testTree +format :: Header -> Core.Expr Parser.Src Core.Import -> Text+format (Header header) expr =+ let doc = Doc.pretty header+ <> Pretty.prettyCharacterSet Pretty.Unicode expr+ <> "\n"++ docStream = Pretty.layout doc+ in+ Doc.Render.Text.renderStrict docStream+ lintTest :: Text -> TestTree lintTest prefix = Tasty.HUnit.testCase (Text.unpack prefix) $ do@@ -39,18 +48,14 @@ inputText <- Text.IO.readFile inputFile - parsedInput <- Core.throws (Parser.exprFromText mempty inputText)-- let actualExpression :: Expr X Import- actualExpression = Core.denote (Lint.lint parsedInput)+ (header, parsedInput) <- Core.throws (Parser.exprAndHeaderFromText mempty inputText) - outputText <- Text.IO.readFile outputFile+ let actualExpression = Lint.lint parsedInput - parsedOutput <- Core.throws (Parser.exprFromText mempty outputText)+ let actualText = format header actualExpression - let expectedExpression :: Expr X Import- expectedExpression = Core.denote parsedOutput+ expectedText <- Text.IO.readFile outputFile let message = "The linted expression did not match the expected output" - Tasty.HUnit.assertEqual message expectedExpression actualExpression+ Tasty.HUnit.assertEqual message expectedText actualText
@@ -1,18 +1,29 @@+{-# LANGUAGE CPP #-} module Main where import System.FilePath ((</>)) import Test.Tasty (TestTree) import qualified Dhall.Test.Dhall+import qualified Dhall.Test.Diff+import qualified Dhall.Test.DirectoryTree import qualified Dhall.Test.Format+import qualified Dhall.Test.Freeze import qualified Dhall.Test.Import import qualified Dhall.Test.Lint import qualified Dhall.Test.Normalization+import qualified Dhall.Test.Package import qualified Dhall.Test.Parser import qualified Dhall.Test.QuickCheck import qualified Dhall.Test.Regression+import qualified Dhall.Test.Schemas+import qualified Dhall.Test.SemanticHash+#ifndef CROSS+import qualified Dhall.Test.TH+#endif+import qualified Dhall.Test.Tags import qualified Dhall.Test.Tutorial-import qualified Dhall.Test.TypeCheck+import qualified Dhall.Test.TypeInference import qualified GHC.IO.Encoding import qualified System.Directory import qualified System.Environment@@ -27,24 +38,44 @@ formattingTests <- Dhall.Test.Format.getTests - typecheckingTests <- Dhall.Test.TypeCheck.getTests+ typeinferenceTests <- Dhall.Test.TypeInference.getTests importingTests <- Dhall.Test.Import.getTests lintTests <- Dhall.Test.Lint.getTests + tagsTests <- Dhall.Test.Tags.getTests++ diffTests <- Dhall.Test.Diff.getTests++ semanticHashTests <- Dhall.Test.SemanticHash.getTests++ freezeTests <- Dhall.Test.Freeze.getTests++ schemaTests <- Dhall.Test.Schemas.getTests+ let testTree = Test.Tasty.testGroup "Dhall Tests" [ normalizationTests , parsingTests , importingTests- , typecheckingTests+ , typeinferenceTests , formattingTests , lintTests+ , diffTests+ , semanticHashTests+ , tagsTests+ , freezeTests+ , schemaTests+ , Dhall.Test.DirectoryTree.tests , Dhall.Test.Regression.tests , Dhall.Test.Tutorial.tests , Dhall.Test.QuickCheck.tests , Dhall.Test.Dhall.tests+#ifndef CROSS+ , Dhall.Test.TH.tests+#endif+ , Dhall.Test.Package.tests ] return testTree@@ -56,6 +87,12 @@ pwd <- System.Directory.getCurrentDirectory System.Environment.setEnv "XDG_CACHE_HOME" (pwd </> ".cache")++ System.Environment.setEnv "DHALL_TEST_VAR" "6 * 7"++ -- Make test failures easier to find by eliding the successes.+ -- https://github.com/feuerbach/tasty/issues/273#issuecomment-657054281+ System.Environment.setEnv "TASTY_HIDE_SUCCESSES" "true" allTests <- getAllTests
@@ -2,15 +2,12 @@ module Dhall.Test.Normalization where -import Data.Monoid ((<>))-import Data.Text (Text)-import Dhall.Core (Expr(..), Var(..), throws)-import Dhall.TypeCheck (X)-import Prelude hiding (FilePath)-import Test.Tasty (TestTree)-import Turtle (FilePath, (</>))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Core (Expr (..), Var (..), throws)+import System.FilePath ((</>))+import Test.Tasty (TestTree) -import qualified Control.Monad as Monad import qualified Data.Text as Text import qualified Data.Text.IO as Text.IO import qualified Dhall.Context as Context@@ -19,6 +16,7 @@ import qualified Dhall.Parser as Parser import qualified Dhall.Test.Util as Test.Util import qualified Dhall.TypeCheck as TypeCheck+import qualified System.FilePath as FilePath import qualified Test.Tasty as Tasty import qualified Test.Tasty.HUnit as Tasty.HUnit import qualified Turtle@@ -26,43 +24,41 @@ normalizationDirectory :: FilePath normalizationDirectory = "./dhall-lang/tests/normalization/success" +unitDirectory :: FilePath+unitDirectory = normalizationDirectory </> "unit/"+ getTests :: IO TestTree getTests = do let pattern = Turtle.chars <* "A.dhall" let normalizationFiles = do- path <- Turtle.lstree normalizationDirectory+ path <- FilePath.normalise <$> Turtle.lstree normalizationDirectory - Nothing <- return (Turtle.stripPrefix (normalizationDirectory </> "unit/") path)+ unitDirectory `Test.Util.pathNotPrefixOf` path return path betaNormalizationTests <- Test.Util.discover pattern betaNormalizationTest normalizationFiles - alphaNormalizationTests <- do+ alphaNormalizationTests <- Test.Util.discover pattern alphaNormalizationTest (Turtle.lstree "./dhall-lang/tests/alpha-normalization/success/") - let unitTestFiles = do- path <- Turtle.lstree "./dhall-lang/tests/normalization/success/unit"-- let skip =- [ normalizationDirectory </> "unit/EmptyAlternativeA.dhall"- -- https://github.com/dhall-lang/dhall-lang/issues/505- , normalizationDirectory </> "unit/OperatorTextConcatenateLhsEmptyA.dhall"- ]-- Monad.guard (path `notElem` skip)-- return path+ let unitTestFiles = Turtle.lstree unitDirectory unitTests <- Test.Util.discover pattern unitTest unitTestFiles let testTree = Tasty.testGroup "normalization"- [ betaNormalizationTests- , unitTests- , alphaNormalizationTests+ [ Tasty.testGroup "beta-normalization"+ [ betaNormalizationTests+ ]+ , Tasty.testGroup "unit tests"+ [ unitTests+ ]+ , Tasty.testGroup "alpha-normalization"+ [ alphaNormalizationTests+ ] , customization ] @@ -80,7 +76,7 @@ let tyCtx = Context.insert "min"- (Pi "_" Natural (Pi "_" Natural Natural))+ (Pi mempty "_" Natural (Pi mempty "_" Natural Natural)) Context.empty valCtx e =@@ -98,7 +94,7 @@ nestedReduction = Tasty.HUnit.testCase "doubleReduction" $ do minType <- Context.insert "min" <$> Test.Util.code "Natural → Natural → Natural" fiveorlessType <- Context.insert "fiveorless" <$> Test.Util.code "Natural → Natural"- wurbleType <- Context.insert "wurble" <$> Test.Util.code "Natural → Integer"+ wurbleType <- Context.insert "wurble" <$> Test.Util.code "Natural → Natural" let tyCtx = minType . fiveorlessType . wurbleType $ Context.empty @@ -138,10 +134,10 @@ expectedResolved <- Import.assertNoImports expectedExpr - let expectedNormalized = Core.denote expectedResolved :: Expr X X+ let expectedNormalized = Core.denote expectedResolved :: Expr Void Void let message =- "The normalized expression did not match the expected output"+ "The alpha-normalized expression did not match the expected output" Tasty.HUnit.assertEqual message expectedNormalized actualNormalized @@ -150,9 +146,11 @@ -} unitTest :: Text -> TestTree unitTest prefix = do+ let expectedFailures = []+ let prefixString = Text.unpack prefix - Tasty.HUnit.testCase prefixString $ do+ Test.Util.testCase prefix expectedFailures $ do let actualPath = prefixString <> "A.dhall" let expectedPath = prefixString <> "B.dhall" @@ -165,7 +163,7 @@ let actualNormalized = Core.alphaNormalize- (Core.normalize actualResolved :: Expr X X)+ (Core.normalize actualResolved :: Expr Void Void) expectedExpr <- throws (Parser.exprFromText mempty expectedCode) @@ -180,11 +178,15 @@ Tasty.HUnit.assertEqual message expectedNormalized actualNormalized betaNormalizationTest :: Text -> TestTree-betaNormalizationTest prefix =- Tasty.HUnit.testCase (Text.unpack prefix) $ do- let actualCode = Test.Util.toDhallPath (prefix <> "A.dhall")- let expectedCode = Test.Util.toDhallPath (prefix <> "B.dhall")+betaNormalizationTest prefix = do+ let prefixString = Text.unpack prefix + Tasty.HUnit.testCase prefixString $ do+ let actualCode = Test.Util.toDhallPath (prefix <> "A.dhall")++ let expectedPath = prefixString <> "B.dhall"+ expectedCode <- Text.IO.readFile expectedPath+ actualExpr <- throws (Parser.exprFromText mempty actualCode) actualResolved <- Import.load actualExpr@@ -193,7 +195,7 @@ let actualNormalized = Core.alphaNormalize- (Core.normalize actualResolved :: Expr X X)+ (Core.normalize actualResolved :: Expr Void Void) expectedExpr <- throws (Parser.exprFromText mempty expectedCode) @@ -207,6 +209,6 @@ Core.alphaNormalize (Core.denote expectedResolved) let message =- "The normalized expression did not match the expected output"+ "The beta-normalized expression did not match the expected output" Tasty.HUnit.assertEqual message expectedNormalized actualNormalized
@@ -0,0 +1,270 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Package where++import Control.Exception (Exception, displayException, finally, try)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Void (Void)+import Dhall.Core+ ( Directory (..)+ , Expr (..)+ , File (..)+ , FilePrefix (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , makeRecordField+ )+import qualified Dhall.Map as Map+import Dhall.Package+import Lens.Micro (set)+import qualified System.Directory as Directory+import System.FilePath ((</>))+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests = testGroup "Package"+ [ packagePackageFile+ , packageCustomPackageFile+ , packageSingleFile+ , packageEmptyDirectory+ , packageSingleDirectory+ , packageNested+ , packageRecursive+ , packageMissingFile+ , packageFilesDifferentDirs+ , packageIncompatibleFiles+ ]++packagePackageFile :: TestTree+packagePackageFile = testCase "package file" $ do+ let path = "./tests/package" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit Map.empty++ (output, expr) <- getPackagePathAndContent defaultOptions ("./tests/package/package.dhall" :| [])+ assertEqual "path" path output+ assertEqual "content" package expr++packageCustomPackageFile :: TestTree+packageCustomPackageFile = testCase "custom package file" $ do+ let path = "./tests/package" </> "custom.dhall"++ let package :: Expr Void Import+ package = RecordLit $+ Map.singleton "package" $ makeRecordField $ Embed packageDhall++ let options :: Options+ options = set packageFileName "custom.dhall" defaultOptions++ (output, expr) <- getPackagePathAndContent options ("./tests/package/package.dhall" :| [])+ assertEqual "path" path output+ assertEqual "content" package expr++packageSingleFile :: TestTree+packageSingleFile = testCase "single file" $ do+ let path = "./tests/package/dir" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit $+ Map.singleton "test" $ makeRecordField $ Embed testDhall++ (output, expr) <- getPackagePathAndContent defaultOptions ("./tests/package/dir/test.dhall" :| [])+ assertEqual "path" path output+ assertEqual "content" package expr++packageEmptyDirectory :: TestTree+packageEmptyDirectory = testCase "empty directory" $ do+ let path = "./tests/package/empty" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit Map.empty++ (output, expr) <- getPackagePathAndContent defaultOptions ("./tests/package/empty" :| [])+ assertEqual "path" path output+ assertEqual "content" package expr++packageSingleDirectory :: TestTree+packageSingleDirectory = testCase "single directory" $ do+ let path = "./tests/package/dir" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit $ Map.singleton "test" $+ makeRecordField $ Embed testDhall++ (output, expr) <- getPackagePathAndContent defaultOptions ("./tests/package/dir" :| [])+ assertEqual "path" path output+ assertEqual "content" package expr++packageNested :: TestTree+packageNested = testCase "nested files" $ do+ let path = "./tests/package" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit $ Map.fromList+ [ ("dir", makeRecordField $ RecordLit $ Map.fromList+ [ ("test", makeRecordField $ Embed dirTestDhall)+ ]+ )+ , ("other", makeRecordField $ Embed otherPackageDhall)+ , ("test", makeRecordField $ Embed testDhall)+ ]++ (output, expr) <- getPackagePathAndContent defaultOptions+ ( "./tests/package/test.dhall" :|+ [ "./tests/package/dir/test.dhall"+ , "./tests/package/other/package.dhall"+ ])+ assertEqual "path" path output+ assertEqual "content" package expr++packageRecursive :: TestTree+packageRecursive = testCase "recursively create subpackages" $ removePackagesAfter $ do+ let path = "./tests/package/dir" </> "package.dhall"++ let package :: Expr Void Import+ package = RecordLit $ Map.fromList+ [ ("subdirectory1", makeRecordField $ Embed subdirectoryPackageDhall1)+ , ("subdirectory2", makeRecordField $ Embed subdirectoryPackageDhall2)+ , ("test", makeRecordField $ Embed testDhall)+ ]++ let options :: Options+ options = set packagingMode RecursiveSubpackages defaultOptions++ (output, expr) <- getPackagePathAndContent options+ ( "./tests/package/dir" :| [] )+ assertEqual "path" path output+ assertEqual "content" package expr+ where+ removePackagesAfter :: IO a -> IO a+ removePackagesAfter action = action `finally` do+ Directory.removePathForcibly "./tests/package/dir/subdirectory1/package.dhall"+ Directory.removePathForcibly "./tests/package/dir/subdirectory2/package.dhall"++packageMissingFile :: TestTree+packageMissingFile = testCase "missing file" $ do+ let action :: IO (FilePath, Expr Void Import)+ action = getPackagePathAndContent defaultOptions ("./tests/package/missing.dhall" :| [])++ assertThrow action $ \case+ InvalidPath "./tests/package/missing.dhall" -> True+ _ -> False++packageFilesDifferentDirs :: TestTree+packageFilesDifferentDirs = testCase "files from different directories" $ do+ let action :: IO (FilePath, Expr Void Import)+ action = getPackagePathAndContent defaultOptions+ ( "./tests/package/dir/test.dhall" :|+ [ "./tests/package/test/test.dhall"+ ])++ assertThrow action $ \case+ AmbiguousOutputDirectory "./tests/package/dir" "./tests/package/test" -> True+ _ -> False++packageIncompatibleFiles :: TestTree+packageIncompatibleFiles = testCase "files that are incompatible" $ do+ let action :: IO (FilePath, Expr Void Import)+ action = getPackagePathAndContent defaultOptions+ ( "./tests/package/test.dhall" :|+ [ "./tests/package/test/test.dhall"+ ])++ assertThrow action $ \case+ IncompatiblePaths xs -> xs == [ testDhall , testTestDhall ]+ _ -> False++packageDhall :: Import+packageDhall = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here File+ { directory = Directory []+ , file = "package.dhall"+ }+ }+ , importMode = Code+ }++testDhall :: Import+testDhall = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here File+ { directory = Directory []+ , file = "test.dhall"+ }+ }+ , importMode = Code+ }++dirTestDhall :: Import+dirTestDhall = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here $ File+ { directory = Directory {components = ["dir"]}+ , file = "test.dhall"+ }+ }+ , importMode = Code+ }++otherPackageDhall :: Import+otherPackageDhall = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here $ File+ { directory = Directory {components = ["other"]}+ , file = "package.dhall"+ }+ }+ , importMode = Code+ }++subdirectoryPackageDhall1 :: Import+subdirectoryPackageDhall1 = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here $ File+ { directory = Directory {components = ["subdirectory1"]}+ , file = "package.dhall"}+ }+ , importMode = Code+ }++subdirectoryPackageDhall2 :: Import+subdirectoryPackageDhall2 = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here $ File+ { directory = Directory {components = ["subdirectory2"]}+ , file = "package.dhall"}+ }+ , importMode = Code+ }++testTestDhall :: Import+testTestDhall = Import+ { importHashed = ImportHashed+ { hash = Nothing+ , importType = Local Here (File+ { directory = Directory {components = ["test"]}+ , file = "test.dhall"+ })+ }+ , importMode = Code+ }++assertThrow :: (Exception e, Show a) => IO a -> (e -> Bool) -> IO ()+assertThrow k p = do+ result <- try k+ case result of+ Left e | p e -> return ()+ Left e -> assertFailure $ "Predicate did not match: " <> displayException e+ Right result' -> assertFailure $ "Expected exception, but got: " <> show result'
@@ -2,17 +2,18 @@ module Dhall.Test.Parser where -import Data.Text (Text)-import Dhall.Core (Expr, Import)-import Dhall.TypeCheck (X)-import Prelude hiding (FilePath)-import Test.Tasty (TestTree)-import Turtle (FilePath, (</>))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Core (Binding (..), Expr (..), Import, Var (..))+import System.FilePath ((</>))+import Test.Tasty (TestTree) -import qualified Codec.Serialise as Serialise import qualified Control.Monad as Monad+import qualified Data.Bifunctor as Bifunctor+import qualified Data.ByteString as ByteString import qualified Data.ByteString.Lazy as ByteString.Lazy import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text.Encoding import qualified Data.Text.IO as Text.IO import qualified Dhall.Binary as Binary import qualified Dhall.Core as Core@@ -20,6 +21,7 @@ import qualified Dhall.Test.Util as Test.Util import qualified Test.Tasty as Tasty import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Text.Printf as Printf import qualified Turtle parseDirectory :: FilePath@@ -30,116 +32,188 @@ getTests :: IO TestTree getTests = do- let successFiles = do- path <- Turtle.lstree (parseDirectory </> "success")-- let skip =- -- This is a bug created by a parsing performance- -- improvement- [ parseDirectory </> "success/unit/MergeParenAnnotationA.dhall"- ]-- Monad.guard (path `notElem` skip)-- return path+ let successFiles = Turtle.lstree (parseDirectory </> "success") - successTests <- do+ successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") shouldParse successFiles - let failureFiles = do- path <- Turtle.lstree (parseDirectory </> "failure")-- let skip =- [ -- These two unexpected successes are due to not correctly- -- requiring non-empty whitespace after the `:` in a type- -- annotatoin- parseDirectory </> "failure/annotation.dhall"- , parseDirectory </> "failure/unit/ImportEnvWrongEscape.dhall"-- -- Similarly, the implementation does not correctly- -- require a space between a function and its argument- , parseDirectory </> "failure/missingSpace.dhall"-- -- For parsing performance reasons the implementation- -- treats a missing type annotation on an empty list as- -- as a type-checking failure instead of a parse failure,- -- but this might be fixable.- , parseDirectory </> "failure/unit/ListLitEmptyAnnotation.dhall"- -- The same performance improvements also broke the- -- precedence of parsing empty list literals- , parseDirectory </> "failure/unit/ListLitEmptyPrecedence.dhall"- ]-- Monad.guard (path `notElem` skip)-- return path+ let failureFiles = Turtle.lstree (parseDirectory </> "failure") - failureTests <- do+ failureTests <- Test.Util.discover (Turtle.chars <> ".dhall") shouldNotParse failureFiles - let binaryDecodeFiles =+ let binaryDecodeSuccessFiles = Turtle.lstree (binaryDecodeDirectory </> "success") - binaryDecodeTests <- do- Test.Util.discover (Turtle.chars <* "A.dhallb") shouldDecode binaryDecodeFiles+ binaryDecodeSuccessTests <-+ Test.Util.discover (Turtle.chars <* "A.dhallb") shouldDecode binaryDecodeSuccessFiles + let binaryDecodeFailureFiles = Turtle.lstree (binaryDecodeDirectory </> "failure")++ binaryDecodeFailureTests <-+ Test.Util.discover (Turtle.chars <* ".dhallb") shouldNotDecode binaryDecodeFailureFiles+ let testTree = Tasty.testGroup "parser tests" [ successTests , failureTests- , binaryDecodeTests+ , internalTests+ , binaryDecodeSuccessTests+ , binaryDecodeFailureTests ] return testTree +internalTests :: TestTree+internalTests =+ Tasty.testGroup "internal"+ [ notesInLetInLet ]++notesInLetInLet :: TestTree+notesInLetInLet =+ Tasty.HUnit.testCase "Notes in let-in-let" $ do+ let code = "let x = 0 let y = 1 in let z = 2 in x"++ expression <- Core.throws (Parser.exprFromText mempty code)++ let simplifyNotes = Bifunctor.first Parser.srcText++ let expected =+ (Note code+ (Let+ (Binding+ (Just " ")+ "x"+ (Just " ")+ Nothing+ (Just " ")+ (Note "0 " (Note "0" (NaturalLit 0)))+ )+ -- This 'Let' isn't wrapped in a 'Note'!+ (Let+ (Binding+ (Just " ")+ "y"+ (Just " ")+ Nothing+ (Just " ")+ (Note "1 " (Note "1" (NaturalLit 1)))+ )+ (Note "let z = 2 in x"+ (Let+ (Binding+ (Just " ")+ "z"+ (Just " ")+ Nothing+ (Just " ")+ (Note "2 " (Note "2" (NaturalLit 2)))+ )+ (Note "x" (Var (V "x" 0)))+ )+ )+ )+ )+ )++ let msg = "Unexpected parse result"++ Tasty.HUnit.assertEqual msg expected (simplifyNotes expression)+ shouldParse :: Text -> TestTree shouldParse path = do+ let expectedFailures = []+ let pathString = Text.unpack path - Tasty.HUnit.testCase pathString $ do+ Test.Util.testCase path expectedFailures $ do text <- Text.IO.readFile (pathString <> "A.dhall") encoded <- ByteString.Lazy.readFile (pathString <> "B.dhallb") - expression <- Core.throws (Parser.exprFromText mempty text)+ expression <- case Parser.exprFromText mempty text of+ Left exception -> Tasty.HUnit.assertFailure (show exception)+ Right expression -> return expression - let term = Binary.encode expression+ let bytes = Binary.encodeExpression (Core.denote expression) - let bytes = Serialise.serialise term+ let render =+ concatMap (Printf.printf "%02x ")+ . ByteString.Lazy.unpack - let message = "The expected CBOR representation doesn't match the actual one"- Tasty.HUnit.assertEqual message encoded bytes+ Monad.unless (encoded == bytes) $ do+ let message = "The expected CBOR representation doesn't match the actual one\n"+ ++ "expected: " ++ render encoded ++ "\n but got: " ++ render bytes+ ++ "\n expr: " ++ show (Core.denote expression :: Expr Void Import) + Tasty.HUnit.assertFailure message++ shouldNotParse :: Text -> TestTree shouldNotParse path = do+ let expectedFailures =+ [ parseDirectory </> "failure/spacing/LetNoSpace4.dhall"+ ]+ let pathString = Text.unpack path - Tasty.HUnit.testCase pathString (do- text <- Text.IO.readFile pathString+ Test.Util.testCase path expectedFailures (do+ bytes <- ByteString.readFile pathString - case Parser.exprFromText mempty text of- Left _ -> return ()- Right _ -> fail "Unexpected successful parser" )+ case Text.Encoding.decodeUtf8' bytes of+ Left _ -> return ()+ Right text ->+ case Parser.exprFromText mempty text of+ Left _ -> return ()+ Right _ -> Tasty.HUnit.assertFailure "Unexpected successful parse" ) shouldDecode :: Text -> TestTree shouldDecode pathText = do+ let expectedFailures =+ [ {- Note that this test actually successfully decodes the value, but+ mistakenly decodes the value to `_` instead of `x`. This is+ because the 55799 tag causes normal decoding to fail, so it falls+ back to treating the `"x"` as a version tag instead of a label.++ Either way, fixing 55799 decoding would cause this test to pass+ again.+ -}+ binaryDecodeDirectory </> "success/unit/SelfDescribeCBORX2"+ , binaryDecodeDirectory </> "success/unit/SelfDescribeCBORX3"+ ]+ let pathString = Text.unpack pathText - Tasty.HUnit.testCase pathString (do+ Test.Util.testCase pathText expectedFailures (do bytes <- ByteString.Lazy.readFile (pathString <> "A.dhallb") - term <- Core.throws (Serialise.deserialiseOrFail bytes)-- decodedExpression <- Core.throws (Binary.decodeExpression term)+ decodedExpression <- case Binary.decodeExpression bytes of+ Left exception ->+ Tasty.HUnit.assertFailure (show exception)+ Right decodedExpression ->+ return decodedExpression text <- Text.IO.readFile (pathString <> "B.dhall") parsedExpression <- Core.throws (Parser.exprFromText mempty text) - let strippedExpression :: Expr X Import+ let strippedExpression :: Expr Void Import strippedExpression = Core.denote parsedExpression let message = "The decoded expression didn't match the parsed expression" - Tasty.HUnit.assertEqual message decodedExpression strippedExpression )+ Tasty.HUnit.assertEqual message strippedExpression decodedExpression )++shouldNotDecode :: Text -> TestTree+shouldNotDecode pathText = do+ let expectedFailures = []++ let pathString = Text.unpack pathText++ Test.Util.testCase pathText expectedFailures (do+ bytes <- ByteString.Lazy.readFile (pathString <> ".dhallb")++ case Binary.decodeExpression bytes :: Either Binary.DecodingFailure (Expr Void Import) of+ Left _ -> return ()+ Right _ -> Tasty.HUnit.assertFailure "Unexpected successful decode" )
@@ -1,63 +1,118 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE StandaloneDeriving #-}+-- TODO: update because we added ShowConstructor constructor to Expr in Dhall.Syntax +{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-}+ {-# OPTIONS_GHC -fno-warn-orphans #-} +-- Build without optimizations to prevent out-of-memory situations in Hydra CI+{-# OPTIONS_GHC -O0 #-}+ module Dhall.Test.QuickCheck where -import Codec.Serialise (DeserialiseFailure(..))-import Data.Either (isRight)-import Data.List.NonEmpty (NonEmpty(..))-import Dhall.Map (Map)+import Data.Either (isRight)+import Data.Either.Validation (Validation (..))+import Data.Text (Text)+import Data.Void (Void)+import Dhall+ ( FromDhall (..)+ , ToDhall (..)+ , Vector+ , auto+ , embed+ , extract+ , inject+ ) import Dhall.Core- ( Binding(..)- , Chunks(..)- , Const(..)- , Directory(..)- , Expr(..)- , File(..)- , FilePrefix(..)- , Import(..)- , ImportHashed(..)- , ImportMode(..)- , ImportType(..)- , Scheme(..)- , URL(..)- , Var(..)+ ( Binding (..)+ , Chunks (..)+ , Const (..)+ , DhallDouble (..)+ , Directory (..)+ , Expr (..)+ , FieldSelection (..)+ , File (..)+ , FilePrefix (..)+ , FunctionBinding (..)+ , Import (..)+ , ImportHashed (..)+ , ImportMode (..)+ , ImportType (..)+ , PreferAnnotation (..)+ , RecordField (..)+ , Scheme (..)+ , URL (..)+ , Var (..)+ , WithComponent (..) )+import Dhall.Map (Map) -import Dhall.Set (Set)-import Dhall.Src (Src(..))-import Numeric.Natural (Natural)+import Data.Functor.Identity (Identity (..))+import Data.Proxy (Proxy (..))+import Data.Typeable (Typeable, typeRep)+import Dhall.Parser (Header (..), createHeader)+import Dhall.Pretty (CharacterSet (..))+import Dhall.Set (Set)+import Dhall.Src (Src (..))+import Dhall.Test.Format (format)+import Dhall.TypeCheck (TypeError, Typer)+import Generic.Random (ConstrGen (..), W, Weights, (%), (:+) (..)) import Test.QuickCheck- (Arbitrary(..), Gen, Positive(..), Property, genericShrink, (===), (==>))+ ( Arbitrary (..)+ , Gen+ , NonNegative (..)+ , Positive (..)+ , Property+ , genericShrink+ , suchThat+ , (===)+ , (==>)+ ) import Test.QuickCheck.Instances ()-import Test.Tasty (TestTree)-import Text.Megaparsec (SourcePos(..), Pos)+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (QuickCheckTests (..))+import Text.Megaparsec (Pos, SourcePos (..)) -import qualified Codec.Serialise-import qualified Data.Coerce+import qualified Control.Spoon+import qualified Data.Char+import qualified Data.Foldable as Foldable+import qualified Data.HashMap.Strict as HashMap+import qualified Data.HashSet import qualified Data.List-import qualified Dhall.Map+import qualified Data.Map import qualified Data.Sequence+import qualified Data.Set+import qualified Data.SpecialValues+import qualified Data.Text as Text+import qualified Data.Time as Time import qualified Dhall.Binary+import qualified Dhall.Context+import qualified Dhall.Core import qualified Dhall.Diff+import qualified Dhall.Map+import qualified Dhall.Parser as Parser import qualified Dhall.Set import qualified Dhall.TypeCheck+import qualified Generic.Random+import qualified Lens.Micro as Lens+import qualified Numeric.Natural as Nat import qualified Test.QuickCheck+import qualified Test.Tasty import qualified Test.Tasty.QuickCheck import qualified Text.Megaparsec as Megaparsec -newtype DeserialiseFailureWithEq = D DeserialiseFailure- deriving (Show)--instance Eq DeserialiseFailureWithEq where- D (DeserialiseFailure aL bL) == D (DeserialiseFailure aR bR) =- aL == aR && bL == bR- instance (Arbitrary a, Ord a) => Arbitrary (Set a) where arbitrary = Dhall.Set.fromList <$> arbitrary+ shrink = map Dhall.Set.fromList . shrink . Dhall.Set.toList lift0 :: a -> Gen a lift0 = pure@@ -108,13 +163,6 @@ <*> arbitrary <*> arbitrary -natural :: (Arbitrary a, Num a) => Gen a-natural =- Test.QuickCheck.frequency- [ (7, arbitrary)- , (1, fmap (\x -> x + (2 ^ (64 :: Int))) arbitrary)- ]- integer :: (Arbitrary a, Num a) => Gen a integer = Test.QuickCheck.frequency@@ -123,10 +171,59 @@ , (1, fmap (\x -> x - (2 ^ (64 :: Int))) arbitrary) ] -instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v) where+whitespace :: Gen Text+whitespace = do+ let commentChar =+ Test.QuickCheck.frequency+ [ (20, Test.QuickCheck.elements [' ' .. '\DEL'])+ , ( 1, arbitrary)+ ]++ noInteriorBlockComments text =+ not (Text.isInfixOf "{-" text || Text.isInfixOf "-}" text)++ commentText =+ suchThat+ (Text.pack <$> Test.QuickCheck.listOf commentChar)+ noInteriorBlockComments++ multiline = do+ txt <- commentText+ pure $ "{-" <> txt <> "-}"++ singleline = do+ txt <- commentText `suchThat` (not . Text.isInfixOf "\n")+ endOfLine <- Test.QuickCheck.elements ["\n", "\r\n"]+ pure $ "--" <> txt <> endOfLine++ newlines = Text.concat <$> Test.QuickCheck.listOf (pure "\n")++ comments <- do+ n <- Test.QuickCheck.choose (0, 2)+ Test.QuickCheck.vectorOf n $ Test.QuickCheck.oneof+ [ multiline+ , singleline+ , newlines+ ]++ pure $ Text.unlines comments++shrinkWhitespace :: Text -> [Text]+shrinkWhitespace "" = []+shrinkWhitespace _ = [""]++instance Arbitrary CharacterSet where+ arbitrary = Test.QuickCheck.elements [ ASCII, Unicode ]++instance Arbitrary Header where+ arbitrary = createHeader <$> whitespace++ shrink (Header text) = Header <$> shrinkWhitespace text++instance (Arbitrary v) => Arbitrary (Map Text v) where arbitrary = do n <- Test.QuickCheck.choose (0, 2)- kvs <- Test.QuickCheck.vectorOf n ((,) <$> arbitrary <*> arbitrary)+ kvs <- Test.QuickCheck.vectorOf n ((,) <$> label <*> arbitrary) -- Sorting the fields here because serialization needs them in order return (Dhall.Map.fromList (Data.List.sortOn fst kvs)) @@ -136,8 +233,21 @@ . Dhall.Map.toList instance (Arbitrary s, Arbitrary a) => Arbitrary (Binding s a) where- arbitrary = lift3 Binding+ arbitrary = do+ bindingSrc0 <- arbitrary + variable <- Test.QuickCheck.oneof [ pure "_", label ]++ bindingSrc1 <- arbitrary++ annotation <- arbitrary++ bindingSrc2 <- arbitrary++ value <- arbitrary++ return Binding{..}+ shrink = genericShrink instance (Arbitrary s, Arbitrary a) => Arbitrary (Chunks s a) where@@ -152,110 +262,210 @@ shrink = genericShrink +instance Arbitrary DhallDouble where+ arbitrary = fmap DhallDouble (Test.QuickCheck.oneof [ arbitrary, special ])+ where+ special = Test.QuickCheck.elements Data.SpecialValues.specialValues++ shrink = genericShrink+ instance Arbitrary Directory where arbitrary = lift1 Directory shrink = genericShrink -averageDepth :: Natural-averageDepth = 3+instance Arbitrary PreferAnnotation where+ arbitrary = Test.QuickCheck.oneof+ [ pure PreferFromSource+ , pure PreferFromCompletion+ ] -averageNumberOfSubExpressions :: Double-averageNumberOfSubExpressions = 1 - 1 / fromIntegral averageDepth+ shrink = genericShrink -probabilityOfNullaryConstructor :: Double-probabilityOfNullaryConstructor = 1 / fromIntegral averageDepth+instance (Arbitrary s, Arbitrary a) => Arbitrary (RecordField s a) where+ arbitrary = lift4 RecordField -numberOfConstructors :: Natural-numberOfConstructors = 50+ shrink = genericShrink +instance (Arbitrary s, Arbitrary a) => Arbitrary (FunctionBinding s a) where+ arbitrary = do+ l <- label+ type_ <- arbitrary+ return $ FunctionBinding Nothing l Nothing Nothing type_++ shrink = genericShrink++instance Arbitrary s => Arbitrary (FieldSelection s) where+ arbitrary = FieldSelection <$> pure Nothing <*> label <*> pure Nothing+ shrink = genericShrink++instance Arbitrary WithComponent where+ arbitrary =+ Test.QuickCheck.oneof [ pure WithQuestion, WithLabel <$> arbitrary ]+ instance (Arbitrary s, Arbitrary a) => Arbitrary (Expr s a) where arbitrary = Test.QuickCheck.suchThat- (Test.QuickCheck.frequency- [ ( 7, lift1 Const)- , ( 7, lift1 Var)- , ( 1, Test.QuickCheck.oneof [ lift2 (Lam "_"), lift3 Lam ])- , ( 1, Test.QuickCheck.oneof [ lift2 (Pi "_"), lift3 Pi ])- , ( 1, lift2 App)- , let letExpression = do- n <- Test.QuickCheck.choose (0, 2)- binding <- arbitrary- bindings <- Test.QuickCheck.vectorOf n arbitrary- body <- arbitrary- return (Let (binding :| bindings) body)- in ( 1, Test.QuickCheck.oneof [ letExpression ])- , ( 1, lift2 Annot)- , ( 7, lift0 Bool)- , ( 7, lift1 BoolLit)- , ( 1, lift2 BoolAnd)- , ( 1, lift2 BoolOr)- , ( 1, lift2 BoolEQ)- , ( 1, lift2 BoolNE)- , ( 1, lift3 BoolIf)- , ( 7, lift0 Natural)- , ( 7, fmap NaturalLit natural)- , ( 7, lift0 NaturalFold)- , ( 7, lift0 NaturalBuild)- , ( 7, lift0 NaturalIsZero)- , ( 7, lift0 NaturalEven)- , ( 7, lift0 NaturalOdd)- , ( 7, lift0 NaturalToInteger)- , ( 7, lift0 NaturalShow)- , ( 1, lift2 NaturalPlus)- , ( 1, lift2 NaturalTimes)- , ( 7, lift0 Integer)- , ( 7, fmap IntegerLit integer)- , ( 7, lift0 IntegerShow)- , ( 7, lift0 Double)- , ( 7, lift1 DoubleLit)- , ( 7, lift0 DoubleShow)- , ( 7, lift0 Text)- , ( 1, lift1 TextLit)- , ( 1, lift2 TextAppend)- , ( 7, lift0 List)- , let listLit = do- n <- Test.QuickCheck.choose (0, 3)- xs <- Test.QuickCheck.vectorOf n arbitrary- let ys = Data.Sequence.fromList xs- ListLit <$> arbitrary <*> pure ys+ (Generic.Random.withBaseCase+ (Generic.Random.genericArbitraryRecG customGens weights)+ (Var <$> arbitrary)+ )+ standardizedExpression+ where+ customGens+ :: ConstrGen "Lam" 1 (FunctionBinding s a)+ :+ ConstrGen "Pi" 1 Text+ :+ ConstrGen "Field" 1 (FieldSelection s)+ :+ ConstrGen "Project" 1 (Either [Text] (Expr s a))+ :+ Gen Integer -- Generates all Integer fields in Expr+ :+ Gen Text -- Generates all Text fields in Expr+ :+ ()+ customGens =+ ConstrGen arbitrary+ :+ ConstrGen label+ :+ ConstrGen arbitrary+ :+ ConstrGen projection+ :+ integer+ -- 'Lam's and 'Pi's are encoded differently when the binding is+ -- the special string "_", so we generate some of these strings+ -- to improve test coverage for these code paths.+ :+ Test.QuickCheck.oneof [pure "_", arbitrary]+ :+ () - in ( 1, listLit)- , ( 1, lift2 ListAppend)- , ( 7, lift0 ListBuild)- , ( 7, lift0 ListFold)- , ( 7, lift0 ListLength)- , ( 7, lift0 ListHead)- , ( 7, lift0 ListLast)- , ( 7, lift0 ListIndexed)- , ( 7, lift0 ListReverse)- , ( 7, lift0 Optional)- , ( 1, lift2 OptionalLit)- , ( 7, lift0 OptionalFold)- , ( 7, lift0 OptionalBuild)- , ( 1, lift1 Record)- , ( 1, lift1 RecordLit)- , ( 1, lift1 Union)- , ( 1, lift3 UnionLit)- , ( 1, lift2 Combine)- , ( 1, lift2 CombineTypes)- , ( 1, lift2 Prefer)- , ( 1, lift3 Merge)- , ( 1, lift2 Field)- , ( 1, lift2 Project)- , ( 7, lift1 Embed)+ projection =+ Test.QuickCheck.oneof+ [ fmap Left (Test.QuickCheck.listOf label)+ , arbitrary ]- )- standardizedExpression + -- These weights determine the frequency of constructors in the generated+ -- Expr.+ -- They will fail to compile if the constructors don't appear in the order+ -- in which they are defined in 'Expr'!+ weights :: Weights (Expr s a)+ weights =+ (7 :: W "Const")+ % (7 :: W "Var")+ % (7 :: W "Lam")+ % (7 :: W "Pi")+ % (7 :: W "App")+ % (7 :: W "Let")+ % (1 :: W "Annot")+ % (1 :: W "Bool")+ % (7 :: W "BoolLit")+ % (1 :: W "BoolAnd")+ % (1 :: W "BoolOr")+ % (1 :: W "BoolEQ")+ % (1 :: W "BoolNE")+ % (1 :: W "BoolIf")+ % (1 :: W "Bytes")+ % (1 :: W "BytesLit")+ % (1 :: W "Natural")+ % (7 :: W "NaturalLit")+ % (1 :: W "NaturalFold")+ % (1 :: W "NaturalBuild")+ % (1 :: W "NaturalIsZero")+ % (1 :: W "NaturalEven")+ % (1 :: W "NaturalOdd")+ % (1 :: W "NaturalToInteger")+ % (1 :: W "NaturalShow")+ % (1 :: W "NaturalSubtract")+ % (1 :: W "NaturalPlus")+ % (1 :: W "NaturalTimes")+ % (1 :: W "Integer")+ % (7 :: W "IntegerLit")+ % (1 :: W "IntegerClamp")+ % (1 :: W "IntegerNegate")+ % (1 :: W "IntegerShow")+ % (1 :: W "IntegerToDouble")+ % (1 :: W "Double")+ % (7 :: W "DoubleLit")+ % (1 :: W "DoubleShow")+ % (1 :: W "Text")+ % (1 :: W "TextLit")+ % (1 :: W "TextAppend")+ % (1 :: W "TextReplace")+ % (1 :: W "TextShow")+ % (1 :: W "Date")+ % (1 :: W "DateLiteral")+ % (1 :: W "DateShow")+ % (1 :: W "Time")+ % (1 :: W "TimeLiteral")+ % (1 :: W "TimeShow")+ % (1 :: W "TimeZone")+ % (1 :: W "TimeZoneLiteral")+ % (1 :: W "TimeZoneShow")+ % (1 :: W "List")+ % (1 :: W "ListLit")+ % (1 :: W "ListAppend")+ % (1 :: W "ListBuild")+ % (1 :: W "ListFold")+ % (1 :: W "ListLength")+ % (1 :: W "ListHead")+ % (1 :: W "ListLast")+ % (1 :: W "ListIndexed")+ % (1 :: W "ListReverse")+ % (1 :: W "Optional")+ % (7 :: W "Some")+ % (1 :: W "None")+ % (1 :: W "Record")+ % (7 :: W "RecordLit")+ % (1 :: W "Union")+ % (7 :: W "Combine")+ % (1 :: W "CombineTypes")+ % (7 :: W "Prefer")+ % (7 :: W "RecordCompletion")+ % (1 :: W "Merge")+ % (1 :: W "ToMap")+ % (1 :: W "ShowConstructor")+ % (7 :: W "Field")+ % (7 :: W "Project")+ % (1 :: W "Assert")+ % (1 :: W "Equivalent")+ % (1 :: W "With")+ % (0 :: W "Note")+ % (7 :: W "ImportAlt")+ % (7 :: W "Embed")+ % ()+ shrink expression = filter standardizedExpression (genericShrink expression) standardizedExpression :: Expr s a -> Bool-standardizedExpression (ListLit Nothing xs) = not (Data.Sequence.null xs)-standardizedExpression (ListLit (Just _ ) xs) = Data.Sequence.null xs-standardizedExpression (Note _ _ ) = False-standardizedExpression _ = True+standardizedExpression (ListLit Nothing xs) =+ not (Data.Sequence.null xs)+standardizedExpression (ListLit (Just _ ) xs) =+ Data.Sequence.null xs+standardizedExpression (Note _ _) =+ False+standardizedExpression (Combine _ (Just _) _ _) =+ False+standardizedExpression With{} =+ False+standardizedExpression (Prefer _ PreferFromCompletion _ _) =+ False+-- The following three expressions are valid ASTs, but they can never be parsed,+-- because the annotation will associate with `Merge`/`ListLit`/`ToMap` with+-- higher precedence+standardizedExpression (Annot (Merge _ _ Nothing) _) =+ False+standardizedExpression (Annot (ListLit Nothing _) _) =+ False+standardizedExpression (Annot (ToMap _ Nothing) _) =+ False+standardizedExpression (TimeZoneLiteral (Time.TimeZone _ b t)) =+ not b && null t+standardizedExpression (TimeLiteral (Time.TimeOfDay _ _ ss) precision) =+ isInteger (ss * magnitude)+ where+ magnitude = 10 ^ precision + isInteger x = x == fromInteger (round x)+standardizedExpression _ =+ True++chooseCharacter :: (Char, Char) -> Gen Char+chooseCharacter = Test.QuickCheck.chooseEnum+ instance Arbitrary File where arbitrary = lift2 File @@ -267,9 +477,13 @@ shrink = genericShrink instance Arbitrary Src where- arbitrary = lift3 Src+ arbitrary = do+ lift2 Src <*> whitespace - shrink = genericShrink+ shrink (Src start end text) =+ (Src <$> shrink start <*> pure end <*> pure text)+ ++ (Src <$> pure start <*> shrink end <*> pure text)+ ++ (Src <$> pure start <*> pure end <*> shrinkWhitespace text) instance Arbitrary SourcePos where arbitrary = lift3 SourcePos@@ -282,8 +496,21 @@ instance Arbitrary ImportType where arbitrary = Test.QuickCheck.oneof- [ lift2 Local- , lift5 (\a b c d e -> Remote (URL a b c d e))+ [ do prefix <- arbitrary++ let nonEmptyText =+ fmap Text.pack (Test.QuickCheck.listOf1 arbitrary)++ components <- Test.QuickCheck.listOf nonEmptyText++ file <- nonEmptyText++ let directory = Directory{ components }++ let path = File{ file, directory }++ return (Local prefix path)+ , lift1 Remote , lift1 Env , lift0 Missing ]@@ -302,7 +529,7 @@ -- The standard does not yet specify how to encode `as Text`, so don't test it -- yet instance Arbitrary ImportMode where- arbitrary = lift0 Code+ arbitrary = Test.QuickCheck.elements [ Code, RawText, Location, RawBytes ] shrink = genericShrink @@ -317,64 +544,259 @@ shrink = genericShrink instance Arbitrary URL where- arbitrary = lift5 URL+ arbitrary = do+ scheme <- arbitrary - shrink = genericShrink+ -- TODO: the authority generator could be more precise, but it currently+ -- seems good enough.+ let validAuthorityChar =+ arbitrary `suchThat` \ch ->+ not (Data.Char.isSpace ch) && not (Data.Char.isPunctuation ch) + authority <- Text.pack <$> Test.QuickCheck.listOf validAuthorityChar++ let validPChar =+ Test.QuickCheck.frequency+ [ (26, chooseCharacter ('A', 'Z'))+ , (26, chooseCharacter ('a', 'z'))+ , (10, chooseCharacter ('0', '9'))+ , (17, Test.QuickCheck.elements "-._~!$&'*+;=:@")+ ]++ let component = fmap Text.pack (Test.QuickCheck.listOf validPChar)++ components <- Test.QuickCheck.listOf component++ file <- component++ let directory = Directory{ components }++ let path = File{ file, directory }++ let validQueryCharacters =+ Test.QuickCheck.frequency+ [ (79, validPChar)+ , ( 2, Test.QuickCheck.elements "/?")+ ]++ query <- Test.QuickCheck.oneof+ [ pure Nothing+ , fmap (Just . Text.pack) (Test.QuickCheck.listOf validQueryCharacters)+ ]++ headers <- arbitrary++ return URL{..}++ shrink _ = []+ instance Arbitrary Var where arbitrary = Test.QuickCheck.oneof- [ fmap (V "_") (fromIntegral <$> (natural :: Gen Int))- , lift1 (\t -> V t 0)- , lift1 V <*> (fromIntegral <$> (natural :: Gen Int))+ [ fmap (V "_") (getNonNegative <$> arbitrary)+ , fmap (\t -> V t 0) label+ , V <$> label <*> (getNonNegative <$> arbitrary) ]- shrink = genericShrink +label :: Gen Text+label = fmap Text.pack (Test.QuickCheck.listOf labelCharacter)+ where+ labelCharacter =+ Test.QuickCheck.frequency+ [ (64, chooseCharacter ('\x20', '\x5F'))+ , (30, chooseCharacter ('\x61', '\x7e'))+ ]+ binaryRoundtrip :: Expr () Import -> Property binaryRoundtrip expression =- wrap- (fmap- Dhall.Binary.decodeExpression- (Codec.Serialise.deserialiseOrFail- (Codec.Serialise.serialise- (Dhall.Binary.encodeExpression expression)- )- )- )- === wrap (Right (Right expression))+ Dhall.Binary.decodeExpression (Dhall.Binary.encodeExpression denotedExpression)+ === Right denotedExpression where- wrap- :: Either DeserialiseFailure a- -> Either DeserialiseFailureWithEq a- wrap = Data.Coerce.coerce+ denotedExpression :: Expr Void Import+ denotedExpression = denote' expression --- isNormalizedIsConsistentWithNormalize :: Expr () Import -> Property--- isNormalizedIsConsistentWithNormalize expression =--- Dhall.Core.isNormalized expression--- === (Dhall.Core.normalize expression == expression)+ denote' :: Expr a Import -> Expr b Import+ denote' = Dhall.Core.denote . fmap denoteHttpHeaders + denoteHttpHeaders import_@(Import importHashed _)+ | Remote url <- importType importHashed+ = let headers' = denote' <$> headers url+ importType' = Remote url { headers = headers' }+ importHashed' = importHashed { importType = importType' }+ in import_ {importHashed = importHashed'}+ | otherwise = import_++everythingWellTypedNormalizes :: Expr () () -> Property+everythingWellTypedNormalizes expression =+ isRight (Dhall.TypeCheck.typeWithA filterOutEmbeds Dhall.Context.empty expression)+ ==> Test.QuickCheck.total (Dhall.Core.normalize expression :: Expr () ())+ where+ filterOutEmbeds :: Typer a+ filterOutEmbeds _ = Const Sort -- This could be any ill-typed expression.++isNormalizedIsConsistentWithNormalize :: Expr () Import -> Property+isNormalizedIsConsistentWithNormalize expression =+ case maybeProp of+ Nothing -> Test.QuickCheck.discard+ Just v -> v+ where+ denotedExpression :: Expr Void Import+ denotedExpression = Dhall.Core.denote expression++ maybeProp = do+ nf <- Control.Spoon.spoon (Dhall.Core.normalize expression)+ isNormalized <- Control.Spoon.spoon (Dhall.Core.isNormalized expression)+ -- Dhall.Core.isNormalized ignores 'Note's and other annotations.+ -- So we do the same when checking the result of 'normalize'.+ return $ isNormalized === (nf == denotedExpression)++normalizeWithMIsConsistentWithNormalize :: Expr () Import -> Property+normalizeWithMIsConsistentWithNormalize expression =+ case Control.Spoon.spoon (nfM, nf) of+ Just (a, b) -> a === b+ Nothing -> Test.QuickCheck.discard+ where nfM = runIdentity (Dhall.Core.normalizeWithM (\_ -> Identity Nothing) expression)+ nf = Dhall.Core.normalize expression :: Expr () Import+ isSameAsSelf :: Expr () Import -> Property isSameAsSelf expression =- hasNoImportAndTypechecks ==> Dhall.Diff.same (Dhall.Diff.diffExpression expression expression)- where hasNoImportAndTypechecks =+ hasNoImportAndTypechecks ==> Dhall.Diff.same (Dhall.Diff.diff denoted denoted)+ where denoted = Dhall.Core.denote expression+ hasNoImportAndTypechecks = case traverse (\_ -> Left ()) expression of Right importlessExpression -> isRight (Dhall.TypeCheck.typeOf importlessExpression) Left _ -> False +inferredTypesAreNormalized :: Expr () Import -> Property+inferredTypesAreNormalized expression =+ Test.Tasty.QuickCheck.counterexample report (all Dhall.Core.isNormalized result)+ where+ report = "Got: " ++ show result+ ++ "\nExpected: " ++ show (fmap Dhall.Core.normalize result+ :: Either (TypeError () Import) (Expr () Import))++ result = Dhall.TypeCheck.typeWithA filterOutEmbeds Dhall.Context.empty expression++ filterOutEmbeds :: Typer a+ filterOutEmbeds _ = Const Sort -- This could be any ill-typed expression.++normalizingAnExpressionDoesntChangeItsInferredType :: Expr () Import -> Property+normalizingAnExpressionDoesntChangeItsInferredType expression =+ case (eT0, eT1) of+ (Right t0, Right t1) -> t0 === t1+ _ -> Test.QuickCheck.discard+ where+ eT0 = typeCheck expression+ eT1 = typeCheck (Dhall.Core.normalize expression)++ typeCheck = Dhall.TypeCheck.typeWithA filterOutEmbeds Dhall.Context.empty++ filterOutEmbeds :: Typer a+ filterOutEmbeds _ = Const Sort -- This could be any ill-typed expression.++noDoubleNotes :: Expr () Import -> Property+noDoubleNotes expression =+ length+ [ ()+ | e <- Foldable.toList parsedExpression+ , Note _ (Note _ _) <- Lens.toListOf Dhall.Core.subExpressions e+ ] === 0+ where+ text = Dhall.Core.pretty expression++ parsedExpression = Parser.exprFromText "" text++embedThenExtractIsIdentity+ :: forall a. (ToDhall a, FromDhall a, Eq a, Typeable a, Arbitrary a, Show a)+ => Proxy a+ -> (String, Property, TestTree -> TestTree)+embedThenExtractIsIdentity p =+ ( "Embedding then extracting is identity for " ++ show (typeRep p)+ , Test.QuickCheck.property (prop :: a -> Bool)+ , adjustQuickCheckTests 1000+ )+ where+ prop a = case extract auto (embed inject a) of+ Success a' -> a == a'+ Failure _ -> False++idempotenceTest :: CharacterSet -> Header -> Expr Src Import -> Property+idempotenceTest characterSet header expr =+ not (any hasHttpHeaders expr)+ ==> let once = format characterSet (header, expr)+ in case Parser.exprAndHeaderFromText mempty once of+ Right (format characterSet -> twice) -> once === twice+ Left _ -> Test.QuickCheck.discard+ where+ -- Workaround for https://github.com/dhall-lang/dhall-haskell/issues/1925.+ hasHttpHeaders = \case+ Import (ImportHashed _ (Remote (URL { headers = Just _ }))) _ -> True+ _ -> False+ tests :: TestTree tests =- Test.Tasty.QuickCheck.testProperties+ testProperties' "QuickCheck" [ ( "Binary serialization should round-trip" , Test.QuickCheck.property binaryRoundtrip+ , adjustQuickCheckTests 100 )- -- , ( "isNormalized should be consistent with normalize"- -- , Test.QuickCheck.property- -- (Test.QuickCheck.withMaxSuccess 10000 isNormalizedIsConsistentWithNormalize)- -- )+ , ( "everything well-typed should normalize"+ , Test.QuickCheck.property everythingWellTypedNormalizes+ , adjustQuickCheckTests 100000+ )+ , ( "isNormalized should be consistent with normalize"+ , Test.QuickCheck.property isNormalizedIsConsistentWithNormalize+ , adjustQuickCheckTests 10000+ )+ , ( "normalizeWithM should be consistent with normalize"+ , Test.QuickCheck.property normalizeWithMIsConsistentWithNormalize+ , adjustQuickCheckTests 10000+ ) , ( "An expression should have no difference with itself"- , Test.QuickCheck.property- (Test.QuickCheck.withMaxSuccess 10000 isSameAsSelf)+ , Test.QuickCheck.property isSameAsSelf+ , adjustQuickCheckTests 10000 )+ , ( "Inferred types should be normalized"+ , Test.QuickCheck.property inferredTypesAreNormalized+ , adjustQuickCheckTests 10000+ )+ , ( "Normalizing an expression doesn't change its inferred type"+ , Test.QuickCheck.property normalizingAnExpressionDoesntChangeItsInferredType+ , adjustQuickCheckTests 10000+ )+ , ( "Parsing an expression doesn't generated doubly-nested Note constructors"+ , Test.QuickCheck.property noDoubleNotes+ , adjustQuickCheckTests 100+ )+ , embedThenExtractIsIdentity (Proxy :: Proxy (Text))+ , embedThenExtractIsIdentity (Proxy :: Proxy [Nat.Natural])+ , embedThenExtractIsIdentity (Proxy :: Proxy (Bool, Double))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Data.Sequence.Seq ()))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Maybe Integer))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Data.Set.Set Nat.Natural))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Data.HashSet.HashSet Text))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Vector Double))+ , embedThenExtractIsIdentity (Proxy :: Proxy (Data.Map.Map Double Bool))+ , embedThenExtractIsIdentity (Proxy :: Proxy (HashMap.HashMap Double Bool))+ , ( "Formatting should be idempotent"+ , Test.QuickCheck.property idempotenceTest+ , adjustQuickCheckTests 10000+ ) ]++adjustQuickCheckMaxRatio :: Int -> TestTree -> TestTree+adjustQuickCheckMaxRatio maxSize =+ Test.Tasty.adjustOption (max $ Test.Tasty.QuickCheck.QuickCheckMaxRatio maxSize)++adjustQuickCheckTests :: Int -> TestTree -> TestTree+adjustQuickCheckTests nTests =+ -- Using adjustOption instead of withMaxSuccess allows us to override the number of tests+ -- with the --quickcheck-tests CLI option.+ Test.Tasty.adjustOption (max $ QuickCheckTests nTests)++testProperties' :: String -> [(String, Property, TestTree -> TestTree)] -> TestTree+testProperties' name = Test.Tasty.testGroup name . map f+ where+ f (n, p, adjust) = adjust (Test.Tasty.QuickCheck.testProperty n p)
@@ -1,31 +1,37 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} module Dhall.Test.Regression where +import Data.Either.Validation (Validation (..))+import Data.Void (Void)+import Dhall.Core (Expr (..), ReifiedNormalizer (..))+import Dhall.Import (Imported, MissingImports (..))+import Dhall.Parser (SourcedException (..), Src)+import Dhall.TypeCheck (TypeError)+import Test.Tasty (TestTree)+import Test.Tasty.HUnit ((@?=))+ import qualified Control.Exception+import qualified Data.Text.IO import qualified Data.Text.Lazy.IO-import qualified Data.Text.Prettyprint.Doc-import qualified Data.Text.Prettyprint.Doc.Render.Text import qualified Dhall-import qualified Dhall.Context+import qualified Dhall.Context as Context import qualified Dhall.Core import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty-import qualified Dhall.Test.Util as Util+import qualified Dhall.Test.Util as Util import qualified Dhall.TypeCheck+import qualified Lens.Micro as Lens+import qualified Prettyprinter+import qualified Prettyprinter.Render.Text import qualified System.Timeout import qualified Test.Tasty import qualified Test.Tasty.HUnit -import Dhall.Import (Imported)-import Dhall.Parser (Src)-import Dhall.TypeCheck (TypeError, X)-import Test.Tasty (TestTree)-import Test.Tasty.HUnit ((@?=))- tests :: TestTree tests = Test.Tasty.testGroup "regression tests"@@ -36,6 +42,15 @@ , issue201 , issue216 , issue253+ , issue1131a+ , issue1131b+ , issue1341+ , issue1584+ , issue1646+ , issue1732+ , issue1884+ , issue2088+ , issue2463 , parsing0 , typeChecking0 , typeChecking1@@ -45,33 +60,43 @@ ] data Foo = Foo Integer Bool | Bar Bool Bool Bool | Baz Integer Integer- deriving (Show, Dhall.Generic, Dhall.Interpret, Dhall.Inject)+ deriving (Show, Dhall.Generic, Dhall.FromDhall, Dhall.ToDhall) unnamedFields :: TestTree unnamedFields = Test.Tasty.HUnit.testCase "Unnamed Fields" (do- let ty = Dhall.auto :: Dhall.Type Foo+ let ty = Dhall.auto :: Dhall.Decoder Foo Test.Tasty.HUnit.assertEqual "Good type" (Dhall.expected ty)- (Dhall.Core.Union+ (Success (Dhall.Core.Union (Dhall.Map.fromList- [ ("Foo",Just (Dhall.Core.Record (Dhall.Map.fromList [- ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool)])))- , ("Bar",Just (Dhall.Core.Record (Dhall.Map.fromList [- ("_1",Dhall.Core.Bool),("_2",Dhall.Core.Bool),("_3",Dhall.Core.Bool)])))- , ("Baz",Just (Dhall.Core.Record (Dhall.Map.fromList [- ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Integer)])))+ [ ("Foo",Just (Dhall.Core.Record (Dhall.Map.fromList+ [ ("_1", Dhall.Core.makeRecordField Dhall.Core.Integer)+ , ("_2", Dhall.Core.makeRecordField Dhall.Core.Bool)+ ])))+ , ("Bar",Just (Dhall.Core.Record (Dhall.Map.fromList+ [ ("_1", Dhall.Core.makeRecordField Dhall.Core.Bool)+ , ("_2", Dhall.Core.makeRecordField Dhall.Core.Bool)+ , ("_3", Dhall.Core.makeRecordField Dhall.Core.Bool)+ ])))+ , ("Baz",Just (Dhall.Core.Record (Dhall.Map.fromList+ [ ("_1", Dhall.Core.makeRecordField Dhall.Core.Integer)+ , ("_2", Dhall.Core.makeRecordField Dhall.Core.Integer)+ ]))) ] )- )+ )) - let inj = Dhall.inject :: Dhall.InputType Foo- Test.Tasty.HUnit.assertEqual "Good Inject" (Dhall.declared inj) (Dhall.expected ty)+ let inj = Dhall.inject :: Dhall.Encoder Foo+ Test.Tasty.HUnit.assertEqual "Good ToDhall" (Success $ Dhall.declared inj) (Dhall.expected ty) - let tu_ty = Dhall.auto :: Dhall.Type (Integer, Bool)- Test.Tasty.HUnit.assertEqual "Auto Tuple" (Dhall.expected tu_ty) (Dhall.Core.Record (- Dhall.Map.fromList [ ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool) ]))+ let tu_ty = Dhall.auto :: Dhall.Decoder (Integer, Bool)+ Test.Tasty.HUnit.assertEqual "Auto Tuple" (Dhall.expected tu_ty) (Success $ Dhall.Core.Record (+ Dhall.Map.fromList+ [ ("_1", Dhall.Core.makeRecordField Dhall.Core.Integer)+ , ("_2", Dhall.Core.makeRecordField Dhall.Core.Bool)+ ])) - let tu_in = Dhall.inject :: Dhall.InputType (Integer, Bool)- Test.Tasty.HUnit.assertEqual "Inj. Tuple" (Dhall.declared tu_in) (Dhall.expected tu_ty)+ let tu_in = Dhall.inject :: Dhall.Encoder (Integer, Bool)+ Test.Tasty.HUnit.assertEqual "Inj. Tuple" (Success $ Dhall.declared tu_in) (Dhall.expected tu_ty) return () ) @@ -89,8 +114,13 @@ issue151 :: TestTree issue151 = Test.Tasty.HUnit.testCase "Issue #151" (do let shouldNotTypeCheck text = do- let handler :: Imported (TypeError Src X) -> IO Bool- handler _ = return True+ let handler :: SourcedException MissingImports -> IO Bool+ handler (SourcedException _ (MissingImports [e])) =+ case Control.Exception.fromException e :: Maybe (Imported (TypeError Src Void)) of+ Just _ -> return True+ Nothing -> return False+ handler _ =+ return True let typeCheck = do _ <- Util.code text@@ -133,10 +163,11 @@ issue216 :: TestTree issue216 = Test.Tasty.HUnit.testCase "Issue #216" (do -- Verify that pretty-printing preserves string interpolation- e <- Util.code "./tests/regression/issue216a.dhall"- let doc = Data.Text.Prettyprint.Doc.pretty e- let docStream = Data.Text.Prettyprint.Doc.layoutSmart Dhall.Pretty.layoutOpts doc- let text0 = Data.Text.Prettyprint.Doc.Render.Text.renderLazy docStream+ source <- Data.Text.IO.readFile "./tests/regression/issue216b.dhall"+ e <- Util.code source+ let doc = Prettyprinter.pretty e+ let docStream = Dhall.Pretty.layout doc+ let text0 = Prettyprinter.Render.Text.renderLazy docStream text1 <- Data.Text.Lazy.IO.readFile "./tests/regression/issue216b.dhall" @@ -145,7 +176,7 @@ issue253 :: TestTree issue253 = Test.Tasty.HUnit.testCase "Issue #253" (do -- Verify that type-checking rejects ill-formed custom contexts- let context = Dhall.Context.insert "x" "x" Dhall.Context.empty+ let context = Context.insert "x" "x" Context.empty let result = Dhall.TypeCheck.typeWith context "x" -- If the context is not validated correctly then type-checking will@@ -153,12 +184,80 @@ Just _ <- System.Timeout.timeout 1000000 (Control.Exception.evaluate $! result) return () ) +issue1131a :: TestTree+issue1131a = Test.Tasty.HUnit.testCase "Issue #1131 a"+ (Util.assertDoesntTypeCheck "toMap {=} : <>.x")++issue1131b :: TestTree+issue1131b = Test.Tasty.HUnit.testCase "Issue #1131 b"+ (Util.assertDoesntTypeCheck "toMap {=} : List {mapKey : Text, mapValue : 0}")++issue1341 :: TestTree+issue1341 = Test.Tasty.HUnit.testCase "Issue #1341" (do+ let nan = Dhall.Core.DoubleLit (Dhall.Core.DhallDouble (0/0)) :: Dhall.Core.Expr () ()+ let actual = Dhall.Core.V "x" 0 `Dhall.Core.freeIn` nan+ let msg = "NaN shouldn't contain any free variables"+ Test.Tasty.HUnit.assertEqual msg False actual)++issue1584 :: TestTree+issue1584 = Test.Tasty.HUnit.testCase "Issue #1584" (do+ -- This test ensures that we can parse variables with keyword prefixes+ -- (e.g. `ifX`)+ _ <- Util.code "./tests/regression/issue1584.dhall"+ return () )++issue1646 :: TestTree+issue1646 = Test.Tasty.HUnit.testCase "Issue #1646" (do+ -- This test ensures that the parser doesn't eagerly consume trailing+ -- whitespace after a `Double`+ _ <- Util.code "./tests/regression/issue1646.dhall"+ return () )++issue1732 :: TestTree+issue1732 = Test.Tasty.HUnit.testCase "Issue #1732" (do+ -- This test ensures that the parser allows whitespace after a record pun+ -- entry+ _ <- Util.code "./tests/regression/issue1732.dhall"+ return () )++issue1884 :: TestTree+issue1884 = Test.Tasty.HUnit.testCase "Issue #1884" (do+ -- This test ensures that the parser allows a parenthesized application+ -- expression as the first argument to a with expression+ _ <- Util.code "./tests/regression/issue1884.dhall"+ return () )++issue2088 :: TestTree+issue2088 = Test.Tasty.HUnit.testCase "Issue #2088" (do+ -- This test ensures that the parser for projection by labels doesn't+ -- accidentally swallow trailing commas OUTSIDE of the projection+ _ <- Util.code "./tests/regression/issue2088.dhall"+ return () )++issue2463 :: TestTree+issue2463 = Test.Tasty.HUnit.testCase "Issue #2463" (do+ let startingContext = Context.insert "foo" Integer Context.empty++ let normalizer (Var "foo") = Just (IntegerLit 0)+ normalizer _ = Nothing++ let inputSettings = transform Dhall.defaultInputSettings+ where+ transform =+ Lens.set Dhall.normalizer+ (Just (ReifiedNormalizer (pure . normalizer)))+ . Lens.set Dhall.startingContext startingContext++ x <- Dhall.inputWithSettings inputSettings Dhall.auto "foo"++ Test.Tasty.HUnit.assertEqual "" (0 :: Integer) x )+ parsing0 :: TestTree-parsing0 = Test.Tasty.HUnit.testCase "Parsing regression #0" (do+parsing0 = Test.Tasty.HUnit.testCase "Parsing regression #0" ( -- Verify that parsing should not fail -- -- In 267093f8cddf1c2f909f2d997c31fd0a7cb2440a I broke the parser when left- -- factoring the grammer by failing to handle the source tested by this+ -- factoring the grammar by failing to handle the source tested by this -- regression test. The root of the problem was that the parser was trying -- to parse `List ./Node` as `Field List "/Node"` instead of -- `App List (Embed (Path (File Homeless "./Node") Code))`. The latter is
@@ -0,0 +1,61 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Schemas where++import Data.Text (Text)+import Dhall.Parser (Header (..))+import Test.Tasty (TestTree)++import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Parser as Parser+import qualified Dhall.Pretty as Pretty+import qualified Dhall.Schemas as Schemas+import qualified Dhall.Test.Util as Test.Util+import qualified Prettyprinter as Doc+import qualified Prettyprinter.Render.Text as Doc.Render.Text+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++schemasDirectory :: FilePath+schemasDirectory = "./tests/schemas"++getTests :: IO TestTree+getTests = do+ schemasTests <- Test.Util.discover (Turtle.chars <* "A.dhall") schemaTest (Turtle.lstree schemasDirectory)++ return (Tasty.testGroup "schemas tests" [ schemasTests ])++format :: Header -> Core.Expr Parser.Src Core.Import -> Text+format (Header header) expr =+ let doc = Doc.pretty header+ <> Pretty.prettyCharacterSet Pretty.Unicode expr+ <> "\n"++ docStream = Pretty.layout doc+ in+ Doc.Render.Text.renderStrict docStream++schemaTest :: Text -> TestTree+schemaTest prefix =+ Tasty.HUnit.testCase (Text.unpack prefix) $ do+ let inputFile = Text.unpack (prefix <> "A.dhall")+ let outputFile = Text.unpack (prefix <> "B.dhall")++ inputText <- Text.IO.readFile inputFile++ (header, parsedInput) <- Core.throws (Parser.exprAndHeaderFromText mempty inputText)++ parsedSchema <- Core.throws (Parser.exprFromText mempty (Test.Util.toDhallPath (prefix <> "Schema.dhall")))++ actualExpression <- Schemas.rewriteWithSchemas parsedSchema parsedInput++ let actualText = format header actualExpression++ expectedText <- Text.IO.readFile outputFile++ let message = "The rewritten expression did not match the expected output"++ Tasty.HUnit.assertEqual message expectedText actualText
@@ -0,0 +1,45 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.SemanticHash where++import Data.Text (Text)+import Test.Tasty (TestTree)++import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Import as Import+import qualified Dhall.Parser as Parser+import qualified Dhall.Test.Util as Test.Util+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++hashDirectory :: FilePath+hashDirectory = "./dhall-lang/tests/semantic-hash"++getTests :: IO TestTree+getTests = do+ hashTests <- Test.Util.discover (Turtle.chars <* "A.dhall") hashTest (Turtle.lstree hashDirectory)++ return (Tasty.testGroup "semantic-hash tests" [ hashTests ])++hashTest :: Text -> TestTree+hashTest prefix =+ Tasty.HUnit.testCase (Text.unpack prefix) $ do+ let codeFile = Test.Util.toDhallPath (prefix <> "A.dhall")+ let hashFile = Test.Util.toDhallPath (prefix <> "B.hash")++ expr <- Core.throws (Parser.exprFromText mempty codeFile)++ resolved <- Import.load expr++ let normalized = Core.alphaNormalize (Core.normalize resolved)++ let actualHash = Import.hashExpressionToCode normalized++ expectedHash <- Text.stripEnd <$> Text.IO.readFile (Text.unpack hashFile)++ let message = "The hash did not match the expected hash."++ Tasty.HUnit.assertEqual message expectedHash actualHash
@@ -0,0 +1,38 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Substitution where++import Control.Exception (throwIO)+import Data.Void (Void)+import Dhall.Core (Expr (BoolLit, Var))+import Dhall.Src (Src)++import qualified Data.Either.Validation+import qualified Dhall+import qualified Dhall.Map+import qualified Lens.Micro as Lens++data Result = Failure Integer | Success String+ deriving (Eq, Dhall.Generic, Show)++instance Dhall.FromDhall Result++substituteResult :: FilePath -> IO Result+substituteResult fp = do+ rt <- resultType+ let evaluateSettings = Lens.over Dhall.substitutions (Dhall.Map.insert "Result" rt) Dhall.defaultEvaluateSettings+ Dhall.inputFileWithSettings evaluateSettings resultDecoder fp++resultDecoder :: Dhall.Decoder Result+resultDecoder = Dhall.auto++resultType :: IO (Expr Src Void)+resultType = case Dhall.expected resultDecoder of+ Data.Either.Validation.Failure e -> throwIO e+ Data.Either.Validation.Success x -> return x++substituteFoo :: FilePath -> IO Bool+substituteFoo fp = let+ evaluateSettings = Lens.set Dhall.substitutions (Dhall.Map.fromList [("Foo", Var "Bar"), ("Bar", BoolLit True)]) Dhall.defaultEvaluateSettings+ in Dhall.inputFileWithSettings evaluateSettings Dhall.auto fp
@@ -0,0 +1,219 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}++module Dhall.Test.TH where++import Control.Exception (throwIO)+import Data.Either.Validation (Validation (..))+import Data.Time (TimeOfDay (..), TimeZone (..), fromGregorian)+import Dhall.TH (HaskellType (..))+import Test.Tasty (TestTree)++import qualified Data.Text+import qualified Dhall+import qualified Dhall.TH+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit++Dhall.TH.makeHaskellTypeFromUnion "T" "./tests/th/example.dhall"++deriving instance Eq T+deriving instance Show T++Dhall.TH.makeHaskellTypes+ [ MultipleConstructors "Department" "./tests/th/Department.dhall"+ , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+ , SingleConstructor "TimeExample" "TimeExample" "./tests/th/Time.dhall"+ ]++deriving instance Eq Department+deriving instance Show Department++deriving instance Eq Employee+deriving instance Show Employee++deriving instance Eq TimeExample+deriving instance Show TimeExample++Dhall.TH.makeHaskellTypes+ [ SingleConstructor "Bar" "MakeBar" "(./tests/th/issue2066.dhall).Bar"+ , SingleConstructor "Foo" "MakeFoo" "(./tests/th/issue2066.dhall).Foo"+ , MultipleConstructors "Qux" "(./tests/th/issue2066.dhall).Qux"+ ]++deriving instance Eq Bar+deriving instance Show Bar++deriving instance Eq Foo+deriving instance Show Foo++deriving instance Eq Qux+deriving instance Show Qux++tests :: TestTree+tests = Tasty.testGroup "Template Haskell" [ makeHaskellTypeFromUnion ]++makeHaskellTypeFromUnion :: TestTree+makeHaskellTypeFromUnion = Tasty.HUnit.testCase "makeHaskellTypeFromUnion" $ do+ t0 <- Dhall.input Dhall.auto "let T = ./tests/th/example.dhall in T.A { x = True, y = [ \"ABC\" ] }"++ Tasty.HUnit.assertEqual "" t0 A{ x = True, y = [ "ABC" ] }++ t1 <- Dhall.input Dhall.auto "let T = ./tests/th/example.dhall in T.B (Some [ 1 ])"++ Tasty.HUnit.assertEqual "" t1 (B (Just [ 1 ]))++ t2 <- Dhall.input Dhall.auto "let T = ./tests/th/example.dhall in T.C"++ Tasty.HUnit.assertEqual "" t2 C++ employee <- Dhall.input Dhall.auto "let Department = ./tests/th/Department.dhall in { name = \"John\", department = Department.Marketing }"++ Tasty.HUnit.assertEqual "" employee MakeEmployee{ name = "John", department = Marketing }++ qux <- Dhall.input Dhall.auto "let T = ./tests/th/issue2066.dhall in T.Qux.Foo { foo = +2, bar = { baz = +3 } }"++ Tasty.HUnit.assertEqual "" qux (Foo MakeFoo{ foo = 2, bar = MakeBar{ baz = 3 } })++ timex <- Dhall.input Dhall.auto "let T = ./tests/th/Time.dhall in { txTime = 21:12:00, txDate = 1976-04-01, txTimeZone = +05:00 } : T"++ Tasty.HUnit.assertEqual "" timex TimeExample { txTime = tod, txDate = day, txTimeZone = tz}++ where+ tod = TimeOfDay { todHour = 21, todMin = 12, todSec = 0 }+ day = fromGregorian 1976 4 1+ tz = TimeZone { timeZoneMinutes = 300, timeZoneSummerOnly = False, timeZoneName = "" }+ ++Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("My" <>)+ , Dhall.TH.fieldModifier = ("my" <>) . Data.Text.toTitle+ })+ [ MultipleConstructors "MyT" "./tests/th/example.dhall"+ , MultipleConstructors "MyDepartment" "./tests/th/Department.dhall"+ , SingleConstructor "MyEmployee" "Employee" "./tests/th/Employee.dhall"+ ]++ +deriving instance Eq MyT+deriving instance Eq MyDepartment+deriving instance Eq MyEmployee+deriving instance Show MyT+deriving instance Show MyDepartment+deriving instance Show MyEmployee++ +Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("My" <>)+ , Dhall.TH.fieldModifier = ("my" <>) . Data.Text.toTitle+ , Dhall.TH.generateFromDhallInstance = False+ , Dhall.TH.generateToDhallInstance = False+ })+ [ SingleConstructor "MyHKSingle" "HKSingle" "./tests/th/HigherKindSingle.dhall"+ , MultipleConstructors "MyHKUnion" "./tests/th/HigherKindUnion.dhall"+ ]++type MyHKSingle_ = MyHKSingle Maybe Int+type MyHKUnion_ = MyHKUnion Bool Int++deriving instance Eq MyHKSingle_+deriving instance Show MyHKSingle_+deriving instance Dhall.Generic MyHKSingle_+instance Dhall.FromDhall MyHKSingle_+instance Dhall.ToDhall MyHKSingle_++deriving instance Eq MyHKUnion_+deriving instance Show MyHKUnion_+deriving instance Dhall.Generic MyHKUnion_+instance Dhall.FromDhall MyHKUnion_+instance Dhall.ToDhall MyHKUnion_++testMakeHaskellTypesWith :: TestTree+testMakeHaskellTypesWith = Tasty.HUnit.testCase "makeHaskellTypesWith" $ do+ let text0 = "let T = ./tests/th/example.dhall in T.A { x = True, y = [] : List Text }"+ ref0 = MyA{ myX = True, myY = [] }+ myTest text0 ref0++ let text1 = "let T = ./tests/th/example.dhall in T.B (None (List Natural))"+ ref1 = MyB Nothing+ myTest text1 ref1++ let text2 = "let T = ./tests/th/example.dhall in T.C"+ ref2 = MyC+ myTest text2 ref2++ let textDepartment = "let T = ./tests/th/Department.dhall in T.Sales"+ refDepartment = MySales+ myTest textDepartment refDepartment++ let textEmployee = "let T = ./tests/th/Department.dhall in T.Sales"+ refEmployee = MyEmployee{ myName = "", myDepartment = MySales }+ myTest textEmployee refEmployee++ let textHKSingle = "let T = (./tests/th/HigherKindSingle.dhall) Optional Int in T { foo = +1, bar = Some +2, bam = \"\" }"+ refHKSingle = MyHKSingle { myFoo = 1, myBar = Just 2, myBam = "" } :: MyHKSingle_+ myTest textHKSingle refHKSingle++ let textHKUnion0 = "let T = (./tests/th/HigherKindUnion.dhall) Bool Int in T.Foo True"+ refHKUnion0 = MyFoo True :: MyHKUnion_+ myTest textHKUnion0 refHKUnion0++ let textHKUnion1 = "let T = (./tests/th/HigherKindUnion.dhall) Bool Int in T.Bar +1"+ refHKUnion1 = MyBar 1 :: MyHKUnion_+ myTest textHKUnion1 refHKUnion1++ where+ myTest text ref = do+ expr <- Dhall.inputExpr text+ t <- case Dhall.extract Dhall.auto expr of+ Failure e -> throwIO e+ Success t -> return t++ Tasty.HUnit.assertEqual "" t ref+ Tasty.HUnit.assertEqual "" expr $ Dhall.embed Dhall.inject ref++Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("NoFromDhall" <>)+ , Dhall.TH.fieldModifier = ("noFromDhall" <>) . Data.Text.toTitle+ , Dhall.TH.generateFromDhallInstance = False+ })+ [ MultipleConstructors "NoFromDhallT" "./tests/th/example.dhall"+ ]++instance Dhall.FromDhall NoFromDhallT++Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("NoToDhall" <>)+ , Dhall.TH.fieldModifier = ("noToDhall" <>) . Data.Text.toTitle+ , Dhall.TH.generateToDhallInstance = False+ })+ [ MultipleConstructors "NoToDhallT" "./tests/th/example.dhall"+ ]++instance Dhall.ToDhall NoToDhallT++Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("NoInstances" <>)+ , Dhall.TH.fieldModifier = ("noInstances" <>) . Data.Text.toTitle+ , Dhall.TH.generateFromDhallInstance = False+ , Dhall.TH.generateToDhallInstance = False+ })+ [ MultipleConstructors "NoInstancesT" "./tests/th/example.dhall"+ ]++deriving instance Dhall.Generic NoInstancesT+instance Dhall.FromDhall NoInstancesT+instance Dhall.ToDhall NoInstancesT++Dhall.TH.makeHaskellTypesWith (Dhall.TH.defaultGenerateOptions+ { Dhall.TH.constructorModifier = ("Strict" <>)+ , Dhall.TH.fieldModifier = ("strict" <>) . Data.Text.toTitle+ , Dhall.TH.makeStrict = True+ })+ [ MultipleConstructors "StrictFields" "./tests/th/example.dhall"+ ]
@@ -0,0 +1,63 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Tags where++import Data.Text (Text)+import Dhall.Util (Input (..))+import System.FilePath ((</>))+import Test.Tasty (TestTree)++import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Tags as Tags+import qualified Dhall.Test.Util as Test.Util+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++tagsDirectory :: FilePath+tagsDirectory = "./tests/tags"++getTests :: IO TestTree+getTests = do+ tagsTests <- Test.Util.discover (Turtle.chars <* ".dhall") tagsTest (Turtle.lstree tagsDirectory)++ let testTree = Tasty.testGroup "tags tests" [ tagsTests, tagsDirTest ]++ return testTree++tagsTest :: Text -> TestTree+tagsTest prefix =+ Tasty.HUnit.testCase (Text.unpack prefix) $ do+ -- The use of toDhallPah is a hack to ensure we always get the same file+ -- paths, i.e. ones with a '.' prefixed and UNIX path separators.+ let inputFile = Text.unpack (Test.Util.toDhallPath prefix <> ".dhall")+ let outputFile = Text.unpack (prefix <> ".tags")++ actualTags <- fixPathSeparators <$> Tags.generate (InputFile inputFile) Nothing False++ expectedTags <- Text.IO.readFile outputFile++ let message = "The actual tags did not match the expected tags"++ Tasty.HUnit.assertEqual message expectedTags actualTags++tagsDirTest :: TestTree+tagsDirTest =+ Tasty.HUnit.testCase "all" $ do+ let outputFile = Text.unpack . Turtle.format Turtle.fp $ tagsDirectory </> "all.tags"++ actualTags <- fmap fixPathSeparators+ (Tags.generate+ (InputFile (Text.unpack . Turtle.format Turtle.fp $ tagsDirectory))+ (Just [".dhall"])+ False)++ expectedTags <- Text.IO.readFile outputFile++ let message = "The actual tags did not match the expected tags for directory test"++ Tasty.HUnit.assertEqual message expectedTags actualTags++fixPathSeparators :: Text -> Text+fixPathSeparators = Text.replace "\\" "/"
@@ -6,16 +6,16 @@ import qualified Data.Vector import qualified Dhall-import qualified Dhall.Test.Util as Util+import qualified Dhall.Test.Substitution as Substitution+import qualified Dhall.Test.Util as Util import qualified Test.Tasty import qualified Test.Tasty.HUnit -import Data.Monoid ((<>))-import Data.Text (Text)-import Dhall (Inject)-import GHC.Generics (Generic)-import Numeric.Natural (Natural)-import Test.Tasty (TestTree)+import Data.Text (Text)+import Dhall (ToDhall)+import GHC.Generics (Generic)+import Numeric.Natural (Natural)+import Test.Tasty (TestTree) import Test.Tasty.HUnit ((@?=)) tests :: TestTree@@ -33,10 +33,20 @@ , Test.Tasty.testGroup "Unions" [ example 0 "./tests/tutorial/unions0A.dhall" "./tests/tutorial/unions0B.dhall" , example 1 "./tests/tutorial/unions1A.dhall" "./tests/tutorial/unions1B.dhall"- , example 2 "./tests/tutorial/unions2A.dhall" "./tests/tutorial/unions2B.dhall" , example 3 "./tests/tutorial/unions3A.dhall" "./tests/tutorial/unions3B.dhall" , example 4 "./tests/tutorial/unions4A.dhall" "./tests/tutorial/unions4B.dhall" ]+ , Test.Tasty.testGroup "Substitutions"+ [ Test.Tasty.HUnit.testCase "substitution1.dhall" $ do+ res <- Substitution.substituteResult "tests/tutorial/substitution1.dhall"+ res @?= Substitution.Failure 1+ , Test.Tasty.HUnit.testCase "substitution2.dhall" $ do+ res <- Substitution.substituteResult "tests/tutorial/substitution2.dhall"+ res @?= Substitution.Failure 1+ , Test.Tasty.HUnit.testCase "substitution3.dhall" $ do+ res <- Substitution.substituteFoo "tests/tutorial/substitution3.dhall"+ res @?= True+ ] ] _Interpolation_0 :: TestTree@@ -70,7 +80,7 @@ makeBools True False @?= False ) data Example0 = Example0 { foo :: Bool, bar :: Bool }- deriving (Generic, Inject)+ deriving (Generic, ToDhall) _Functions_2 :: TestTree _Functions_2 = Test.Tasty.HUnit.testCase "Example #2" (do
@@ -1,88 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Dhall.Test.TypeCheck where--import Control.Exception (SomeException)-import Data.Monoid (mempty, (<>))-import Data.Text (Text)-import Prelude hiding (FilePath)-import Test.Tasty (TestTree)-import Turtle (FilePath, (</>))--import qualified Control.Exception as Exception-import qualified Control.Monad as Monad-import qualified Data.Text as Text-import qualified Dhall.Core as Core-import qualified Dhall.Import as Import-import qualified Dhall.Parser as Parser-import qualified Dhall.Test.Util as Test.Util-import qualified Dhall.TypeCheck as TypeCheck-import qualified Test.Tasty as Tasty-import qualified Test.Tasty.HUnit as Tasty.HUnit-import qualified Turtle--typecheckDirectory :: FilePath-typecheckDirectory = "./dhall-lang/tests/typecheck"--getTests :: IO TestTree-getTests = do- successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest (Turtle.lstree (typecheckDirectory </> "success"))-- let failureTestFiles = do- path <- Turtle.lstree (typecheckDirectory </> "failure")-- let skip =- [ typecheckDirectory </> "failure/duplicateFields.dhall"- ]-- Monad.guard (path `notElem` skip)-- return path-- failureTests <- Test.Util.discover (Turtle.chars <> ".dhall") failureTest failureTestFiles-- let testTree = Tasty.testGroup "typecheck tests"- [ successTests- , failureTests- ]-- return testTree--successTest :: Text -> TestTree-successTest prefix =- Tasty.HUnit.testCase (Text.unpack prefix) $ do- let actualCode = Test.Util.toDhallPath (prefix <> "A.dhall")- let expectedCode = Test.Util.toDhallPath (prefix <> "B.dhall")-- actualExpr <- Core.throws (Parser.exprFromText mempty actualCode)-- expectedExpr <- Core.throws (Parser.exprFromText mempty expectedCode)-- let annotatedExpr = Core.Annot actualExpr expectedExpr-- resolvedExpr <- Import.load annotatedExpr-- _ <- Core.throws (TypeCheck.typeOf resolvedExpr)-- return ()--failureTest :: Text -> TestTree-failureTest path = do- Tasty.HUnit.testCase (Text.unpack path) $ do- let dhallPath = Test.Util.toDhallPath path-- expression <- Core.throws (Parser.exprFromText mempty dhallPath)-- let io :: IO Bool- io = do- _ <- Import.load expression- return True-- let handler :: SomeException -> IO Bool- handler _ = return False-- typeChecked <- Exception.handle handler io-- if typeChecked- then fail (Text.unpack path <> " should not have type-checked")- else return ()
@@ -0,0 +1,127 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.TypeInference where++import Control.Exception (SomeException (..))+import Data.Text (Text)+import System.FilePath ((</>))+import Test.Tasty (TestTree)++import qualified Control.Exception as Exception+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Dhall.Core as Core+import qualified Dhall.Import as Import+import qualified Dhall.Parser as Parser+import qualified Dhall.Test.Util as Test.Util+import qualified Dhall.TypeCheck as TypeCheck+import qualified System.FilePath as FilePath+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.HUnit as Tasty.HUnit+import qualified Turtle++typeInferenceDirectory :: FilePath+typeInferenceDirectory = "./dhall-lang/tests/type-inference"++getTests :: IO TestTree+getTests = do+ let successTestFiles = do+ path <- Turtle.lstree (typeInferenceDirectory </> "success")++ let skip =+ -- These tests intermittently fails with:+ -- "Error: Remote host not found"+ [ typeInferenceDirectory </> "success/CacheImportsA.dhall"+ , typeInferenceDirectory </> "success/CacheImportsCanonicalizeA.dhall"+ ]++ path `Test.Util.pathNotIn` skip++ return path++ successTests <- Test.Util.discover (Turtle.chars <* "A.dhall") successTest successTestFiles++ let failureTestFiles = Turtle.lstree (typeInferenceDirectory </> "failure")++ failureTests <- Test.Util.discover (Turtle.chars <* ".dhall") failureTest failureTestFiles++ let testTree = Tasty.testGroup "type-inference tests"+ [ successTests+ , failureTests+ ]++ return testTree++successTest :: Text -> TestTree+successTest prefix = do+ let expectedFailures =+ []+#if defined(WITH_HTTP) && defined(NETWORK_TESTS)+#else+ ++ [ typeInferenceDirectory </> "success/CacheImports"+ ]+#endif++ Test.Util.testCase prefix expectedFailures $ do+ let prefixFP = Text.unpack prefix++ actualCode <- Text.IO.readFile (prefixFP <> "A.dhall")++ actualExpr <- Core.throws (Parser.exprFromText mempty actualCode)++ tryResolvedExpr <-+ Exception.try+ (Test.Util.loadRelativeTo+ (FilePath.takeDirectory prefixFP)+ Import.IgnoreSemanticCache+ (Core.denote actualExpr))++ resolvedExpr <- case tryResolvedExpr of+ Left exception -> Tasty.HUnit.assertFailure (show (exception :: SomeException))+ Right resolvedExpr -> return resolvedExpr++ expectedTypeCode <- Text.IO.readFile (prefixFP <> "B.dhall")++ expectedType <- Core.throws (Parser.exprFromText mempty expectedTypeCode)++ resolvedExpectedType <- Import.assertNoImports (Core.denote expectedType)++ inferredType <- case TypeCheck.typeOf resolvedExpr of+ Left exception -> Tasty.HUnit.assertFailure (show exception)+ Right inferredType -> return inferredType++ let message = "The inferred type did not match the expected type"++ Tasty.HUnit.assertEqual message resolvedExpectedType inferredType++ -- We also add this to exercise the `Dhall.Eval.conv` code path, since+ -- it's easy to forget to update it when adding new syntax+ _ <- Core.throws (TypeCheck.typeOf (Core.Annot resolvedExpr resolvedExpectedType))+ return ()++failureTest :: Text -> TestTree+failureTest prefix = do+ let expectedFailures =+ [+ -- Duplicate fields are incorrectly caught during parsing:+ -- https://github.com/dhall-lang/dhall-haskell/issues/772+ typeInferenceDirectory </> "failure/unit/RecordTypeDuplicateFields"+ , typeInferenceDirectory </> "failure/unit/UnionTypeDuplicateVariants1"+ , typeInferenceDirectory </> "failure/unit/UnionTypeDuplicateVariants2"+ ]++ Test.Util.testCase prefix expectedFailures $ do+ let prefixFP = Text.unpack prefix++ code <- Text.IO.readFile (prefixFP <> ".dhall")++ expression <- case Parser.exprFromText mempty code of+ Left _ -> Tasty.HUnit.assertFailure (prefixFP <> " should have parsed")+ Right e -> return e++ resolved <- Import.assertNoImports expression++ case TypeCheck.typeOf resolved of+ Left _ -> return ()+ Right _ -> Tasty.HUnit.assertFailure (prefixFP <> " should not have type-checked")
@@ -1,83 +1,271 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} module Dhall.Test.Util ( code , codeWith , equivalent+ , load+ , loadRelativeTo+ , loadWith , normalize' , normalizeWith' , assertNormalizesTo , assertNormalizesToWith , assertNormalized , assertTypeChecks+ , assertDoesntTypeCheck , discover+ , Dhall.Test.Util.testCase+ , pathIn+ , pathNotIn+ , pathNotPrefixOf+ , pathNotSuffixOf , toDhallPath+ , managedTestEnvironment ) where -import Data.Bifunctor (first)-import Data.Text (Text)-import Dhall.Context (Context)-import Dhall.Core (Expr, Normalizer, ReifiedNormalizer(..))-import Dhall.Parser (Src)-import Dhall.TypeCheck (X)-import Prelude hiding (FilePath)+import Control.Applicative (Alternative, liftA2, (<|>))+import Control.Exception (tryJust)+import Control.Monad (guard)+import Control.Monad.Trans.State.Strict (StateT)+import Data.Bifunctor (first)+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Context (Context)+import Dhall.Core+ ( Chunks (..)+ , Expr (..)+ , Import+ , Normalizer+ , ReifiedNormalizer (..)+ )+import Dhall.Import (SemanticCacheMode (..), Status (..))+import Dhall.Parser (Src)+import System.IO.Error (isDoesNotExistError)+import Test.Tasty (TestTree) import Test.Tasty.HUnit-import Test.Tasty (TestTree)-import Turtle (FilePath, Pattern, Shell, fp)+import Turtle (Pattern, Shell, fp) import qualified Control.Exception-import qualified Control.Foldl as Foldl+import qualified Control.Foldl as Foldl+import qualified Control.Monad.Trans.State.Strict as State import qualified Data.Functor-import qualified Data.Text as Text+import qualified Data.List as List+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Import+import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.TypeCheck-import qualified Test.Tasty as Tasty+import qualified System.FilePath as FilePath+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.ExpectedFailure as Tasty.ExpectedFailure import qualified Turtle -normalize' :: Expr Src X -> Text+#if defined(WITH_HTTP) && defined(NETWORK_TESTS)+import qualified Data.Foldable+#else+import Control.Monad.IO.Class (MonadIO (..))+import Dhall.Core (Directory (..), File (..), URL (..))+import Lens.Micro.Mtl (zoom)++import qualified Data.Foldable+import qualified Data.Text.Encoding+import qualified Data.Text.IO+#endif++normalize' :: Expr Src Void -> Text normalize' = Dhall.Core.pretty . Dhall.Core.normalize -normalizeWith' :: Normalizer X -> Expr Src X -> Text+normalizeWith' :: Normalizer Void -> Expr Src Void -> Text normalizeWith' ctx t = Dhall.Core.pretty (Dhall.Core.normalizeWith (Just (ReifiedNormalizer ctx)) t) -code :: Text -> IO (Expr Src X)+code :: Text -> IO (Expr Src Void) code = codeWith Dhall.Context.empty -codeWith :: Context (Expr Src X) -> Text -> IO (Expr Src X)+codeWith :: Context (Expr Src Void) -> Text -> IO (Expr Src Void) codeWith ctx expr = do expr0 <- case Dhall.Parser.exprFromText mempty expr of Left parseError -> Control.Exception.throwIO parseError Right expr0 -> return expr0- expr1 <- Dhall.Import.load expr0+ expr1 <- load expr0 case Dhall.TypeCheck.typeWith ctx expr1 of Left typeError -> Control.Exception.throwIO typeError Right _ -> return () return expr1 +load :: Expr Src Import -> IO (Expr Src Void)+load = loadRelativeTo "." UseSemanticCache++loadRelativeTo :: FilePath.FilePath -> SemanticCacheMode -> Expr Src Import -> IO (Expr Src Void)+loadRelativeTo rootDirectory semanticCacheMode expression =+ State.evalStateT+ (loadWith expression)+ (Dhall.Import.emptyStatus rootDirectory) { _semanticCacheMode = semanticCacheMode }++#if defined(WITH_HTTP) && defined(NETWORK_TESTS)+loadWith :: Expr Src Import -> StateT Status IO (Expr Src Void)+loadWith = Dhall.Import.loadWith++#else+loadWith :: Expr Src Import -> StateT Status IO (Expr Src Void)+loadWith expr = do+ zoom Dhall.Import.remote (State.put mockRemote)+ Dhall.Import.loadWith expr++mockRemote :: Dhall.Core.URL -> StateT Status IO Data.Text.Text+mockRemote+ url@URL+ { authority = "raw.githubusercontent.com"+ , path = File (Directory components) file+ } = do+ let localDir = case reverse components of+ "dhall-lang" : "dhall-lang" : _ : rest ->+ reverse ("dhall-lang" : rest)+ "Nadrieril" : "dhall-rust" : _ : "dhall" : rest ->+ reverse ("dhall-lang" : rest)+ _ -> do+ fail ("Unable to mock URL: " <> Text.unpack (Dhall.Core.pretty url))++ localPath <- Dhall.Import.localToPath Dhall.Core.Here (File (Directory localDir) file)++ liftIO (Data.Text.IO.readFile localPath)++mockRemote+ URL { authority = "prelude.dhall-lang.org"+ , path = File (Directory components) file+ } = do+ let localDir = components ++ [ "Prelude", "dhall-lang" ]++ localPath <- Dhall.Import.localToPath Dhall.Core.Here (File (Directory localDir) file)++ liftIO (Data.Text.IO.readFile localPath)++mockRemote url@URL{ authority = "test.dhall-lang.org", path, headers } =+ case (path, fmap Dhall.Import.toHeaders headers) of+ (File (Directory []) "foo", Just [("test", _)]) ->+ return "./bar"+ (File (Directory []) "bar", Just [("test", _)]) ->+ return "True"+ (File (Directory ["cors"]) "AllowedAll.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "OnlyGithub.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "OnlySelf.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "OnlyOther.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "Empty.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "NoCORS.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "Null.dhall", _) ->+ return "42"+ (File (Directory ["cors"]) "SelfImportAbsolute.dhall", _) ->+ return "https://test.dhall-lang.org/cors/NoCORS.dhall"+ (File (Directory ["cors"]) "SelfImportRelative.dhall", _) ->+ return "./NoCORS.dhall"+ (File (Directory ["cors"]) "TwoHopsFail.dhall", _) ->+ return "https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/OnlySelf.dhall"+ (File (Directory ["cors"]) "TwoHopsSuccess.dhall", _) ->+ return "https://raw.githubusercontent.com/dhall-lang/dhall-lang/5ff7ecd2411894dd9ce307dc23020987361d2d43/tests/import/data/cors/OnlyGithub.dhall"+ _ -> do+ fail ("Unable to mock URL: " <> Text.unpack (Dhall.Core.pretty url))++mockRemote url@URL{ authority = "httpbin.org", path, headers } =+ case (path, fmap Dhall.Import.toHeaders headers) of+ (File (Directory []) "user-agent", Just [("user-agent", userAgent)]) -> do+ let agentText = Data.Text.Encoding.decodeUtf8 userAgent++ return ("{\n \"user-agent\": \"" <> agentText <> "\"\n}\n")+ (File (Directory []) "user-agent", Nothing) -> do+ return ("{\n \"user-agent\": \"Dhall\"\n}\n")+ _ -> do+ fail ("Unable to mock URL: " <> Text.unpack (Dhall.Core.pretty url))++mockRemote url = do+ let urlString = Text.unpack (Dhall.Core.pretty url)+ fail ("(mock http) Url does not match any of the hard-coded rules: "+ <> urlString)+#endif++{- Given a test prefix, returns a managed resource+ which sets / reverts relevant environment variables based+ on `prefix <> "ENV.dhall"` (if present)+ -}+managedTestEnvironment :: Text -> Turtle.Managed [(Text, Maybe Text)]+managedTestEnvironment prefix = Turtle.managed (Control.Exception.bracket setup cleanup)+ where+ envPath = Text.unpack (prefix <> "ENV.dhall")++ setup :: IO [(Text, Maybe Text)]+ setup = do+ envFileContents <-+ tryJust (guard . isDoesNotExistError) (Text.IO.readFile envPath)++ testEnv <- case envFileContents of+ Right contents -> do+ resolved <- code contents+ return (convertEnvExpr (Dhall.Core.normalize resolved))+ Left _ -> return []++ traverse setEnv testEnv++ cleanup :: [(Text, Maybe Text)] -> IO ()+ cleanup = Data.Foldable.traverse_ restoreEnv++ convertEnvExpr :: Expr Src Void -> [(Text, Text)]+ convertEnvExpr (ListLit _ hs) = Data.Foldable.toList (Data.Foldable.fold maybePairs)+ where+ maybePairs = mapM toPair hs++ toPair :: Expr s a -> Maybe (Text, Text)+ toPair (RecordLit m) = do+ (Dhall.Core.recordFieldValue -> TextLit (Chunks [] key), Dhall.Core.recordFieldValue -> TextLit (Chunks [] value))+ <- lookupHeader <|> lookupMapKey+ return (key, value)+ where+ lookupHeader = liftA2 (,) (Dhall.Map.lookup "header" m) (Dhall.Map.lookup "value" m)+ lookupMapKey = liftA2 (,) (Dhall.Map.lookup "mapKey" m) (Dhall.Map.lookup "mapValue" m)+ toPair _ = Nothing+ convertEnvExpr _ = []++ setEnv :: (Text, Text) -> IO (Text, Maybe Text)+ setEnv (k, v) = do+ old <- Turtle.need k+ Turtle.export k v+ return (k, old)++ restoreEnv :: (Text, Maybe Text) -> IO ()+ restoreEnv (k, Just old) = Turtle.export k old+ restoreEnv (k, Nothing) = Turtle.unset k+ equivalent :: Text -> Text -> IO () equivalent text0 text1 = do- expr0 <- fmap Dhall.Core.normalize (code text0) :: IO (Expr X X)- expr1 <- fmap Dhall.Core.normalize (code text1) :: IO (Expr X X)+ expr0 <- fmap Dhall.Core.normalize (code text0) :: IO (Expr Void Void)+ expr1 <- fmap Dhall.Core.normalize (code text1) :: IO (Expr Void Void) assertEqual "Expressions are not equivalent" expr0 expr1 -assertNormalizesTo :: Expr Src X -> Text -> IO ()+assertNormalizesTo :: Expr Src Void -> Text -> IO () assertNormalizesTo e expected = do assertBool msg (not $ Dhall.Core.isNormalized e) normalize' e @?= expected where msg = "Given expression is already in normal form" -assertNormalizesToWith :: Normalizer X -> Expr Src X -> Text -> IO ()+assertNormalizesToWith :: Normalizer Void -> Expr Src Void -> Text -> IO () assertNormalizesToWith ctx e expected = do assertBool msg (not $ Dhall.Core.isNormalizedWith ctx (first (const ()) e)) normalizeWith' ctx e @?= expected where msg = "Given expression is already in normal form" -assertNormalized :: Expr Src X -> IO ()+assertNormalized :: Expr Src Void -> IO () assertNormalized e = do assertBool msg1 (Dhall.Core.isNormalized e) assertEqual msg2 (normalize' e) (Dhall.Core.pretty e)@@ -87,15 +275,25 @@ assertTypeChecks :: Text -> IO () assertTypeChecks text = Data.Functor.void (code text) +assertDoesntTypeCheck :: Text -> IO ()+assertDoesntTypeCheck text = do+ expr0 <- case Dhall.Parser.exprFromText mempty text of+ Left parseError -> Control.Exception.throwIO parseError+ Right e -> return e+ expr1 <- load expr0+ case Dhall.TypeCheck.typeOf expr1 of+ Left _ -> return ()+ Right type_ -> fail ("Bad type for " <> Text.unpack text <> "\n " <> show type_)+ {-| Automatically run a test on all files in a directory tree that end in @A.dhall@ -} discover :: Pattern Text -> (Text -> TestTree) -> Shell FilePath -> IO TestTree discover pattern buildTest paths = do let shell = do- path <- paths+ path_ <- paths - let pathText = Turtle.format fp path+ let pathText = Turtle.format fp (FilePath.normalise path_) prefix : _ <- return (Turtle.match pattern pathText) @@ -105,10 +303,31 @@ return (Tasty.testGroup "discover" tests) +testCase :: Text -> [ FilePath ] -> Assertion -> TestTree+testCase prefix expectedFailures assertion =+ if prefix `elem` map (Turtle.format fp . FilePath.normalise) expectedFailures+ then Tasty.ExpectedFailure.expectFail test+ else test+ where+ test = Test.Tasty.HUnit.testCase (Text.unpack prefix) assertion +pathIn :: Alternative f => FilePath -> [FilePath] -> f ()+pathIn this = guard . any (FilePath.equalFilePath this)++pathNotIn :: Alternative f => FilePath -> [FilePath] -> f ()+pathNotIn this = guard . not . any (FilePath.equalFilePath this)++pathNotPrefixOf :: Alternative f => FilePath -> FilePath -> f ()+pathNotPrefixOf this =+ guard . not . List.isPrefixOf (FilePath.normalise this) . FilePath.normalise++pathNotSuffixOf :: Alternative f => FilePath -> FilePath -> f ()+pathNotSuffixOf this =+ guard . not . List.isSuffixOf (FilePath.normalise this) . FilePath.normalise+ {-| Path names on Windows are not valid Dhall paths due to using backslashes instead of forwardslashes to separate path components. This utility fixes them if necessary -} toDhallPath :: Text -> Text-toDhallPath = Text.replace "\\" "/"+toDhallPath = ("./" <>) . Text.replace "\\" "/"
@@ -0,0 +1,4 @@+ λ(… : …+ → …)+→ …+ …
@@ -0,0 +1,1 @@+λ(f : List Bool -> Bool) → f ([] : List Bool)
@@ -0,0 +1,1 @@+λ(f : List Bool -> Bool) → f ([] : List Bool)
@@ -0,0 +1,2 @@+- [] : …++ True
@@ -0,0 +1,1 @@+[] : List Natural
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,6 @@+ …+→ …+→ …@- 1+ + 0++→ …
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(b : Type) → ∀(x : a) → Bool
@@ -0,0 +1,1 @@+∀(a : Type) → ∀(b : Type) → ∀(x : b) → Bool
@@ -0,0 +1,7 @@+[ …+, { y = - 4+ + 5+ , …+ }+]+
@@ -0,0 +1,3 @@+[ { x = 1, y = 2 }+, { x = 3, y = 4 }+]
@@ -0,0 +1,3 @@+[ { x = 1, y = 2 }+, { x = 3, y = 5 }+]
@@ -0,0 +1,2 @@+- [ … ]++ True
@@ -0,0 +1,1 @@+[1]
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,5 @@+ λ(… : { …+ })+→ … with …+ .c.d+ = - 2+ + 3
@@ -0,0 +1,1 @@+λ(r : { a : Natural }) → r with b = 2
@@ -0,0 +1,1 @@+λ(r : { a : Natural }) → r with b.c.d = 3
@@ -0,0 +1,33 @@+{ app =+ ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff+ aaaaaaaaaaaaaaaaa+, app2 =+ f+ a+ b+ cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc+, app3 =+ f+ a+ b+ c+ dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd+, some =+ Some+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+, someList =+ Some+ [ aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccc, dddddddddddddd ]+, merge1 =+ merge+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+, merge3 =+ merge+ a+ b+ ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc+, toMap1 =+ toMap+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+}
@@ -0,0 +1,34 @@+{ app =+ ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff+ aaaaaaaaaaaaaaaaa+, app2 =+ f+ a+ b+ cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc+, app3 =+ f+ a+ b+ c+ dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd+, some = Some+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+, someList = Some+ [ aaaaaaaaaaaaaaaaaaaaaaaaaa+ , bbbbbbbbbbbbbbbbbbbb+ , cccccccccccccccccccccccc+ , dddddddddddddd+ ]+, merge1 =+ merge+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+, merge3 =+ merge+ a+ b+ ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc+, toMap1 = toMap+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+}
@@ -0,0 +1,30 @@+{-+Concatenate a `List` of `Text` values with a separator in between each value+-}+let Status = < Empty | NonEmpty : Text >++let concatSep+ : ∀(separator : Text) → ∀(elements : List Text) → Text+ = λ(separator : Text)+ → λ(elements : List Text)+ → let status =+ List/fold Text elements Status+ ( λ(element : Text)+ → λ(status : Status)+ → merge+ { Empty = Status.NonEmpty element+ , NonEmpty =+ λ(result : Text)+ → Status.NonEmpty (element ++ separator ++ result)+ }+ status+ )+ Status.Empty+ + in merge { Empty = "", NonEmpty = λ(result : Text) → result } status++let example0 = assert : concatSep ", " [ "ABC", "DEF", "GHI" ] ≡ "ABC, DEF, GHI"++let example1 = assert : concatSep ", " ([] : List Text) ≡ ""++in concatSep
@@ -0,0 +1,33 @@+{-+Concatenate a `List` of `Text` values with a separator in between each value+-}+let Status = < Empty | NonEmpty : Text >++let concatSep+ : ∀(separator : Text) → ∀(elements : List Text) → Text+ = λ(separator : Text) →+ λ(elements : List Text) →+ let status =+ List/fold+ Text+ elements+ Status+ ( λ(element : Text) →+ λ(status : Status) →+ merge+ { Empty = Status.NonEmpty element+ , NonEmpty =+ λ(result : Text) →+ Status.NonEmpty (element ++ separator ++ result)+ }+ status+ )+ Status.Empty++ in merge { Empty = "", NonEmpty = λ(result : Text) → result } status++let example0 = assert : concatSep ", " [ "ABC", "DEF", "GHI" ] ≡ "ABC, DEF, GHI"++let example1 = assert : concatSep ", " ([] : List Text) ≡ ""++in concatSep
@@ -0,0 +1,1 @@+{ x = { y = { a = { b = 1 }, c = { d = 2 } } } }
@@ -0,0 +1,1 @@+{ x.y = { a.b = 1, c.d = 2 } }
@@ -0,0 +1,17 @@+{ {- A -}+ a+ -- B+ . -- C+ b+ . c+ {- D -}+ . d =+ -- E+ x+, {- F -}+ e+ {- G -}+ . f =+ {- H -}+ { g = y }+}
@@ -0,0 +1,17 @@+{ {- A -}+ a+ -- B+ . -- C+ b+ . c+ {- D -}+ . d+ = -- E+ x+, {- F -}+ e+ {- G -}+ . f+ = {- H -}+ { g = y }+}
@@ -1,37 +1,37 @@-[ 1.0-, 1.0-, 1.0000000000000002+[ 1.0000000000000000+, 1.0000000000000001 , 1.0000000000000002-, 1.0000000000000004+, 1.0000000000000003 , 1.0000000000000004-, 1.0000000000000007+, 1.0000000000000005+, 1.0000000000000006 , 1.0000000000000007-, 1.0000000000000009+, 1.0000000000000008 , 1.0000000000000009-, 1.0e64-, 1.0000000000000002e64+, 1.0000000000000000e64+, 1.0000000000000001e64 , 1.0000000000000002e64 , 1.0000000000000003e64-, 1.0000000000000005e64+, 1.0000000000000004e64 , 1.0000000000000005e64 , 1.0000000000000006e64-, 1.0000000000000008e64+, 1.0000000000000007e64 , 1.0000000000000008e64 , 1.0000000000000009e64-, 1.0e100-, 1.0e100-, 1.0000000000000002e100+, 1.0000000000000000e100+, 1.0000000000000001e100 , 1.0000000000000002e100-, 1.0000000000000004e100+, 1.0000000000000003e100 , 1.0000000000000004e100+, 1.0000000000000005e100 , 1.0000000000000006e100-, 1.0000000000000008e100+, 1.0000000000000007e100 , 1.0000000000000008e100-, 1.000000000000001e100-, 1.7976931348623157e308-, 1.7976931348623157e308-, 1.7976931348623155e308-, -1.7976931348623157e308-, -1.7976931348623157e308-, -1.7976931348623155e308+, 1.0000000000000009e100+, 179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.0+, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218945.0+, 179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944.0+, -179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.0+, -179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218945.0+, -179769313486231560835325876058105298516207002341652166261661174625869553267292326574530099287946549246750631490335877017522087105926987962906277604735569213290190919152394180476217125334960946356387261286640198029037799514183602981511756283727771403830521483963923935633133642802139091669457927874464075218944.0 ]
@@ -0,0 +1,4 @@+{ {- Comments around duplicate fields are not preserved -} foo.bar = 1+, foo = { baz = {- Comments within values are still preserved-} 2 }+, foo = qux+}
@@ -0,0 +1,6 @@+{ foo.bar = 1+, foo.baz+ = {- Comments within values are still preserved-}+ 2+, foo = qux+}
@@ -0,0 +1,1 @@+[ env:x, env:"1", env:" ", env:"\\", env:"." ]
@@ -0,0 +1,1 @@+[ env:x, env:"1", env:" ", env:"\\", env:"." ]
@@ -0,0 +1,6 @@+{ example0 = merge a b + merge a b+, example1 = (merge a b : T) + (merge a b : T)+, example2 = toMap a + toMap a+, example3 = (toMap a b : T) + (toMap a b : T)+, example4 = Some a + Some a+}
@@ -0,0 +1,6 @@+{ example0 = merge a b + merge a b+, example1 = (merge a b : T) + (merge a b : T)+, example2 = toMap a + toMap a+, example3 = (toMap a b : T) + (toMap a b : T)+, example4 = Some a + Some a+}
@@ -0,0 +1,4 @@+ +{- bla -} + +True
@@ -0,0 +1,2 @@+{- bla -}+True
@@ -0,0 +1,1 @@+{- -}0
@@ -0,0 +1,2 @@+{- -}+0
@@ -1,13 +1,7 @@- if True-+if True then if True then if True then 1 else 2 else if True then 3 else 4- else if True- then if True then 5 else 6- else if True- then 7- else 8
@@ -0,0 +1,1 @@+a ? b || c
@@ -0,0 +1,1 @@+a ? b || c
@@ -0,0 +1,11 @@+{ inner =+ ''++ one++ two++ three++ ''+}
@@ -0,0 +1,11 @@+{ inner =+ ''++ one++ two++ three++ ''+}
@@ -0,0 +1,1 @@+"foo\n${a} bar"
@@ -0,0 +1,3 @@+''+foo+${a} bar''
@@ -0,0 +1,163 @@+let name = "ipfs"++let labels =+ { `app.kubernetes.io/name` = name+ , `app.kubernetes.io/instance` = "wintering-rodent"+ , `app.kubernetes.io/version` = "0.4.0"+ , `app.kubernetes.io/managed-by` = "dhall"+ }++let matchLabels =+ labels.{ `app.kubernetes.io/name`, `app.kubernetes.io/instance` }++let k8s =+ https://raw.githubusercontent.com/dhall-lang/dhall-kubernetes/4ab28225a150498aef67c226d3c5f026c95b5a1e/package.dhall sha256:2c7ac35494f16b1f39afcf3467b2f3b0ab579edb0c711cddd2c93f1cbed358bd++let serviceName = "ipfs"++let apiPort = k8s.IntOrString.Int 5001++let gatewayPort = k8s.IntOrString.Int 8080++let toRule =+ λ ( args+ : { host : Text+ , path : Text+ , serviceName : Text+ , servicePort : k8s.IntOrString+ }+ )+ → k8s.IngressRule::{+ , host = Some args.host+ , http =+ Some+ k8s.HTTPIngressRuleValue::{+ , paths =+ [ k8s.HTTPIngressPath::{+ , path = Some args.path+ , backend =+ k8s.IngressBackend::args.{ serviceName, servicePort }+ }+ ]+ }+ }++in [ k8s.Resource.Ingress+ k8s.Ingress::{+ , metadata =+ k8s.ObjectMeta::{ labels = toMap labels, name = "${name}-api" }+ , spec =+ Some+ k8s.IngressSpec::{+ , rules =+ [ toRule+ { host = "localhost"+ , path = "/"+ , serviceName = serviceName+ , servicePort = gatewayPort+ }+ , toRule+ { host = "localhost"+ , path = "/"+ , serviceName = serviceName+ , servicePort = apiPort+ }+ ]+ }+ }+ , k8s.Resource.Service+ k8s.Service::{+ , metadata =+ k8s.ObjectMeta::{ name = serviceName, labels = toMap labels }+ , spec =+ Some+ k8s.ServiceSpec::{+ , ports =+ [ k8s.ServicePort::{+ , port = 5001+ , targetPort = Some apiPort+ , name = Some "api"+ }+ , k8s.ServicePort::{+ , port = 8080+ , targetPort = Some gatewayPort+ , name = Some "api"+ }+ ]+ , selector = toMap matchLabels+ }+ }+ , k8s.Resource.StatefulSet+ k8s.StatefulSet::{+ , metadata = k8s.ObjectMeta::{ name = name, labels = toMap labels }+ , spec =+ Some+ k8s.StatefulSetSpec::{+ , serviceName = serviceName+ , selector =+ k8s.LabelSelector::{ matchLabels = toMap matchLabels }+ , template =+ k8s.PodTemplateSpec::{+ , metadata =+ k8s.ObjectMeta::{ name = name, labels = toMap labels }+ , spec =+ Some+ k8s.PodSpec::{+ , securityContext =+ Some+ k8s.PodSecurityContext::{+ , runAsUser = Some 1000+ , runAsGroup = Some 1000+ , fsGroup = Some 1000+ }+ , containers =+ [ k8s.Container::{+ , name = name+ , image = Some "ipfs/go-ipfs:v0.4.22"+ , livenessProbe =+ k8s.Probe::{+ , httpGet =+ Some+ k8s.HTTPGetAction::{+ , path =+ Some "/debug/metrics/prometheus"+ , port = k8s.IntOrString.String "api"+ }+ , initialDelaySeconds = Some 15+ , periodSeconds = Some 3+ }+ , readinessProbe =+ k8s.Probe::{+ , httpGet =+ Some+ k8s.HTTPGetAction::{+ , path =+ Some "/debug/metrics/prometheus"+ , port = k8s.IntOrString.String "api"+ }+ , initialDelaySeconds = Some 15+ , periodSeconds = Some 3+ }+ , ports =+ [ k8s.ContainerPort::{+ , containerPort = 5001+ , name = Some "api"+ }+ , k8s.ContainerPort::{+ , containerPort = 8080+ , name = Some "gateway"+ }+ ]+ , volumeMounts =+ [ k8s.VolumeMount::{+ , name = "ipfs-storage"+ , mountPath = "/data/ipfs"+ }+ ]+ }+ ]+ }+ }+ }+ }+ ]
@@ -0,0 +1,144 @@+let name = "ipfs"++let labels =+ { `app.kubernetes.io/name` = name+ , `app.kubernetes.io/instance` = "wintering-rodent"+ , `app.kubernetes.io/version` = "0.4.0"+ , `app.kubernetes.io/managed-by` = "dhall"+ }++let matchLabels =+ labels.{ `app.kubernetes.io/name`, `app.kubernetes.io/instance` }++let k8s =+ https://raw.githubusercontent.com/dhall-lang/dhall-kubernetes/4ab28225a150498aef67c226d3c5f026c95b5a1e/package.dhall+ sha256:2c7ac35494f16b1f39afcf3467b2f3b0ab579edb0c711cddd2c93f1cbed358bd++let serviceName = "ipfs"++let apiPort = k8s.IntOrString.Int 5001++let gatewayPort = k8s.IntOrString.Int 8080++let toRule =+ λ ( args+ : { host : Text+ , path : Text+ , serviceName : Text+ , servicePort : k8s.IntOrString+ }+ ) →+ k8s.IngressRule::{+ , host = Some args.host+ , http = Some k8s.HTTPIngressRuleValue::{+ , paths =+ [ k8s.HTTPIngressPath::{+ , path = Some args.path+ , backend = k8s.IngressBackend::args.{ serviceName, servicePort }+ }+ ]+ }+ }++in [ k8s.Resource.Ingress+ k8s.Ingress::{+ , metadata = k8s.ObjectMeta::{+ , labels = toMap labels+ , name = "${name}-api"+ }+ , spec = Some k8s.IngressSpec::{+ , rules =+ [ toRule+ { host = "localhost"+ , path = "/"+ , serviceName+ , servicePort = gatewayPort+ }+ , toRule+ { host = "localhost"+ , path = "/"+ , serviceName+ , servicePort = apiPort+ }+ ]+ }+ }+ , k8s.Resource.Service+ k8s.Service::{+ , metadata = k8s.ObjectMeta::{+ , name = serviceName+ , labels = toMap labels+ }+ , spec = Some k8s.ServiceSpec::{+ , ports =+ [ k8s.ServicePort::{+ , port = 5001+ , targetPort = Some apiPort+ , name = Some "api"+ }+ , k8s.ServicePort::{+ , port = 8080+ , targetPort = Some gatewayPort+ , name = Some "api"+ }+ ]+ , selector = toMap matchLabels+ }+ }+ , k8s.Resource.StatefulSet+ k8s.StatefulSet::{+ , metadata = k8s.ObjectMeta::{ name, labels = toMap labels }+ , spec = Some k8s.StatefulSetSpec::{+ , serviceName+ , selector = k8s.LabelSelector::{ matchLabels = toMap matchLabels }+ , template = k8s.PodTemplateSpec::{+ , metadata = k8s.ObjectMeta::{ name, labels = toMap labels }+ , spec = Some k8s.PodSpec::{+ , securityContext = Some k8s.PodSecurityContext::{+ , runAsUser = Some 1000+ , runAsGroup = Some 1000+ , fsGroup = Some 1000+ }+ , containers =+ [ k8s.Container::{+ , name+ , image = Some "ipfs/go-ipfs:v0.4.22"+ , livenessProbe = k8s.Probe::{+ , httpGet = Some k8s.HTTPGetAction::{+ , path = Some "/debug/metrics/prometheus"+ , port = k8s.IntOrString.String "api"+ }+ , initialDelaySeconds = Some 15+ , periodSeconds = Some 3+ }+ , readinessProbe = k8s.Probe::{+ , httpGet = Some k8s.HTTPGetAction::{+ , path = Some "/debug/metrics/prometheus"+ , port = k8s.IntOrString.String "api"+ }+ , initialDelaySeconds = Some 15+ , periodSeconds = Some 3+ }+ , ports =+ [ k8s.ContainerPort::{+ , containerPort = 5001+ , name = Some "api"+ }+ , k8s.ContainerPort::{+ , containerPort = 8080+ , name = Some "gateway"+ }+ ]+ , volumeMounts =+ [ k8s.VolumeMount::{+ , name = "ipfs-storage"+ , mountPath = "/data/ipfs"+ }+ ]+ }+ ]+ }+ }+ }+ }+ ]
@@ -0,0 +1,5 @@+let attribute+ : Text → Text → { mapKey : Text, mapValue : Text }+ = λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }++in attribute
@@ -0,0 +1,5 @@+let attribute+ : Text → Text → { mapKey : Text, mapValue : Text }+ = λ(key : Text) → λ(value : Text) → { mapKey = key, mapValue = value }++in attribute
@@ -0,0 +1,14 @@+{ conversation =+ [ { author = "robert", content = xs }+ , { author = "robert", content = xs }+ , { author =+ "bob"+ , content =+ [ text+ ''+ any line going past the 80 characters boundary (e.g. this one is 82)+ ''+ ]+ }+ ]+}
@@ -0,0 +1,13 @@+{ conversation =+ [ { author = "robert", content = xs }+ , { author = "robert", content = xs }+ , { author = "bob"+ , content =+ [ text+ ''+ any line going past the 80 characters boundary (e.g. this one is 82)+ ''+ ]+ }+ ]+}
@@ -0,0 +1,14 @@+let Tagged+ : Type → Type+ = λ ( a+ : Type+ )+ → { field :+ Text+ , nesting :+ ./Nesting sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting+ , contents : a+ }++in Tagged
@@ -0,0 +1,12 @@+let Tagged+ : Type → Type+ = λ(a : Type) →+ { field : Text+ , nesting :+ ./Nesting+ sha256:6284802edd41d5d725aa1ec7687e614e21ad1be7e14dd10996bfa9625105c335+ ? ./Nesting+ , contents : a+ }++in Tagged
@@ -0,0 +1,6 @@+let foo =++ {- test -}+ "hello"++in foo
@@ -0,0 +1,6 @@+let foo =++ {- test -}+ "hello"++in foo
@@ -0,0 +1,1 @@+"\n\tx"
@@ -0,0 +1,3 @@+''++${"\t"}x''
@@ -0,0 +1,1 @@+"\n x"
@@ -0,0 +1,3 @@+''++${" "}x''
@@ -0,0 +1,7 @@+let {- foo++ bar -}+ x =+ 1++in x
@@ -0,0 +1,7 @@+let {- foo++ bar -}+ x =+ 1++in x
@@ -0,0 +1,1 @@+{ `if` = True }
@@ -0,0 +1,1 @@+{ `if` = True }
@@ -0,0 +1,1 @@+let `Some` = 3 in { `if` = True, Some = 333 }
@@ -0,0 +1,1 @@+let `Some` = 3 in { `if` = True, Some = 333 }
@@ -0,0 +1,11 @@+ let foo = 1++in λ(bar : Integer)+ → let exposePort =+ λ(portSpec : { ext : Integer, int : Integer })+ → Integer/show portSpec.ext ++ ":" ++ Integer/show portSpec.int+ + in let exposeSamePort =+ λ(port : Integer) → exposePort { ext = port, int = port }+ + in { blah = bar }
@@ -0,0 +1,11 @@+let foo = 1++in λ(bar : Integer) →+ let exposePort =+ λ(portSpec : { ext : Integer, int : Integer }) →+ Integer/show portSpec.ext ++ ":" ++ Integer/show portSpec.int++ in let exposeSamePort =+ λ(port : Integer) → exposePort { ext = port, int = port }++ in { blah = bar }
@@ -0,0 +1,4 @@+let x = ({ foo = 1 } ∧ { bar = 2 })+ with bar = 3 + with foo = 4 +in x
@@ -0,0 +1,1 @@+let x = ({ foo = 1 } ∧ { bar = 2 }) with bar = 3 with foo = 4 in x
@@ -0,0 +1,1 @@+"'\${x}'\n"
@@ -0,0 +1,3 @@+''+${"'"}''${x}'+''
@@ -0,0 +1,11 @@+let T = < Some | Type >++let t+ : T+ = T.`Some`++let x+ : T+ = T.Type++in True
@@ -0,0 +1,11 @@+let T = < Some | Type >++let t+ : T+ = T.`Some`++let x+ : T+ = T.Type++in True
@@ -1,1 +1,1 @@-[ 1.0, 1.0e100, 1.0e-100 ]+[ 1.0, 1e100, 1e-100 ]
@@ -0,0 +1,142 @@+-- This file was tested using console NetHack version 3.6.1+--+-- To exercise all options documented in https://nethackwiki.com/wiki/Options+-- see `./unvalidated.dhall`+let types = ./../types.dhall++let defaults = ./../defaults.dhall++in defaults.Config+ ⫽ { AUTOCOMPLETE =+ [ { enable = True, value = "zap" }+ , { enable = False, value = "annotate" }+ ]+ , acoustics = Some True+ , align = Some { enable = True, value = types.Alignment.chaotic }+ , autodescribe = Some False+ , autodig = Some False+ , AUTOPICKUP_EXCEPTION =+ [ { pickup = False, name = "chest" }+ , { pickup = True, name = "dagger" }+ ]+ , BIND =+ [ { keybinding = "!", command = "loot" }+ , { keybinding = "^v", command = "untrap" }+ , { keybinding = "M-x", command = "terrain" }+ ]+ , catname = Some "Mirri"+ , checkpoint = Some True+ , checkspace = Some True+ , clicklook = Some False+ , cmdassist = Some True+ , confirm = Some True+ , dark_room = Some False+ , disclose =+ Some+ ( defaults.Disclose+ ⫽ { inventory = Some { prompt = True, default = True }+ , attributes = Some { prompt = True, default = False }+ , monsters_killed = Some { prompt = False, default = True }+ , monsters_genocided = Some { prompt = False, default = False }+ , conduct = Some { prompt = False, default = False }+ , dungeon_overview = Some { prompt = False, default = False }+ }+ )+ , dogname = Some "Cujo"+ , extmenu = Some False+ , fixinv = Some True+ , force_invmenu = Some False+ , fruit = Some "slime mold"+ , gender = Some types.Gender.female+ , goldX = Some False+ , help = Some True+ , hilite_pet = Some False+ , hilite_pile = Some False+ , hilite_status =+ defaults.HiliteStatus+ ⫽ { gold =+ [ { color = types.Color.yellow+ , trigger = Some types.Numeric.always+ , attributes = None types.Attributes+ }+ ]+ }+ , hitpointbar = Some True+ , horsename = Some "Erhir"+ , ignintr = Some False+ , implicit_uncursed = Some True+ , legacy = Some True+ , lit_corridor = Some False+ , lootabc = Some False+ , mail = Some True+ , mention_walls = Some False+ , menucolors =+ [ { regex = "blessed"+ , color = Some types.Color.cyan+ , attributes = defaults.Attributes ⫽ { bold = Some True }+ }+ ]+ , menustyle = Some types.MenuStyle.traditional+ , menu_deselect_all = Some "-"+ , menu_deselect_page = Some "\\"+ , menu_first_page = Some "^"+ , menu_headings = Some types.MenuHeadings.bold+ , menu_invert_all = Some "@"+ , menu_invert_page = Some "~"+ , menu_last_page = Some "|"+ , menu_next_page = Some ">"+ , menu_objsyms = Some False+ , menu_previous_page = Some "<"+ , menu_search = Some ":"+ , menu_select_all = Some "."+ , menu_tab_sep = Some False+ , msg_window = Some types.MsgWindow.single+ , MSGTYPE = [ types.MsgType.hide "You swap places with .*" ]+ , name = Some "Kaeru"+ , news = Some True+ , nudist = Some False+ , null = Some False+ , number_pad = Some types.NumberPad.Letters+ , packorder = Some "\")[%?+!=/(*`0_"+ , paranoid_confirmation =+ defaults.ParanoidConfirmation ⫽ { pray = Some True }+ , pettype = Some types.PetType.cat+ , pickup_burden = Some types.PickupBurden.stressed+ , pickup_thrown = Some True+ , pickup_types = Some "?!/"+ , pile_limit = Some (types.PileLimit.limit 5)+ , playmode = Some types.PlayMode.normal+ , pushweapon = Some False+ , race = Some { enable = True, value = types.Race.elf }+ , rest_on_space = Some False+ , role = Some { enable = True, value = types.Role.wizard }+ , roguesymset = Some types.SymSet.RogueEpyx+ , runmode = Some types.RunMode.walk+ , safe_pet = Some True+ , sanity_check = Some False+ , scores = { own = Some True, around = Some 2, top = Some 10 }+ , showexp = Some False+ , showrace = Some False+ , showscore = Some False+ , silent = Some True+ , sortloot = Some types.SortLoot.none+ , sortpack = Some True+ , sparkle = Some True+ , standout = Some False+ , status_updates = Some True+ , statushilites = Some 10+ , suppress_alert = Some "3.3.1"+ , symset = Some types.SymSet.DECgraphics+ , time = Some False+ , timed_delay = Some True+ , tombstone = Some True+ , toptenwin = Some False+ , travel = Some True+ , verbose = Some True+ , whatis_coord = Some types.WhatisCoord.none+ , whatis_filter = Some types.WhatisFilter.no_filtering+ , whatis_menu = Some False+ , whatis_moveskip = Some False+ , windowtype = Some "tty"+ , wizkit = Some "wizkit.txt"+ }
@@ -0,0 +1,141 @@+-- This file was tested using console NetHack version 3.6.1+--+-- To exercise all options documented in https://nethackwiki.com/wiki/Options+-- see `./unvalidated.dhall`+let types = ./../types.dhall++let defaults = ./../defaults.dhall++in defaults.Config+ ⫽ { AUTOCOMPLETE =+ [ { enable = True, value = "zap" }+ , { enable = False, value = "annotate" }+ ]+ , acoustics = Some True+ , align = Some { enable = True, value = types.Alignment.chaotic }+ , autodescribe = Some False+ , autodig = Some False+ , AUTOPICKUP_EXCEPTION =+ [ { pickup = False, name = "chest" }+ , { pickup = True, name = "dagger" }+ ]+ , BIND =+ [ { keybinding = "!", command = "loot" }+ , { keybinding = "^v", command = "untrap" }+ , { keybinding = "M-x", command = "terrain" }+ ]+ , catname = Some "Mirri"+ , checkpoint = Some True+ , checkspace = Some True+ , clicklook = Some False+ , cmdassist = Some True+ , confirm = Some True+ , dark_room = Some False+ , disclose = Some+ ( defaults.Disclose+ ⫽ { inventory = Some { prompt = True, default = True }+ , attributes = Some { prompt = True, default = False }+ , monsters_killed = Some { prompt = False, default = True }+ , monsters_genocided = Some { prompt = False, default = False }+ , conduct = Some { prompt = False, default = False }+ , dungeon_overview = Some { prompt = False, default = False }+ }+ )+ , dogname = Some "Cujo"+ , extmenu = Some False+ , fixinv = Some True+ , force_invmenu = Some False+ , fruit = Some "slime mold"+ , gender = Some types.Gender.female+ , goldX = Some False+ , help = Some True+ , hilite_pet = Some False+ , hilite_pile = Some False+ , hilite_status =+ defaults.HiliteStatus+ ⫽ { gold =+ [ { color = types.Color.yellow+ , trigger = Some types.Numeric.always+ , attributes = None types.Attributes+ }+ ]+ }+ , hitpointbar = Some True+ , horsename = Some "Erhir"+ , ignintr = Some False+ , implicit_uncursed = Some True+ , legacy = Some True+ , lit_corridor = Some False+ , lootabc = Some False+ , mail = Some True+ , mention_walls = Some False+ , menucolors =+ [ { regex = "blessed"+ , color = Some types.Color.cyan+ , attributes = defaults.Attributes ⫽ { bold = Some True }+ }+ ]+ , menustyle = Some types.MenuStyle.traditional+ , menu_deselect_all = Some "-"+ , menu_deselect_page = Some "\\"+ , menu_first_page = Some "^"+ , menu_headings = Some types.MenuHeadings.bold+ , menu_invert_all = Some "@"+ , menu_invert_page = Some "~"+ , menu_last_page = Some "|"+ , menu_next_page = Some ">"+ , menu_objsyms = Some False+ , menu_previous_page = Some "<"+ , menu_search = Some ":"+ , menu_select_all = Some "."+ , menu_tab_sep = Some False+ , msg_window = Some types.MsgWindow.single+ , MSGTYPE = [ types.MsgType.hide "You swap places with .*" ]+ , name = Some "Kaeru"+ , news = Some True+ , nudist = Some False+ , null = Some False+ , number_pad = Some types.NumberPad.Letters+ , packorder = Some "\")[%?+!=/(*`0_"+ , paranoid_confirmation =+ defaults.ParanoidConfirmation ⫽ { pray = Some True }+ , pettype = Some types.PetType.cat+ , pickup_burden = Some types.PickupBurden.stressed+ , pickup_thrown = Some True+ , pickup_types = Some "?!/"+ , pile_limit = Some (types.PileLimit.limit 5)+ , playmode = Some types.PlayMode.normal+ , pushweapon = Some False+ , race = Some { enable = True, value = types.Race.elf }+ , rest_on_space = Some False+ , role = Some { enable = True, value = types.Role.wizard }+ , roguesymset = Some types.SymSet.RogueEpyx+ , runmode = Some types.RunMode.walk+ , safe_pet = Some True+ , sanity_check = Some False+ , scores = { own = Some True, around = Some 2, top = Some 10 }+ , showexp = Some False+ , showrace = Some False+ , showscore = Some False+ , silent = Some True+ , sortloot = Some types.SortLoot.none+ , sortpack = Some True+ , sparkle = Some True+ , standout = Some False+ , status_updates = Some True+ , statushilites = Some 10+ , suppress_alert = Some "3.3.1"+ , symset = Some types.SymSet.DECgraphics+ , time = Some False+ , timed_delay = Some True+ , tombstone = Some True+ , toptenwin = Some False+ , travel = Some True+ , verbose = Some True+ , whatis_coord = Some types.WhatisCoord.none+ , whatis_filter = Some types.WhatisFilter.no_filtering+ , whatis_menu = Some False+ , whatis_moveskip = Some False+ , windowtype = Some "tty"+ , wizkit = Some "wizkit.txt"+ }
@@ -0,0 +1,1 @@+let x = "Lorem ipsum" let y = "Lorem ipsum" in let z = "Lorem ipsum" in x ++ y ++ z
@@ -0,0 +1,1 @@+let empty : ∀(a : Type) → List a = λ(a : Type) → [] : List a in empty
@@ -0,0 +1,5 @@+let empty+ : ∀(a : Type) → List a+ = λ(a : Type) → [] : List a++in empty
@@ -0,0 +1,5 @@+let x = "Lorem ipsum"++let y = "Lorem ipsum"++in let z = "Lorem ipsum" in x ++ y ++ z
@@ -0,0 +1,7 @@+let {- Example documentation for a let binding+ that spans more than one line+ -}+ x {- we can interject things here -} = -- Make sure one-line comments work+ 1++in x
@@ -0,0 +1,8 @@+let {- Example documentation for a let binding+ that spans more than one line+ -}+ x {- we can interject things here -} =+ -- Make sure one-line comments work+ 1++in x
@@ -0,0 +1,10 @@+let x -- xxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxx+ : Natural+ = 0++let y -- yyyyyyyyyy yyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyy+ -- yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyyyyyyy+ : Natural+ = 1++in x + y
@@ -0,0 +1,12 @@+let x+ -- xxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxx+ : Natural+ = 0++let y+ -- yyyyyyyyyy yyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyy+ -- yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyyyyyyy+ : Natural+ = 1++in x + y
@@ -0,0 +1,3 @@+let x {- foo -} : {- bar -} Bool {- baz -} = {- bla -} True++in x
@@ -0,0 +1,5 @@+let x+ {- foo -} : {- bar -} Bool+ = {- bla -} True++in x
@@ -0,0 +1,7 @@+let x = 1+in+let {- aaaaaaaaaaaaaaaaaaa+ -} y : {- bbbbbbbbbbbbbbbbbbbbb+ -} Natural {- cccccccccccccc+ -} = {- ddddddddddddddddd -} 2+ in x
@@ -0,0 +1,9 @@+let x = 1++in let {- aaaaaaaaaaaaaaaaaaa+ -} y+ : {- bbbbbbbbbbbbbbbbbbbbb+ -} Natural+ = {- ddddddddddddddddd -} 2++ in x
@@ -0,0 +1,3 @@+let x = True+let {- 0 -} y {- 1 -} : {- 2 -} Bool = {- 3-} False+in x
@@ -0,0 +1,7 @@+let x = True++let {- 0 -} y+ {- 1 -} : {- 2 -} Bool+ = {- 3-} False++in x
@@ -0,0 +1,1 @@+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff xxxxxxxxxxxxxxxx "\n"
@@ -0,0 +1,3 @@+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff+ xxxxxxxxxxxxxxxx+ "\n"
@@ -0,0 +1,1 @@+"\n'"
@@ -0,0 +1,3 @@+''++${"'"}''
@@ -0,0 +1,1 @@+{ x = " \n\nfoo \n" }
@@ -0,0 +1,7 @@+{ x =+ ''+ ++ foo + ''+}
@@ -0,0 +1,1 @@+04:00:00-04:00
@@ -0,0 +1,1 @@+04:00:00-04:00
@@ -0,0 +1,1 @@+([] : a) : b
@@ -0,0 +1,1 @@+([] : a) : b
@@ -0,0 +1,1 @@+{ example0 = 0x42, example1 = +0x42, example2 = 1.2e20, example3 = -0b0111 }
@@ -0,0 +1,1 @@+{ example0 = 0x42, example1 = +0x42, example2 = 1.2e20, example3 = -0b0111 }
@@ -0,0 +1,6 @@+-- https://github.com/dhall-lang/dhall-haskell/issues/2273+let MyPackage =+ https://server.test/package.dhall using (./headers.dhall)+ sha256:03a6e298ff140d430cea8b387fad886ce9f5bee24622c7d1102115cc08ed9cf8++in MyPackage
@@ -0,0 +1,6 @@+-- https://github.com/dhall-lang/dhall-haskell/issues/2273+let MyPackage =+ https://server.test/package.dhall using (./headers.dhall)+ sha256:03a6e298ff140d430cea8b387fad886ce9f5bee24622c7d1102115cc08ed9cf8++in MyPackage
@@ -0,0 +1,2 @@+#!/usr/bin/env -S dhall text --file+"Hello, world!"
@@ -0,0 +1,2 @@+#!/usr/bin/env -S dhall text --file+"Hello, world!"
@@ -0,0 +1,1 @@+{ x = x, y = 1, z = z }
@@ -0,0 +1,1 @@+{ x, y = 1, z }
@@ -0,0 +1,7 @@+{ {- A -}+ x+ {- B -}+, y =+ {- C -}+ y+}
@@ -0,0 +1,7 @@+{ {- A -}+ x+ {- B -}+, y =+ {- C -}+ y+}
@@ -0,0 +1,26 @@+{ field0 =+T::{+, a = 1+, b = 1+, c = 1+, d = 1+, e = 1+, f = 1+, g = 1+, h = 1+, i = 1+, j = 1+, k = 1+, l = 1+, m = 1+, n = 1+, o = 1+, p = 1+, q = 1+, r = 1+, s = 1+, t = 1+}+, field1 = T::{ a = 1 }+, field2 = T::{ a = a }+}
@@ -0,0 +1,25 @@+{ field0 = T::{+ , a = 1+ , b = 1+ , c = 1+ , d = 1+ , e = 1+ , f = 1+ , g = 1+ , h = 1+ , i = 1+ , j = 1+ , k = 1+ , l = 1+ , m = 1+ , n = 1+ , o = 1+ , p = 1+ , q = 1+ , r = 1+ , s = 1+ , t = 1+ }+, field1 = T::{ a = 1 }+, field2 = T::{ a }+}
@@ -0,0 +1,6 @@+{ {- A -}+ x+ {- B -}+ = {- C -}+ T+}
@@ -0,0 +1,6 @@+{ {- A -}+ x+ {- B -}+ = {- C -}+ T+}
@@ -0,0 +1,4 @@+{+--| a comment for y+y = 42+}
@@ -0,0 +1,3 @@+{ --| a comment for y+ y = 42+}
@@ -0,0 +1,9 @@+{ {- A+ A -}+ x+ {- B+ B -}+ = {- C+ C -}+ y+}
@@ -0,0 +1,9 @@+{ {- A+ A -}+ x+ {- B+ B -}+ = {- C+ C -}+ y+}
@@ -0,0 +1,6 @@+{ {- A -}+ a+ {- B -}+ : {- C -}+ A+}
@@ -0,0 +1,6 @@+{ {- A -}+ a+ {- B -}+ : {- C -}+ A+}
@@ -1,4 +1,5 @@ let replicate =- https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:cc856d59b63f7699881bdb8e4b1036ca4c0013827268040a50c1e1405f646a2c+ https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate+ sha256:cc856d59b63f7699881bdb8e4b1036ca4c0013827268040a50c1e1405f646a2c in replicate 5
@@ -0,0 +1,1 @@+" x\n\n y\n "
@@ -0,0 +1,5 @@+''+${" "} x++${" "} y+${" "}''
@@ -0,0 +1,1 @@+"\u0000 \$ \\ \n ☺"
@@ -0,0 +1,3 @@+''+${"\u0000"} $ \ + ☺''
@@ -0,0 +1,1 @@+"\n\n"
@@ -0,0 +1,1 @@+"\n\n"
@@ -0,0 +1,3 @@+-- This test ensures that we don't strip leading zeros from the fractional+-- component of seconds when pretty-printing them+00:00:00.01
@@ -0,0 +1,3 @@+-- This test ensures that we don't strip leading zeros from the fractional+-- component of seconds when pretty-printing them+00:00:00.01
@@ -1,15 +1,15 @@ λ(isActive : Bool) → { barLeftEnd =- [ "┨" ] : Optional Text+ Some "┨" , barRightEnd =- [ "┠" ] : Optional Text+ Some "┠" , separator =- [ "┃" ] : Optional Text+ Some "┃" , alignment =- < ToTheLeft = {=} | ToTheRight : {} | Centered : {} >+ < ToTheLeft | ToTheRight | Centered >.ToTheLeft : ./Alignment.dhall , barWidth =- [] : Optional Natural+ None Natural , barSegments = [ "index", "command", "path", "title" ] }
@@ -1,16 +1,10 @@- λ(isActive : Bool)-→ { barLeftEnd =- [ "┨" ] : Optional Text- , barRightEnd =- [ "┠" ] : Optional Text- , separator =- [ "┃" ] : Optional Text+λ(isActive : Bool) →+ { barLeftEnd = Some "┨"+ , barRightEnd = Some "┠"+ , separator = Some "┃" , alignment =- < ToTheLeft = {=} | ToTheRight : {} | Centered : {} >- : ./Alignment.dhall- , barWidth =- [] : Optional Natural- , barSegments =- [ "index", "command", "path", "title" ]+ < ToTheLeft | ToTheRight | Centered >.ToTheLeft : ./Alignment.dhall+ , barWidth = None Natural+ , barSegments = [ "index", "command", "path", "title" ] } : ./Bar.dhall
@@ -0,0 +1,7 @@+let unreserved = http://x/y%7ez++let uppercasehex = http://x/y%3bz++let reserved = http://x/y:z++in "done"
@@ -0,0 +1,7 @@+let unreserved = http://x/y~z++let uppercasehex = http://x/y%3Bz++let reserved = http://x/y:z++in "done"
@@ -0,0 +1,1 @@+https://httpbin.org/headers using (toMap { TOKEN = "AAAA" }) as Text
@@ -0,0 +1,1 @@+https://httpbin.org/headers using (toMap { TOKEN = "AAAA" }) as Text
@@ -0,0 +1,5 @@+r with a = Some { b = 1, c = 1, d = 1, e = 1, f = 1, g = 1, h = 1, i = 1, j = 1, k = 1, l = 1 }+ with b = T::{ b = 1, c = 1, d = 1, e = 1, f = 1, g = 1, h = 1, i = 1, j = 1, k = 1, l = 1 }+ with c = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]+ with d = 1+ with e = 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
@@ -0,0 +1,58 @@+r+ with a = Some+ { b = 1+ , c = 1+ , d = 1+ , e = 1+ , f = 1+ , g = 1+ , h = 1+ , i = 1+ , j = 1+ , k = 1+ , l = 1+ }+ with b = T::{+ , b = 1+ , c = 1+ , d = 1+ , e = 1+ , f = 1+ , g = 1+ , h = 1+ , i = 1+ , j = 1+ , k = 1+ , l = 1+ }+ with c =+ [ 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ , 1+ ]+ with d = 1+ with e =+ 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
@@ -0,0 +1,5 @@+let Foo =+ Bar+ with default = (Bar.default ⫽ { bar = 0 })++in Foo
@@ -0,0 +1,1 @@+let Foo = Bar with default = Bar.default ⫽ { bar = 0 } in Foo
@@ -0,0 +1,1 @@+λ(x : Optional Natural) → x with ? = 2
@@ -0,0 +1,1 @@+λ(x : Optional Natural) → x with ? = 2
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,2 @@+ ./True.dhall sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,5 @@+-- The purpose of this test is to verify that `dhall freeze --cached` is+-- idempotent and doesn't attempt to resolve the `missing` import+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,1 @@+./True.dhall sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,3 @@+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,1 @@+./True.dhall sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,3 @@+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,1 @@+./True.dhall
@@ -0,0 +1,3 @@+ missing+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,1 @@+True
@@ -0,0 +1,2 @@+ ./True.dhall sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70+? ./True.dhall
@@ -0,0 +1,2 @@+./True.dhall+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+./True.dhall sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,2 @@+./True.dhall+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+./True.dhall sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,2 @@+./True.dhall+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+./True.dhall
@@ -0,0 +1,2 @@+./True.dhall+ sha256:27abdeddfe8503496adeb623466caa47da5f63abd2bc6fa19f6cfcb73ecfed70
@@ -0,0 +1,1 @@+https://prelude.dhall-lang.org/List/map
@@ -0,0 +1,1 @@+https://prelude.dhall-lang.org/List/map.dhall
@@ -0,0 +1,14 @@+let simpleAssert = assert : 1 + 1 ≡ 2++let assertIn1Lam = λ(n : Natural) → assert : Natural/subtract 0 n ≡ n++let assertIn2Lams =+ λ(m : Natural)+ → λ(n : Natural)+ → assert : Natural/subtract m m ≡ Natural/subtract n n++let assertInLetInLam = λ(m : Natural) → let n = m + 0 in assert : m ≡ n++let unusedNonAssert = "Foo"++in {=}
@@ -0,0 +1,12 @@+let simpleAssert = assert : 1 + 1 ≡ 2++let assertIn1Lam = λ(n : Natural) → assert : Natural/subtract 0 n ≡ n++let assertIn2Lams =+ λ(m : Natural) →+ λ(n : Natural) →+ assert : Natural/subtract m m ≡ Natural/subtract n n++let assertInLetInLam = λ(m : Natural) → let n = m + 0 in assert : m ≡ n++in {=}
@@ -0,0 +1,5 @@+let example0 = 1 ≡ 1++let example1 = let x = 1 in x ≡ 1++in 1
@@ -0,0 +1,1 @@+let example0 = assert : 1 ≡ 1 let example1 = let x = 1 in assert : x ≡ 1 in 1
@@ -0,0 +1,1 @@+let {- 1 -} x {- 2 -} : {- 3 -} Natural = {- 4 -} 1 {- 5 -} in x
@@ -0,0 +1,5 @@+let {- 1 -} x+ {- 2 -} : {- 3 -} Natural+ = {- 4 -} 1++in x
@@ -1,5 +1,4 @@ -- example0.dhall- let Person : Type = ∀(Person : Type)@@ -21,7 +20,7 @@ let everybody : Person → List Text- = let concat = http://prelude.dhall-lang.org/List/concat+ = let concat = http://prelude.dhall-lang.org/List/concat.dhall in λ(x : Person) → x
@@ -1,35 +1,35 @@ -- example0.dhall- let Person : Type- = ∀(Person : Type)- → ∀(MakePerson : { children : List Person, name : Text } → Person)- → Person+ = ∀(Person : Type) →+ ∀(MakePerson : { children : List Person, name : Text } → Person) →+ Person let example : Person- = λ(Person : Type)- → λ(MakePerson : { children : List Person, name : Text } → Person)- → MakePerson- { children =+ = λ(Person : Type) →+ λ(MakePerson : { children : List Person, name : Text } → Person) →+ MakePerson+ { children = [ MakePerson { children = [] : List Person, name = "Mary" } , MakePerson { children = [] : List Person, name = "Jane" } ]- , name =- "John"- }+ , name = "John"+ } let everybody : Person → List Text- = let concat = http://prelude.dhall-lang.org/List/concat- - in λ(x : Person)- → x- (List Text)- ( λ(p : { children : List (List Text), name : Text })- → [ p.name ] # concat Text p.children- )+ = let concat = http://prelude.dhall-lang.org/List/concat.dhall -let result : List Text = everybody example+ in λ(x : Person) →+ x+ (List Text)+ ( λ(p : { children : List (List Text), name : Text }) →+ [ p.name ] # concat Text p.children+ )++let result+ : List Text+ = everybody example in result
@@ -1,4 +1,4 @@- let replicate = https://prelude.dhall-lang.org/List/replicate+ let replicate = https://prelude.dhall-lang.org/List/replicate.dhall in let Config = { name : Text, age : Natural }
@@ -1,3 +1,3 @@-let replicate = https://prelude.dhall-lang.org/List/replicate+let replicate = https://prelude.dhall-lang.org/List/replicate.dhall in replicate 10 Text "!"
@@ -0,0 +1,17 @@+ λ(Expr : Type)+→ let ExprF =+ < LitF : Natural+ | AddF : { _1 : Expr, _2 : Expr }+ | MulF : { _1 : Expr, _2 : Expr }+ >++ in λ(Fix : ExprF → Expr)+ → let Lit = λ(x : Natural) → Fix (ExprF.LitF x)++ let Add =+ λ(x : Expr) → λ(y : Expr) → Fix (ExprF.AddF { _1 = x, _2 = y })++ let Mul =+ λ(x : Expr) → λ(y : Expr) → Fix (ExprF.MulF { _1 = x, _2 = y })++ in Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))
@@ -0,0 +1,15 @@+ λ(a : Type)+→ let ExprF =+ < LitF : Natural+ | AddF : { _1 : a, _2 : a }+ | MulF : { _1 : a, _2 : a }+ >++ in λ(a : ExprF → a)+ → let Lit = λ(x : Natural) → a (ExprF.LitF x)++ let Add = λ(x : a@1) → λ(y : a@1) → a (ExprF.AddF { _1 = x, _2 = y })++ let Mul = λ(x : a@1) → λ(y : a@1) → a (ExprF.MulF { _1 = x, _2 = y })++ in Add (Mul (Lit 3) (Lit 7)) (Add (Lit 1) (Lit 2))
@@ -1,1 +1,1 @@-let foo : (\(x : A) -> x x) (\(x : A) -> x x) = 1 in foo+\(A : Type) -> let foo : (\(x : A) -> x x) (\(x : A) -> x x) = 1 in foo
@@ -1,1 +1,1 @@-\(omega : ((\(x : A) -> x x) (\(x : A) -> x x))) -> omega 1+\(A : Type) -> \(omega : ((\(x : A) -> x x) (\(x : A) -> x x))) -> omega 1
@@ -0,0 +1,19 @@+[ let ifX = 1 in ifX+, let thenX = 1 in thenX+, let elseX = 1 in elseX+, let letX = 1 in letX+, let inX = 1 in inX+, let usingX = 1 in usingX+{- Fixing this case appears to be difficult for the current parser+ implementation+-}+-- , let missingX = 1 in missingX+, let asX = 1 in asX+, let InfinityX = 1 in InfinityX+, let NaNX = 1 in NaNX+, let mergeX = 1 in mergeX+, let SomeX = 1 in SomeX+, let toMapX = 1 in toMapX+, let assertX = 1 in assertX+, let forallX = 1 in forallX+]
@@ -0,0 +1,1 @@+let f = \(d : Double) -> \(i : Integer) -> {=} in f 3.1 -1
@@ -0,0 +1,1 @@+let x = 0 in { x , a = 0 }
@@ -0,0 +1,4 @@+let Make = \(T: Type) -> { Type = { a: T }, default = {=} }++in+(Make Natural) with default = { a = 2 }
@@ -0,0 +1,1 @@+[ { x = 1 }.{ x }, { x = 1 } ]
@@ -1,5 +1,5 @@ let GitHubProject : Type = { owner : Text, repo : Text } in let gitHubProject = \( github : GitHubProject ) -> let gitHubRoot = "https://github.com/${github.owner}/${github.repo}"- in { bugReports = "${gitHubRoot}/issues" }+ in { bugReports = "${gitHubRoot}/issues" } in gitHubProject
@@ -1,2 +1,2 @@- λ(github : { owner : Text, repo : Text })-→ { bugReports = "https://github.com/${github.owner}/${github.repo}/issues" }+λ(github : { owner : Text, repo : Text }) →+ { bugReports = "https://github.com/${github.owner}/${github.repo}/issues" }
@@ -0,0 +1,1 @@+{=}
@@ -0,0 +1,1 @@+let schemas = ./tests/schemas/multipleSchema.dhall in schemas.B::{=}
@@ -0,0 +1,3 @@+{ A = { Type = {}, default = {=} }+, B = { Type = {}, default = {=} }+}
@@ -0,0 +1,4 @@+{ addr = { city = None Text, country = "Switzerland" }+, alive = True+, name = "Alice"+}
@@ -0,0 +1,6 @@+let schemas = ./tests/schemas/personSchema.dhall++in schemas.Person::{+ , addr = schemas.Address::{ country = "Switzerland" }+ , name = "Alice"+ }
@@ -0,0 +1,11 @@+let Address =+ { Type = { country : Text, city : Optional Text }+ , default.city = None Text+ }++let Person =+ { Type = { name : Text, addr : Address.Type, alive : Bool }+ , default.alive = True+ }++in { Person, Address }
@@ -0,0 +1,61 @@++./tests/tags/let.dhall,66+let.dhall1,1+/let.dhall1,1+let foo foo1,5+let bar bar3,22++./tests/tags/nonunicode.dhall,63+nonunicode.dhall1,1+/nonunicode.dhall1,1+let foo foo2,12++./tests/tags/record.dhall,335+record.dhall1,1+/record.dhall1,1+let Config Config6,81+ { home home8,161+ , privateKey privateKey9,181+ , publicKey publicKey10,207+ , name name11,232+ , name : { firstName firstName11,241+ , secondName secondName12,275+let makeUser makeUser16,323+let configs configs30,804++./tests/tags/recordlit.dhall,223+recordlit.dhall1,1+/recordlit.dhall1,1+{ home home8,143+, privateKey privateKey9,171+, publicKey publicKey10,215+, name name11,263+, name = { firstName firstName11,272+ , secondName secondName12,302++./tests/tags/simple.dhall,254+simple.dhall1,1+/simple.dhall1,1+let generate generate6,100+let makeUser makeUser17,409+let buildUser buildUser26,680+let Config Config32,880+ { home home33,897+ , privateKey privateKey34,917+ , publicKey publicKey35,943++./tests/tags/unicode.dhall,57+unicode.dhall1,1+/unicode.dhall1,1+let foo foo2,15++./tests/tags/union.dhall,394+union.dhall1,1+/union.dhall1,1+let Element Element1,5+let Element = < Left Left1,17+let Element = < Left : Natural | Right Right1,34+let Element = < Left : Natural | Right : Bool | Middle Middle1,49+let Element = < Left : Natural | Right : Bool | Middle : < Top Top1,60+let Element = < Left : Natural | Right : Bool | Middle : < Top : Text | Bottom Bottom1,73+let foo foo3,95
@@ -0,0 +1,4 @@+let foo = "foo"++let bar = foo+in bar
@@ -0,0 +1,6 @@++./tests/tags/let.dhall,66+let.dhall1,1+/let.dhall1,1+let foo foo1,5+let bar bar3,22
@@ -0,0 +1,3 @@+-- abc+let foo = "bar"+in foo
@@ -0,0 +1,5 @@++./tests/tags/nonunicode.dhall,63+nonunicode.dhall1,1+/nonunicode.dhall1,1+let foo foo2,12
@@ -0,0 +1,35 @@+{- You can optionally add types++ `x : T` means that `x` has type `T`+-}++let Config : Type =+ {- What happens if you add another field here? -}+ { home : Text+ , privateKey : Text+ , publicKey : Text+ , name : { firstName : Text+ , secondName : Text+ }+ }++let makeUser : Text -> Config = \(user : Text) ->+ let home : Text = "/home/${user}"+ let privateKey : Text = "${home}/.ssh/id_ed25519"+ let publicKey : Text = "${privateKey}.pub"+ let config : Config =+ { home = home+ , privateKey = privateKey+ , publicKey = publicKey+ , name = { firstName = user+ , secondName = ""+ }+ }+ in config++let configs : List Config =+ [ makeUser "bill"+ , makeUser "jane"+ ]++in configs
@@ -0,0 +1,13 @@++./tests/tags/record.dhall,335+record.dhall1,1+/record.dhall1,1+let Config Config6,81+ { home home8,161+ , privateKey privateKey9,181+ , publicKey publicKey10,207+ , name name11,232+ , name : { firstName firstName11,241+ , secondName secondName12,275+let makeUser makeUser16,323+let configs configs30,804
@@ -0,0 +1,14 @@+{- This is an example Dhall configuration file++ Can you spot the mistake?++ Fix the typo, then move onto the "Definitions" example+-}++{ home = "/home/bill"+, privateKey = "/home/bill/.ssh/id_ed25519"+, publicKey = "/home/blil/.ssh/id_ed25519.pub"+, name = { firstName = "Bill"+ , secondName = "Bar"+ }+}
@@ -0,0 +1,10 @@++./tests/tags/recordlit.dhall,223+recordlit.dhall1,1+/recordlit.dhall1,1+{ home home8,143+, privateKey privateKey9,171+, publicKey publicKey10,215+, name name11,263+, name = { firstName firstName11,272+ , secondName secondName12,302
@@ -0,0 +1,39 @@+{- Need to generate a lot of users?++ Use the `generate` function from the Dhall Prelude+-}++let generate = https://prelude.dhall-lang.org/List/generate++{- You can import Dhall expressions from URLs that support+ CORS++ The command-line tools also let you import from files,+ environment variables, and URLs without CORS support.++ Browse https://prelude.dhall-lang.org for more utilities+-}++let makeUser = \(user : Text) ->+ let home = "/home/${user}"+ let privateKey = "${home}/.ssh/id_ed25519"+ let publicKey = "${privateKey}.pub"+ in { home = home+ , privateKey = privateKey+ , publicKey = publicKey+ }++let buildUser = \(index : Natural) ->+ {- `Natural/show` is a "built-in", meaning that+ you can use `Natural/show` without an import+ -}+ makeUser "build${Natural/show index}"++let Config =+ { home : Text+ , privateKey : Text+ , publicKey : Text+ }++in {- Try generating 20 users instead of 10 -}+ generate 10 Config buildUser
@@ -0,0 +1,11 @@++./tests/tags/simple.dhall,254+simple.dhall1,1+/simple.dhall1,1+let generate generate6,100+let makeUser makeUser17,409+let buildUser buildUser26,680+let Config Config32,880+ { home home33,897+ , privateKey privateKey34,917+ , publicKey publicKey35,943
@@ -0,0 +1,3 @@+-- αβξ+let foo = "bar"+in foo
@@ -0,0 +1,5 @@++./tests/tags/unicode.dhall,57+unicode.dhall1,1+/unicode.dhall1,1+let foo foo2,15
@@ -0,0 +1,4 @@+let Element = < Left : Natural | Right : Bool | Middle : < Top : Text | Bottom : Bool> >++let foo = Element.Left 6+in foo
@@ -0,0 +1,11 @@++./tests/tags/union.dhall,394+union.dhall1,1+/union.dhall1,1+let Element Element1,5+let Element = < Left Left1,17+let Element = < Left : Natural | Right Right1,34+let Element = < Left : Natural | Right : Bool | Middle Middle1,49+let Element = < Left : Natural | Right : Bool | Middle : < Top Top1,60+let Element = < Left : Natural | Right : Bool | Middle : < Top : Text | Bottom Bottom1,73+let foo foo3,95
@@ -0,0 +1,1 @@+< Sales | Engineering | Marketing >
@@ -0,0 +1,1 @@+{ name : Text, department : ./Department.dhall }
@@ -0,0 +1,1 @@+\(a : Type -> Type) -> \(a : Type) -> { foo : a, bar : a@1 a, bam : Text }
@@ -0,0 +1,1 @@+\(a : Type) -> \(b : Type) -> < Foo : a | Bar : b >
@@ -0,0 +1,1 @@+{ txTime : Time, txDate : Date, txTimeZone : TimeZone }
@@ -0,0 +1,1 @@+< A : { x : Bool, y : List Text } | B : Optional (List Natural) | C >
@@ -0,0 +1,7 @@+let Bar = { baz : Integer }++let Foo = { foo : Integer, bar : Bar }++let Qux = < Foo : Foo | Bar : Bar >++in { Foo, Bar, Qux }
@@ -0,0 +1,25 @@+let User = (./fixpoint-helper.dhall).User++let Group = (./fixpoint-helper.dhall).Group++let Mode = (./fixpoint-helper.dhall).Mode++let Make = (./fixpoint-helper.dhall).Make++in \(r : Type) ->+ \(make : Make r) ->+ [ make.file+ { name = "non-existent-1/file"+ , content = ""+ , user = None User+ , group = None Group+ , mode = None Mode+ }+ , make.directory+ { name = "non-existent-2/directory"+ , content = [] : List r+ , user = None User+ , group = None Group+ , mode = None Mode+ }+ ]
@@ -0,0 +1,3 @@+let Make = (./fixpoint-helper.dhall).Make++in \(r : Type) -> \(make : Make r) -> [] : List r
@@ -0,0 +1,30 @@+let User = < UserId : Natural | UserName : Text >++let Group = < GroupId : Natural | GroupName : Text >++let Access =+ { execute : Optional Bool, read : Optional Bool, write : Optional Bool }++let Mode =+ { user : Optional Access+ , group : Optional Access+ , other : Optional Access+ }++let Entry =+ \(content : Type) ->+ { name : Text+ , content : content+ , user : Optional User+ , group : Optional Group+ , mode : Optional Mode+ }++let Make =+ \(r : Type) ->+ { directory : Entry (List r) -> r+ , binary-file : Entry Bytes -> r+ , file : Entry Text -> r+ }++in { User, Group, Access, Mode, Entry, Make }
@@ -0,0 +1,24 @@+let User = (./fixpoint-helper.dhall).User++let Group = (./fixpoint-helper.dhall).Group++let Make = (./fixpoint-helper.dhall).Make++let no-access = { execute = Some False, read = Some False, write = Some False }++let full-access = { execute = Some True, read = Some True, write = Some True }++in \(r : Type) ->+ \(make : Make r) ->+ [ make.file+ { name = "file"+ , content = ""+ , user = None User+ , group = None Group+ , mode = Some+ { user = Some full-access+ , group = Some no-access+ , other = Some no-access+ }+ }+ ]
@@ -0,0 +1,25 @@+let User = (./fixpoint-helper.dhall).User++let Group = (./fixpoint-helper.dhall).Group++let Mode = (./fixpoint-helper.dhall).Mode++let Make = (./fixpoint-helper.dhall).Make++in \(r : Type) ->+ \(make : Make r) ->+ [ make.file+ { name = "file"+ , content = ""+ , user = None User+ , group = None Group+ , mode = None Mode+ }+ , make.directory+ { name = "directory"+ , content = [] : List r+ , user = None User+ , group = None Group+ , mode = None Mode+ }+ ]
@@ -0,0 +1,25 @@+let User = (./fixpoint-helper.dhall).User++let Group = (./fixpoint-helper.dhall).Group++let Mode = (./fixpoint-helper.dhall).Mode++let Make = (./fixpoint-helper.dhall).Make++in \(r : Type) ->+ \(make : Make r) ->+ [ make.file+ { name = "ids"+ , content = ""+ , user = Some (User.UserId 0)+ , group = Some (Group.GroupId 0)+ , mode = None Mode+ }+ , make.file+ { name = "names"+ , content = ""+ , user = Some (User.UserName "user")+ , group = Some (Group.GroupName "group")+ , mode = None Mode+ }+ ]
@@ -0,0 +1,36 @@+let User = < UserId : Natural | UserName : Text >++let Group = < GroupId : Natural | GroupName : Text >++let Access =+ { execute : Optional Bool, read : Optional Bool, write : Optional Bool }++let Mode =+ { user : Optional Access+ , group : Optional Access+ , other : Optional Access+ }++let Entry =+ \(content : Type) ->+ { name : Text+ , content : content+ , user : Optional User+ , group : Optional Group+ , mode : Optional Mode+ }++in forall (result : Type) ->+ let DirectoryEntry = Entry (List result)++ let BinaryFileEntry = Entry Bytes++ let TextFileEntry = Entry Text++ let Make =+ { directory : DirectoryEntry -> result+ , binary-file : BinaryFileEntry -> result+ , file : TextFileEntry -> result+ }++ in forall (make : Make) -> List result
@@ -0,0 +1,1 @@+< Left : Natural | Right : Bool>
@@ -0,0 +1,1 @@+Result.Failure +1
@@ -0,0 +1,1 @@+./substitution1.dhall
@@ -0,0 +1,1 @@+Foo
@@ -1,1 +1,1 @@-./process.dhall < Left = 3 | Right : Bool >+./process.dhall ((./Union.dhall).Left 3)
@@ -1,1 +1,1 @@-./process.dhall < Right = True | Left : Natural >+./process.dhall ((./Union.dhall).Right True)
@@ -1,8 +0,0 @@- let Empty = < Empty = {=} | Person : { name : Text, age : Natural } >-in let Person =- λ(p : { name : Text, age : Natural }) → < Person = p | Empty : {} >-in [ Empty- , Person { name = "John", age = 23 }- , Person { name = "Amy" , age = 25 }- , Empty- ]
@@ -1,5 +0,0 @@-[ < Empty = {=} | Person : { age : Natural, name : Text } >-, < Person = { age = 23, name = "John" } | Empty : {} >-, < Person = { age = 25, name = "Amy" } | Empty : {} >-, < Empty = {=} | Person : { age : Natural, name : Text } >-]